/* The /start/ pages' own layer (PLT-1374, PLT-1439), on top of the portal's
 * built stylesheet. Tokens only — every colour, size and face comes from the
 * Hello Purple layer the portal already loads, so this file adds layout, never
 * a palette. Served from the portal's origin because its CSP is
 * `style-src 'self'`: an inline <style> or style="" would be refused.
 * The markup comes from scripts/front-pages/renderHtml.ts.
 *
 * The values follow hello-purple.com's own `globals.scss` where the site has
 * the thing (section rhythm, `.section-title`, `.card`, `.tag`, `.btn`,
 * `.prose code`, `.pullquote`), so these pages read as pages of the site
 * (design review, 2026-10-18). */

/* One measure for running text, lists, code and the sentences to say, so
 * their right edges line up instead of a 1152px code block under a 680px
 * paragraph. */
.app-content {
	--qs-measure: 42.5rem;
}

/* ---- Links and focus ---- */

/* Links in running text are underlined (WCAG 1.4.1): told apart from the
 * text around them by colour alone, they were 1.25 : 1 against it. */
.app-content a:not(.portal-button) {
	text-decoration: underline;
	text-decoration-thickness: 1px;
	text-underline-offset: 3px;
}

/* One focus ring for everything on these pages: the portal's shadow token,
 * which its buttons already wear, rather than the browser's own outline on
 * the links. Buttons keep their own rule (`.portal-button:focus-visible`):
 * the radius here would square off a pill. */
.app-content a:not(.portal-button):focus-visible,
.site-nav a:not(.portal-button):focus-visible,
.app-content summary:focus-visible,
.qs-copy:focus-visible,
.qs-copy-field:focus-visible {
	outline: none;
	box-shadow: var(--shadow-focus);
	border-radius: var(--radius-sm);
}

/* ---- Buttons: the site's `.btn` ---- */

/* `.portal-button` is written for <button>, which the UA sheet makes
 * border-box. On an <a> it is content-box, so the narrow pass's 48px
 * min-height lands on top of the padding and the pill stands 75px tall. */
a.portal-button {
	box-sizing: border-box;
}

.app-shell .portal-button {
	min-height: 44px;
	padding: 12px 22px;
	line-height: 1.2;
	white-space: nowrap;
	transition:
		background var(--dur-base) var(--ease-standard),
		color var(--dur-base) var(--ease-standard),
		border-color var(--dur-base) var(--ease-standard),
		transform var(--dur-fast) var(--ease-standard);
}

.app-shell .portal-button--ghost {
	border-color: var(--hp-violet-200);
}

.app-shell .portal-button--ghost:hover {
	background: var(--hp-violet-050);
	border-color: var(--hp-blue-violet);
	color: var(--hp-violet-700);
}

/* The site's `.nav-cta`: filled, a size down from a page's own button. */
.app-shell .qs-nav-cta {
	min-height: 40px;
	padding: 10px 18px;
}

@media (max-width: 40rem) {
	/* The narrow pass floors every button at 48px; in the 68px bar that
	 * outweighs the logo. 40px is still well over the 24px target. */
	.app-shell .qs-nav-cta {
		min-height: 40px;
	}
}

@media (prefers-reduced-motion: reduce) {
	.app-shell .portal-button {
		transition: none;
	}
}

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

.qs-hero .portal-hero__main {
	gap: var(--space-5);
	padding-bottom: var(--space-12);
}

.qs-hero .portal-hero__title {
	margin-bottom: var(--space-1);
}

/* The eyebrow already reads as a label; it needs no gap of its own above
 * the heading beyond the section's. */
.qs-eyebrow {
	margin-bottom: calc(-1 * var(--space-2));
}

/* "Start / With Claude Code": the way back the eyebrow used to leave out. */
.qs-crumbs ol {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-2);
	margin: 0 0 calc(-1 * var(--space-2));
	padding: 0;
	list-style: none;
	font-size: var(--fs-body-sm);
	color: var(--text-muted);
}

.qs-crumbs li + li::before {
	content: "/";
	margin-right: var(--space-2);
	color: var(--text-subtle);
}

.qs-crumbs [aria-current="page"] {
	color: var(--text-strong);
	font-weight: var(--fw-semibold);
}

.qs-needs {
	font-size: var(--fs-body-sm);
	color: var(--text-muted);
	max-width: var(--qs-measure);
}

