/* site.css — the page layer shared by / and /i/.
 *
 * Hand-authored (unlike tokens.css + sticker.css, which are GENERATED from
 * constants/theme.ts). Everything here is composition: where the card sits, how
 * Rosie bobs, how the confetti drifts. Every value is a token — no page declares
 * its own :root, no rule types a hex, a size or a radius
 * (design-system-spec §3 rule 7; findings-G-web G-02…G-06, G-10, G-13, G-14, G-22).
 *
 * The two pages differ by ONE class on <body>: `.invite` narrows and centres the
 * card. That is the whole delta, so the G-10 drift cannot come back.
 */

/* Load order, set by the page head: /tokens.css, then /sticker.css, then this
   file. No @import chain here — three parallel <link>s beat three serial fetches. */

/* ------------------------------------------------------------------- page -- */

*,
*::before,
*::after { box-sizing: border-box; }
html, body { min-height: 100%; }
body { margin: 0; }

body {
	background:
		radial-gradient(circle at 12% 18%, color-mix(in srgb, var(--fill-rose) 55%, transparent), transparent 38%),
		radial-gradient(circle at 88% 82%, color-mix(in srgb, var(--fill-lilac) 50%, transparent), transparent 40%),
		var(--paper);
	color: var(--text-primary);
	font: var(--type-body);
	padding: var(--space-xxl) var(--space-xl) var(--space-xl);
	overflow-x: hidden;
	text-wrap: pretty;
}
body.invite {
	display: flex;
	align-items: center;
	justify-content: center;
	padding-block: var(--space-xl);
}

p, ol, ul, h1, h2, h3 { margin: 0; }

.page {
	position: relative;
	z-index: 1;
	width: 100%;
	max-width: 820px;
	margin: 0 auto;
}
body.invite .page { max-width: 560px; }

/* --------------------------------------------------------------- confetti -- */

.bg-stars { position: fixed; inset: 0; pointer-events: none; z-index: 0; }
.bg-stars b {
	position: absolute;
	color: var(--fill-rose-deep);
	opacity: var(--opacity-dim);
	animation: float-up linear infinite;
}
@keyframes float-up {
	0%   { transform: translateY(20px) rotate(0deg) scale(.6); opacity: 0; }
	15%  { opacity: var(--opacity-dim); }
	85%  { opacity: var(--opacity-dim); }
	100% { transform: translateY(-110vh) rotate(220deg) scale(1); opacity: 0; }
}

/* ------------------------------------------------------------------- card -- */
/* .sticker carries the ink border, the tilt and the 4,4 shadow. The card only
   says how big and how generously padded — no second shadow tier. */

.card {
	max-width: 680px;
	width: 100%;
	margin: 0 auto;
	padding: var(--space-xl) var(--space-xl) var(--space-lg);
	border-radius: var(--radius-xxl);
	opacity: 0;
	animation: card-pop .7s cubic-bezier(.2, 1.3, .4, 1) .05s forwards;
}
body.invite .card { max-width: 560px; text-align: center; }

/* The two overshoot curves below approximate MOTION_SPRING.overshoot (the app
   springs; CSS can't). Everything else on this page eases on var(--ease-out). */
@keyframes card-pop {
	0%   { opacity: 0; transform: rotate(3deg) scale(.86) translateY(18px); }
	70%  { opacity: 1; transform: rotate(-1.4deg) scale(1.012) translateY(0); }
	100% { opacity: 1; transform: rotate(var(--tilt-card)) scale(1); }
}
@keyframes rise {
	from { opacity: 0; transform: translateY(14px); }
	to   { opacity: 1; transform: translateY(0); }
}

/* ------------------------------------------------------------------- hero -- */

.hero {
	display: grid;
	grid-template-columns: 1fr 208px;
	gap: var(--space-card);
	align-items: center;
}
body.invite .hero { grid-template-columns: 1fr; gap: var(--space-sm); }
body.invite .rosie-col { order: -1; }
.copy-col { padding-top: var(--space-xs); }
body.invite .copy-col { padding-top: 0; }