.qs-aside,
.qs-contact {
	color: var(--text-muted);
	max-width: var(--qs-measure);
}

.qs-contact {
	font-size: var(--fs-body-sm);
}

/* A fact to read before choosing (an app works only for whoever registered
 * it), in the portal's own `.portal-callout`, so it reads the same here and
 * on signed-out My Apps. This adds only the page's measure. */
.qs-notice {
	max-width: var(--qs-measure);
	box-sizing: border-box;
	margin: 0;
}

/* "You're done when …": the line the person checks the run against, so it is
 * a block of its own, keyed in the good status colour. */
.qs-expect {
	max-width: var(--qs-measure);
	box-sizing: border-box;
	padding: var(--space-3) var(--space-5);
	border: var(--hairline);
	border-left: var(--border-w-frame) solid var(--status-good);
	background: var(--surface-card);
}

/* A quiet line for agents, after the choice rather than inside it. Inline,
 * not flex: flex items would put gaps around the link and its full stop. */
.qs-twin {
	font-size: var(--fs-body-sm);
	color: var(--text-muted);
}

.qs-twin .qs-copy {
	margin-left: var(--space-3);
	vertical-align: middle;
}

/* ---- The two doors ---- */

/* Equal weight, side by side, stacked on a narrow screen. Each door is the
 * site's `.card` (white, one hairline, 32px in, square); its button sits at
 * the foot, so the two buttons line up whatever the text above them. */
.qs-doors {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: var(--space-6);
	margin-top: var(--space-2);
}

.qs-door {
	display: flex;
	flex-direction: column;
	gap: var(--space-3);
	min-width: 0;
	padding: var(--space-8);
	background: var(--surface-card);
	border: var(--hairline);
	border-radius: var(--radius-block);
	transition: border-color var(--dur-base) var(--ease-standard);
}

.qs-door:hover {
	border-color: var(--hp-blue-violet);
}

.qs-door__go {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-3);
	margin-top: auto;
	padding-top: var(--space-3);
}

@media (max-width: 40rem) {
	.qs-doors {
		grid-template-columns: minmax(0, 1fr);
		gap: var(--space-3);
	}

	/* On a phone both doors must show their button above the fold (measured
	 * at 375 × 812), or the second way in is a scroll away and the choice is
	 * not a choice. The button moves up under the door's heading, the text
	 * follows it, and the hero above tightens. */
	.qs-hero .portal-hero__main {
		gap: var(--space-4);
		padding: var(--space-6) 0 var(--space-10);
	}

	.qs-door {
		padding: var(--space-4);
		gap: var(--space-2);
	}

	.qs-door > h2 {
		order: -2;
	}

	.qs-door__go {
		order: -1;
		margin-top: 0;
		padding-top: 0;
		margin-bottom: var(--space-1);
	}

	.qs-door__go .portal-button {
		width: 100%;
	}
}

@media (prefers-reduced-motion: reduce) {
	.qs-door {
		transition: none;
	}
}

/* ---- Sections ---- */

/* The site's section rhythm (its `section.tight`, 64px), closed by a hairline. */
.qs-section {
	padding-block: var(--space-16);
	border-top: var(--hairline);
}

@media (max-width: 40rem) {
	.qs-section {
		padding-block: var(--space-10);
	}
}

/* The site's `.section-title`: a section heading well above its items, which
 * were the same 22px before. `.portal h2` is (0,1,1), hence `.portal`. */
.portal .qs-title {
	font-size: clamp(28px, 3.4vw, var(--fs-display-md));
	line-height: var(--lh-snug);
	letter-spacing: var(--ls-display);
}

.qs-intro {
	max-width: 62ch;
	font-size: var(--fs-body-lg);
	color: var(--text-muted);
}

.qs-list {
	max-width: var(--qs-measure);
}

ol.qs-list {
	margin: 0;
	padding-left: var(--space-6);
	display: grid;
	gap: var(--space-3);
	line-height: var(--lh-body);
}

/* ---- First things to ask for: the cards ---- */

.qs-cards {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: var(--space-6);
	margin-top: var(--space-3);
}

.qs-card {
	display: flex;
	flex-direction: column;
	gap: var(--space-4);
	min-width: 0;
	padding: var(--space-8);
	background: var(--surface-card);
	border: var(--hairline);
	border-radius: var(--radius-block);
}

.portal .qs-card h3 {
	margin: 0;
	font-size: var(--fs-title);
}

/* A card this stage cannot serve says so under its title, in the muted
 * caption the wizard uses for the same fact. */
.portal .qs-card__note {
	margin: calc(-1 * var(--space-2)) 0 0;
	font-size: var(--fs-caption);
	color: var(--text-muted);
}

.qs-card__needs {
	display: grid;
	gap: var(--space-2);
	margin-top: auto;
}

.qs-card__label {
	font-size: var(--fs-overline);
	font-weight: var(--fw-semibold);
	letter-spacing: var(--ls-overline);
	text-transform: uppercase;
	color: var(--text-muted);
}

@media (max-width: 40rem) {
	.qs-cards {
		grid-template-columns: minmax(0, 1fr);
		gap: var(--space-4);
	}

	.qs-card {
		padding: var(--space-5);
	}
}

/* The site's `.tag`, in sentence case: these are operation names, too long
 * for its uppercase overline. One the person confirms is the warm tag, with
 * an icon named "Asks you first" so the colour is not the only signal; the
 * section's intro says what orange means. */
.qs-tags {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-2);
	margin: 0;
	padding: 0;
	list-style: none;
}

.qs-tag {
	padding: 4px 12px;
	border: 1px solid var(--hp-violet-100);
	border-radius: var(--radius-pill);
	background: var(--hp-violet-050);
	color: var(--hp-violet-700);
	font-size: var(--fs-caption);
	font-weight: var(--fw-semibold);
	line-height: var(--lh-body);
}

.qs-tag--confirm {
	border-color: var(--hp-orange-200);
	background: var(--hp-orange-100);
	color: var(--hp-orange-ink);
}

/* The icon that says "asks you first" without the colour (renderHtml's
 * CONFIRM_MARK), sitting on the label's x-height. */
.qs-tag__mark {
	display: inline-block;
	margin-right: 6px;
	vertical-align: -1px;
}

/* A card's second group ("May see" after "May change") opens with a little
 * more air than the grid's own gap. */
.qs-tags + .qs-card__label {
	margin-top: var(--space-2);
}

/* ---- Code ---- */

/* The site's `.prose code`: monospace a step below the text it sits in, on
 * the sunken cream, so a command name reads as a word rather than a block. */
.app-content :not(pre) > code {
	font-family: var(--portal-font-mono);
	font-size: 0.86em;
	padding: 0.08em 0.35em;
	border-radius: 3px;
	background: var(--surface-sunken);
	color: var(--text-strong);
	overflow-wrap: anywhere;
}

.qs-code {
	max-width: var(--qs-measure);
	box-sizing: border-box;
	margin: 0;
	padding: var(--space-4) var(--space-5);
	background: var(--surface-inverse);
	color: var(--surface-page);
	border-radius: var(--radius-sm);
	font-family: var(--portal-font-mono);
	font-size: var(--fs-caption);
	line-height: 1.7;
	overflow-x: auto;
	white-space: pre;
}

.qs-code code {
	background: none;
	color: inherit;
	padding: 0;
}

/* ---- What the person says to the agent ---- */

/* The site's `.pullquote`: a wholly serif block takes the accent colour as
 * well as the accent face (the site's hard rule), on a 2px violet rule and
 * no ground. */
.qs-say {
	max-width: var(--qs-measure);
	box-sizing: border-box;
	margin: 0;
	padding: 0 0 0 var(--space-5);
	border-left: 2px solid var(--hp-blue-violet);
	font-family: var(--font-accent);
	font-size: var(--fs-body-lg);
	line-height: 1.45;
	color: var(--text-accent-on-light);
	/* A sentence may carry a full URL. The page breaks it after a `/` or a
	 * `.` (renderHtml inserts the break points); `anywhere` is the fallback
	 * for a part still wider than the line. */
	overflow-wrap: anywhere;
}

/* The same sentence inside running text (the TL;DR's last line): the say
 * box's face and colour, so it reads as the words to type. */
.qs-quote {
	font-family: var(--font-accent);
	color: var(--text-accent-on-light);
}

/* ---- The TL;DR panel ---- */

/* A shortcut for people who already know Claude Code plugins, boxed as the
 * site's `.card` so it reads as a side door rather than the next step. Its
 * label is the cards' overline. Inside it the commands sit closer together
 * than the page's rhythm, as one install. */
.qs-panel {
	display: grid;
	gap: var(--space-3);
	max-width: var(--qs-measure);
	box-sizing: border-box;
	padding: var(--space-6);
	background: var(--surface-card);
	border: var(--hairline);
	border-radius: var(--radius-block);
}