.kicker {
	display: inline-flex;
	align-items: center;
	gap: var(--space-sm);
	margin-bottom: var(--space-md);
	opacity: 0;
	animation: rise .55s ease-out .35s forwards;
}
.kicker .tw { display: inline-block; animation: twinkle 2.4s ease-in-out infinite; }
.kicker .tw:last-child { animation-delay: 1.2s; }
@keyframes twinkle {
	0%, 100% { transform: scale(1) rotate(0); opacity: var(--opacity-muted); }
	50%      { transform: scale(1.35) rotate(18deg); opacity: 1; }
}

/* Caprasimo, fluid between the display-lg and hero steps. The clamp is the one
   sanctioned deviation from a bare `font:` role — a marketing headline has to
   survive a 320px phone and an 820px card. */
.hero-title {
	font: var(--type-display-lg);
	font-size: clamp(32px, 6vw, 50px);
	line-height: 1.04;
	margin-bottom: var(--space-card);
}
body.invite .hero-title {
	font-size: clamp(24px, 5.5vw, 32px);
	margin-bottom: var(--space-lg);
	opacity: 0;
	animation: rise .55s ease-out .58s forwards;
}
.hero-title .l1 { display: block; opacity: 0; animation: rise .55s ease-out .45s forwards; }
.hero-title .l2 {
	display: inline-block;
	position: relative;
	opacity: 0;
	animation: rise .55s ease-out .58s forwards;
}
/* the highlighter swipe under the second line */
.hero-title .l2::after {
	content: "";
	position: absolute;
	left: -2px; right: -2px;
	bottom: 6px;
	height: var(--space-md);
	background: var(--fill-sun);
	border-radius: var(--radius-hair);
	z-index: -1;
	transform: scaleX(0);
	transform-origin: left center;
	animation: swipe .5s var(--ease-out) 1s forwards;
}
@keyframes swipe { to { transform: scaleX(1); } }

.hero-sub {
	display: inline-flex;
	align-items: center;
	gap: var(--space-sm);
	font: var(--type-body-lg);
	opacity: 0;
	animation: rise .55s ease-out .72s forwards;
}
.hero-sub .arrow { color: var(--accent); animation: nudge 1.6s ease-in-out infinite; }
@keyframes nudge {
	0%, 100% { transform: translateX(0); }
	50%      { transform: translateX(4px); }
}

/* ------------------------------------------------------------------ Rosie -- */

.rosie-col {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	align-self: stretch;
}
.rosie-stage {
	position: relative;
	width: 100%;
	max-width: 214px;
	aspect-ratio: 370 / 383;
	cursor: pointer;
}
/* the soft rose halo behind her */
.rosie-stage::before {
	content: "";
	position: absolute;
	inset: 14% 8% 16% 8%;
	background: radial-gradient(circle, color-mix(in srgb, var(--fill-rose) 85%, transparent), transparent 70%);
	border-radius: var(--radius-pill);
	z-index: 0;
	animation: halo 3.4s ease-in-out infinite;
}
@keyframes halo {
	0%, 100% { transform: scale(.96); opacity: var(--opacity-pressed); }
	50%      { transform: scale(1.06); opacity: 1; }
}
.rosie-wrap {
	display: block;
	position: relative;
	z-index: 1;
	opacity: 0;
	transform-origin: 50% 88%;
	animation: rosie-in .7s cubic-bezier(.2, 1.4, .4, 1) .55s forwards;
}
.rosie {
	/* width/height attributes stay on the <img> for CLS; height:auto keeps them
	   from acting as a presentational hint once CSS sets the width. */
	width: 100%;
	height: auto;
	display: block;
	transform-origin: 50% 88%;
	animation: bob 3.2s ease-in-out 1.3s infinite;
	will-change: transform;
}
@keyframes rosie-in {
	0%   { opacity: 0; transform: scale(.4) rotate(-12deg) translateY(30px); }
	70%  { opacity: 1; transform: scale(1.06) rotate(3deg); }
	100% { opacity: 1; transform: scale(1) rotate(0); }
}
@keyframes bob {
	0%, 100% { transform: translateY(0) rotate(-1deg); }
	50%      { transform: translateY(-7px) rotate(1deg); }
}
.rosie-stage.tickled .rosie { animation: wiggle .5s ease-in-out 1; }
@keyframes wiggle {
	0%, 100% { transform: rotate(0) translateY(0); }
	15% { transform: rotate(-7deg) translateY(-4px); }
	30% { transform: rotate(6deg) translateY(-8px); }
	45% { transform: rotate(-6deg) translateY(-4px); }
	60% { transform: rotate(5deg) translateY(-7px); }
	75% { transform: rotate(-4deg) translateY(-2px); }
}