.qs-panel__label {
	margin: 0;
	font-size: var(--fs-overline);
	font-weight: var(--fw-semibold);
	letter-spacing: var(--ls-overline);
	text-transform: uppercase;
	color: var(--text-muted);
}

.qs-panel > p:not(.qs-panel__label) {
	margin: var(--space-2) 0 0;
	line-height: var(--lh-body);
}

@media (max-width: 40rem) {
	.qs-panel {
		padding: var(--space-5);
	}
}

/* ---- Copy buttons (start.js) ---- */

/* A labelled pill, as the site's buttons are. A command block wears it in
 * its top-right corner; a sentence to say carries it under the sentence. */
.qs-copyable {
	position: relative;
	/* A grid item's min-width defaults to auto, so an unbreakable command line
	 * would widen the whole section; the <pre> scrolls instead. */
	min-width: 0;
	max-width: var(--qs-measure);
}

.qs-copyable--say {
	display: grid;
	justify-items: start;
	gap: var(--space-2);
}

.qs-copyable--say .qs-copy {
	margin-left: var(--space-5);
}

.qs-copy {
	flex: none;
	display: inline-flex;
	align-items: center;
	gap: 6px;
	height: 32px;
	padding: 0 14px;
	box-sizing: border-box;
	border: var(--border-w) solid var(--hp-violet-200);
	border-radius: var(--radius-pill);
	background: transparent;
	color: var(--text-accent-on-light);
	font-size: var(--fs-caption);
	font-weight: var(--fw-semibold);
	line-height: 1;
	white-space: nowrap;
	cursor: pointer;
	transition:
		background var(--dur-base) var(--ease-standard),
		border-color var(--dur-base) var(--ease-standard),
		color var(--dur-base) var(--ease-standard);
}

.qs-copy:hover {
	background: var(--hp-violet-050);
	border-color: var(--hp-blue-violet);
}

.qs-copy--done {
	color: var(--status-good);
	border-color: var(--status-good);
}

/* The block's scroller is the <pre>, so the pill sits on the wrapper and
 * never scrolls away with a long line. */
.qs-copyable--code .qs-code {
	padding-right: calc(var(--space-5) + 6rem);
}

.qs-copyable--code .qs-copy {
	position: absolute;
	top: var(--space-2);
	right: var(--space-2);
	/* Opaque on purpose: a long command scrolls under the pill, and a
	 * translucent ground let it show through (owner's call). Its z-index
	 * makes it a stacking context for the band below. */
	z-index: 1;
	border-color: rgba(253, 248, 232, 0.34);
	background: var(--surface-inverse);
	color: var(--surface-page);
}

.qs-copyable--code .qs-copy:hover {
	border-color: var(--surface-page);
	background: var(--hp-violet-700);
}

.qs-copyable--code .qs-copy--done {
	border-color: var(--surface-page);
}

/* A command that runs under the pill fades out before it instead of peeking
 * past it: a band from the block's right edge leftwards, solid where the
 * pill sits and transparent towards the text. It takes no clicks. */
.qs-copyable--code .qs-copy::before {
	content: "";
	position: absolute;
	z-index: -1;
	/* Measured from the pill's padding box, so its border is added back: the
	 * band reaches the block's edges exactly. */
	top: calc(-1 * (var(--space-2) + var(--border-w)));
	bottom: calc(-1 * (var(--space-2) + var(--border-w)));
	right: calc(-1 * (var(--space-2) + var(--border-w)));
	left: calc(-1 * var(--space-10));
	background: linear-gradient(
		to right,
		transparent,
		var(--surface-inverse) var(--space-8)
	);
	pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
	.qs-copy {
		transition: none;
	}
}

/* The twin's address, shown only when copying it failed (start.js), so the
 * reader can select and copy it by hand. A field in view, not a hidden one:
 * these pages hide nothing, and focus moves to it. */
.qs-copy-field {
	display: block;
	box-sizing: border-box;
	width: 100%;
	max-width: var(--qs-measure);
	margin-top: var(--space-2);
	padding: var(--space-2) var(--space-3);
	border: var(--hairline);
	border-radius: var(--radius-sm);
	background: var(--surface-card);
	color: var(--text-strong);
	font-family: var(--portal-font-mono);
	font-size: var(--fs-caption);
}

/* ---- The closed sections ---- */