.giggle {
	position: absolute;
	top: 2%; left: 50%;
	transform: translateX(-50%);
	background: var(--bark);
	color: var(--text-on-dark);
	font: var(--type-label);
	letter-spacing: var(--tracking-label);
	padding: var(--space-xs) var(--space-md);
	border-radius: var(--radius-pill);
	white-space: nowrap;
	opacity: 0;
	pointer-events: none;
	z-index: 3;
}
.giggle.show { animation: pop-giggle 1.1s ease-out 1; }
@keyframes pop-giggle {
	0%   { opacity: 0; transform: translateX(-50%) translateY(6px) scale(.6); }
	25%  { opacity: 1; transform: translateX(-50%) translateY(-6px) scale(1); }
	75%  { opacity: 1; transform: translateX(-50%) translateY(-10px) scale(1); }
	100% { opacity: 0; transform: translateX(-50%) translateY(-22px) scale(.9); }
}
.spark {
	position: absolute;
	font-size: var(--art-mark);
	pointer-events: none;
	z-index: 2;
	animation: spark-fly .8s ease-out forwards;
}
@keyframes spark-fly {
	0%   { opacity: 0; transform: translate(0, 0) scale(.2); }
	20%  { opacity: 1; }
	100% { opacity: 0; transform: translate(var(--dx), var(--dy)) scale(1.1) rotate(var(--dr)); }
}

/* The discovery hint lives INSIDE the card, under the stage it points at, in the
   hand face at accent — not 11px of low-contrast grey outside the border (G-22). */
.hint {
	display: inline-flex;
	align-items: center;
	gap: var(--space-xs);
	margin-top: var(--space-xs);
	font: var(--type-kicker);
	letter-spacing: var(--tracking-kicker);
	color: var(--accent);
	opacity: 0;
	animation: rise .5s ease-out 1.5s forwards;
}

/* ------------------------------------------------------------------ glyph -- */

.glyph {
	display: inline-block;
	width: var(--art-glyph-sm);
	height: var(--art-glyph-sm);
	vertical-align: -6px;
}
.glyph--mark { width: var(--art-mark); height: var(--art-mark); vertical-align: -1px; }

/* ------------------------------------------------------------------ panel -- */

.panel {
	margin-top: var(--space-lg);
	opacity: 0;
	animation: rise .55s ease-out .9s forwards;
}
body.invite .panel { animation-delay: .72s; }

.code-label {
	font: var(--type-kicker-pill);
	letter-spacing: var(--tracking-kicker-pill);
	text-transform: uppercase;
	color: var(--ink-mute);
	margin-bottom: var(--space-sm);
}
.code-pill {
	--fill: var(--cream);
	--tilt: 0deg;
	--shadow: var(--shadow-sm);
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--space-md);
	margin-bottom: var(--space-md);
	text-align: left;
}
.code {
	font: var(--type-numeral-lg);
	font-variant-numeric: tabular-nums;
	letter-spacing: 1.5px;
	color: var(--text-primary);
	word-break: break-word;
}
body.invite .code {
	font-size: clamp(26px, 8vw, 40px);
	line-height: 1.1;
}
.cta { margin-bottom: var(--space-card); }
.cta .ja { transition: transform var(--motion-fade); }
.cta:hover .ja { transform: translateX(5px); }

.steps {
	--fill: var(--fill-sage);
	--tilt: 0deg;
	--shadow: var(--shadow-sm);
	font: var(--type-body-sm);
	text-align: left;
}
.steps strong { display: block; margin-bottom: var(--space-xs); }
.steps ol { margin: 0; padding-left: var(--space-xl); }
.steps li { margin-bottom: var(--space-xxs); }

.no-code {
	--fill: var(--cream);
	--tilt: 0deg;
	--shadow: var(--shadow-sm);
	color: var(--text-secondary);
	margin-bottom: var(--space-md);
	text-align: left;
}

/* -------------------------------------------------- crawlable answer hub -- */