/* "For your agent", "Do it by hand" and "If something goes wrong": rows
 * between hairlines, each with its heading and one line saying what is in
 * it, so they read as sections and not as three stray links. A native
 * <details> needs no script, so the pages read complete under the CSP
 * without start.js. */
.qs-under {
	display: grid;
	/* A <details>' grid items include the browser's content slot, whose
	 * min-content is the longest command; an auto column grows to it and
	 * widens the page on a phone. */
	grid-template-columns: minmax(0, 1fr);
	max-width: 100%;
	min-width: 0;
	border-bottom: var(--hairline);
}

.qs-under:first-of-type {
	border-top: var(--hairline);
}

/* A section that holds only closed sections already has its hairline; the
 * first row takes that one rather than drawing a second under 64px of
 * nothing. */
.qs-section > .qs-under:first-child {
	border-top: 0;
}

.qs-section:has(> .qs-under:first-child) {
	padding-top: var(--space-4);
}

.qs-under > summary,
.qs-check > summary {
	position: relative;
	display: grid;
	gap: var(--space-1);
	padding-right: var(--space-10);
	cursor: pointer;
	list-style: none;
}

.qs-under > summary::-webkit-details-marker,
.qs-check > summary::-webkit-details-marker {
	display: none;
}

.qs-under > summary {
	padding-block: var(--space-6);
}

/* The chevron: drawn, not a glyph, so it says nothing to a screen reader;
 * the <details> itself announces open and closed. */
.qs-under > summary::after,
.qs-check > summary::after {
	content: "";
	position: absolute;
	right: var(--space-3);
	top: 50%;
	width: 0.55rem;
	height: 0.55rem;
	border-right: var(--border-w) solid var(--hp-blue-violet);
	border-bottom: var(--border-w) solid var(--hp-blue-violet);
	transform: translateY(-75%) rotate(45deg);
	transition: transform var(--dur-base) var(--ease-standard);
}

.qs-under[open] > summary::after,
.qs-check[open] > summary::after {
	transform: translateY(-25%) rotate(-135deg);
}

.portal .qs-under__title {
	margin: 0;
	font-size: var(--fs-h3);
	color: var(--text-strong);
	transition: color var(--dur-base) var(--ease-standard);
}

.qs-under > summary:hover .qs-under__title {
	color: var(--hp-violet-700);
}

.qs-under__desc {
	font-size: var(--fs-body-sm);
	color: var(--text-muted);
}

.qs-under__body {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: var(--space-4);
	min-width: 0;
	padding-bottom: var(--space-10);
}

.qs-under__body p {
	margin: 0;
	max-width: var(--qs-measure);
}

.portal .qs-under__body h3 {
	margin: var(--space-4) 0 0;
	font-size: var(--fs-title);
}

/* "Before you act": the agent's first read, the host rule and every
 * restraint in one box. */
.qs-readfirst {
	display: grid;
	gap: var(--space-3);
	max-width: var(--qs-measure);
	box-sizing: border-box;
	padding: var(--space-4) var(--space-5);
	border-left: var(--border-w-frame) solid var(--border-brand);
	background: var(--surface-sunken);
}

/* ---- The failure checklists ---- */

/* Grouped by where in the setup they happen, each titled by what the person
 * sees, the code under it. A link such as #eperm opens one (start.js); it
 * lands below the sticky header. */
.portal .qs-under__body .qs-group {
	margin-top: var(--space-6);
	font-size: var(--fs-body);
	color: var(--text-muted);
	font-weight: var(--fw-semibold);
}

.qs-checks {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	max-width: var(--qs-measure);
	border-top: var(--hairline);
}

.qs-check {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: var(--space-3);
	min-width: 0;
	border-bottom: var(--hairline);
}

.qs-check > summary {
	padding-block: var(--space-3);
}

.qs-check[open] {
	padding-bottom: var(--space-4);
}

.qs-check__title {
	font-weight: var(--fw-semibold);
	color: var(--text-strong);
}

.qs-check__seen {
	font-size: var(--fs-body-sm);
	color: var(--text-muted);
	overflow-wrap: anywhere;
}

.qs-under,
.qs-check {
	scroll-margin-top: calc(var(--portal-nav-h) + var(--space-4));
}

@media (prefers-reduced-motion: reduce) {
	.qs-under > summary::after,
	.qs-check > summary::after,
	.portal .qs-under__title {
		transition: none;
	}
}