.answer-hub { margin: var(--space-xxl) auto 0; max-width: 820px; }
/* The marketing h2 outranks an in-app section title; same Caprasimo role, fluid. */
.answer-hub .section-header__title { font-size: clamp(24px, 4.5vw, 34px); line-height: 1.1; }
.answer-hub > header {
	max-width: 680px;
	margin: 0 auto var(--space-xl);
	text-align: center;
	align-items: center;
}
.answer-hub > header .rule { align-self: center; }
.lede { font: var(--type-body-lg); margin-top: var(--space-sm); }

.answer-grid {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: var(--space-lg);
}
.answer-grid > .sticker { padding: var(--space-lg); }
.answer-grid > .sticker:nth-child(4n + 1) { --fill: var(--fill-sun); }
.answer-grid > .sticker:nth-child(4n + 2) { --fill: var(--fill-rose); }
.answer-grid > .sticker:nth-child(4n + 3) { --fill: var(--fill-sage); }
.answer-grid > .sticker:nth-child(4n + 4) { --fill: var(--fill-lilac); }
.answer-grid h3 {
	font: var(--type-card-title);
	letter-spacing: var(--tracking-card-title);
	margin-bottom: var(--space-sm);
}
.answer-grid p { font: var(--type-body); }

.faq { margin-top: var(--space-xxl); }
.faq .section-header { align-items: center; text-align: center; }
.bottom-cta { max-width: 680px; margin: var(--space-xl) auto 0; }

/* ----------------------------------------------------------------- footer -- */

footer.site {
	margin-top: var(--space-xl);
	text-align: center;
	color: var(--text-secondary);
	font: var(--type-body-sm);
}
footer.site a {
	display: inline-flex;
	align-items: center;
	min-height: var(--tap-min);
	padding: 0 var(--space-xs);
	color: var(--text-primary);
}

/* ------------------------------------------------------------------ toast -- */

.toast {
	position: fixed;
	bottom: var(--space-xl);
	left: 50%;
	transform: translateX(-50%) translateY(20px);
	z-index: 50;
	opacity: 0;
	pointer-events: none;
	transition:
		opacity var(--motion-fade) ease-out,
		transform var(--motion-fade) ease-out;
}
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
.toast--success::after {
	content: "";
	display: inline-block;
	width: var(--space-lg);
	height: var(--space-lg);
	margin-left: var(--space-xs);
	vertical-align: text-bottom;
	background: currentColor;
	-webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M6 12.5L10.5 17 18.5 8' fill='none' stroke='black' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
	mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M6 12.5L10.5 17 18.5 8' fill='none' stroke='black' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
}

/* ------------------------------------------------------------ small screens -- */

@media (max-width: 540px) {
	body { padding: var(--space-xl) var(--space-lg) var(--space-lg); }
	.card { padding: var(--space-xl) var(--space-lg) var(--space-lg); }
	.hero { grid-template-columns: 1fr; gap: var(--space-xs); }
	.rosie-col { order: -1; }
	.rosie-stage { max-width: 190px; }
	.hero-title { font-size: clamp(32px, 11vw, 44px); }
	.answer-grid { grid-template-columns: 1fr; }
	.answer-hub { margin-top: var(--space-xxl); }
}

/* ------------------------------------------------------------- safety net -- */
/* If the intro animations never run (background tab, throttled compositor), force
   the end state at 1.6 s so content is never stuck invisible. */

body.shown .card { opacity: 1; transform: rotate(var(--tilt-card)); }
body.shown .kicker,
body.shown .hero-title,
body.shown .hero-title .l1,
body.shown .hero-title .l2,
body.shown .hero-sub,
body.shown .panel,
body.shown .hint,
body.shown .rosie-wrap { opacity: 1; }
body.shown .card,
body.shown .kicker,
body.shown .hero-title,
body.shown .hero-title .l1,
body.shown .hero-title .l2,
body.shown .hero-title .l2::after,
body.shown .hero-sub,
body.shown .panel,
body.shown .hint,
body.shown .rosie-wrap { animation: none !important; }
body.shown .hero-title .l2::after { transform: scaleX(1); }

@media (prefers-reduced-motion: reduce) {
	*, *::before, *::after { animation: none !important; transition: none !important; }
	.card,
	.kicker,
	.hero-title,
	.hero-title .l1,
	.hero-title .l2,
	.hero-sub,
	.rosie,
	.rosie-wrap,
	.panel,
	.hint { opacity: 1 !important; transform: none !important; }
	.hero-title .l2::after { transform: scaleX(1) !important; }
	.toast { transform: translateX(-50%); }
}
