/* The app-ui playground - the internal tester at /app-ui
   (templates/pages/app-ui.php). Geometry only: the parts inside wear the
   real chrome classes and paint themselves; this file only lays out the
   board and draws the "show boxes" outlines. */

.app-ui-playground {
	.try-links {
		margin-top: 1rem;
		padding: 0;
		list-style: none;

		li + li {
			margin-top: 0.75rem;
		}
	}

	.show-boxes {
		display: inline-flex;
		align-items: center;
		gap: 0.5em;
		margin-top: 1.5em;
	}

	/* One column per take, side by side, each the width of the designed
	   panel measure - the size the card really is. */
	.context-heading {
		margin-top: 3rem;
	}

	.app-ui-board {
		display: flex;
		flex-wrap: wrap;
		gap: 3rem;
		margin-top: 2rem;
	}

	.app-ui-column {
		width: var(--layout-panel-max);

		/* The column's own captions only - a bare "p" here reached into
		   the real panel's labels and skewed the "Today" measurements. */
		> p {
			margin-top: 1.5rem;
		}

		.toolbar,
		.app-card {
			margin-top: 0.5rem;
		}

		/* Left-aligned here - the live toolbar's row-reverse sits it in
		   the corner, but in a column the triggers read from the left. */
		.toolbar {
			justify-content: flex-end;
		}
	}

	/* Show boxes: outline each control's real box - the tap/grab area -
	   so the same-box rule and the target sizes are visible. Outline
	   never takes space, so turning it on moves nothing. A focused
	   control keeps its real focus ring instead - the dashes must never
	   hide where the keyboard is. */
	&:has(.show-boxes input:checked) {
		:is(.trigger, input[type='range'], .mode-button-group button):not(:focus-visible) {
			outline: 1px dashed var(--accent);
			outline-offset: 0;
		}
	}
}

/* CONTEXT - a phone-sized frame over a stand-in page, so the bar, the
   card, and the page can be seen meeting. px for the frame on purpose: it
   IS a device's width, not a type-scaled measure. The bar's height is the
   live tray's (a trigger plus its 0.5rem padding above and below) - which
   is why the frame wears data-ui='app': --app-trigger-size only exists
   inside the chrome's scope. */
.phone-context {
	--context-bar-height: calc(var(--app-trigger-size) + var(--app-border-width) * 2 + 1rem);

	position: relative;
	/* A phone doesn't get narrower because the row is crowded - the frame
	   keeps its width and the row scrolls. */
	flex-shrink: 0;
	width: 375px;
	height: 34rem;
	overflow: hidden;
	margin: 0;
	border: 1px solid var(--stroke-secondary);
	background: var(--fill-primary);

	/* The page behind: a gray field ruled like lines of text - enough to
	   judge the card's edges against, with no words to read. */
	.stand-in-page {
		position: absolute;
		inset: var(--context-bar-height) 0 0 0;
		background:
			repeating-linear-gradient(
				to bottom,
				transparent 0 1.2rem,
				color-mix(in oklch, var(--ink-primary) 12%, transparent) 1.2rem 1.9rem
			)
			var(--fill-secondary);
		background-clip: content-box;
		padding: 1.5rem var(--gutter);
	}

	/* No z-index, on purpose: like the live tray, the bar's background
	   paints UNDER the card, and only the triggers (the toolbar's own
	   z-index 2) ride above it. */
	.context-bar {
		position: absolute;
		inset: 0 0 auto 0;
		height: var(--context-bar-height);
		padding: 0.5rem var(--gutter);
		display: flex;
		justify-content: flex-end;
		align-items: center;
		background: var(--fill-primary);
	}

	/* The card, as the live phone posture draws it: flush to the right
	   edge, a strip of page left visible, no right border or corners. */
	.context-card {
		position: absolute;
		right: 0;
		z-index: 1;
		width: calc(100% - 5rem);
		border-right: none;
		border-radius: var(--app-corners) 0 0 var(--app-corners);
	}

	figcaption {
		position: absolute;
		left: 0;
		bottom: 0;
		z-index: 3;
		padding: 0.25rem 0.5rem;
		background: var(--fill-primary);
	}
}

/* A context row keeps its three placements in one line - the comparison
   IS the row - and scrolls sideways where the column is narrower than
   three phones, instead of wrapping them apart. */
.app-ui-playground .context-board {
	flex-wrap: nowrap;
	overflow-x: auto;
	gap: 1.5rem;
	padding-bottom: 0.5rem;
}

/* The three placements. */
.phone-context[data-placement='straddle'] .context-card {
	/* Today: the card's top edge through the triggers' midline. */
	top: calc(var(--context-bar-height) / 2);
}

.phone-context[data-placement='below'] .context-card {
	top: var(--context-bar-height);
}

.phone-context[data-placement='contain'] {
	/* The card rises to include the bar, so the icons sit inside it - the
	   bar steps back to let the card's own color show behind them. */
	.context-bar {
		background: transparent;
	}

	.context-card {
		top: 0;

		/* No top edge - matches the live try rule (settings-panel.css):
		   on a real phone the line across the top read as a leftover. */
		border-top: none;
		border-top-left-radius: 0;
	}

	.context-card .panel-scroll {
		padding-top: var(--context-bar-height);
	}
}

/* Float: the card detached below the bar, inset, rounded - the same
   placement the live chrome gets on a ?try=...-float visit
   (settings-panel.css). */
.phone-context[data-placement='float'] .context-card {
	top: calc(var(--context-bar-height) + var(--layout-panel-gap));
	right: var(--gutter);
	border-right: var(--app-border-width) solid var(--app-stroke);
	border-radius: calc(var(--app-trigger-size) / 3);
}

/* The ghost take the frames wear lives with the chrome's other rules -
   styles/modules/settings-panel.css, beside CHROME TAKES - because the
   live tray uses the same one on a ?try= visit. */


/* MENU FAMILIES - the pages menu painted after real products, on the
   /design-system/app-ui Menu row. Token values only (the menu's slots in
   settings-panel.css): link, row, icon, card. Nothing here can move a
   row. Raw product colors are named at their use: fidelity to the real
   thing is the point (the recognition test). */
.menu-example {
	flex-shrink: 0;
	width: 16rem;
	margin: 0;

	.app-card {
		margin-top: 0.5rem;
	}
}

/* Classic web - Wikipedia: blue underlined links, purple once visited,
   the current page as plain dark text with no underline (Wikipedia
   doesn't link the page you're on). */
.menu-example[data-family='classic'] [data-ui='app'] {
	--app-menu-link-color: var(--color-blue-700);
	--app-menu-link-visited-color: var(--color-purple-800);
	--app-menu-link-underline-color: currentColor;
	--app-menu-row-current-ink: var(--app-ink);
	--app-menu-row-current-decoration: none;
}

/* Finder - macOS sidebar: no underline, ink text, blue icons, the
   current row a soft rounded fill. */
.menu-example[data-family='finder'] [data-ui='app'] {
	--app-menu-link-color: var(--app-ink);
	--app-menu-link-decoration: none;
	--app-menu-icon-color: var(--color-blue-500);
	--app-menu-row-radius: 0.375rem;
	--app-menu-row-current-fill: color-mix(in oklch, var(--app-ink) 10%, var(--app-fill));
	--app-corners: 0.75rem;
}

/* shadcn - its dropdown: crisp black and white, small radius, a faint
   row fill, monochrome icons. */
.menu-example[data-family='shadcn'] [data-ui='app'] {
	--app-menu-link-color: var(--app-ink);
	--app-menu-link-decoration: none;
	--app-menu-row-radius: 0.25rem;
	--app-menu-row-current-fill: color-mix(in oklch, var(--app-ink) 6%, var(--app-fill));
	--app-corners: 0.5rem;
	--app-shadow: 0 4px 12px rgb(0 0 0 / 0.08);
}

/* Reveal - Claude / Linear: soft and quiet, rounder rows and card, a
   gentle tint for the current row. */
.menu-example[data-family='reveal'] [data-ui='app'] {
	--app-menu-link-color: var(--app-ink);
	--app-menu-link-decoration: none;
	--app-menu-row-radius: 0.5rem;
	--app-menu-row-current-fill: color-mix(in oklch, var(--app-ink) 7%, var(--app-fill));
	--app-corners: 1rem;
	--app-stroke: color-mix(in oklch, var(--app-ink) 10%, var(--app-fill));
	--app-shadow: 0 8px 24px rgb(0 0 0 / 0.1);
}

/* Windows 95 - the silver window: a raised bevel (light top-left, dark
   bottom-right), square everything, the current item as the navy
   selection bar with white text. */
.menu-example[data-family='win95'] [data-ui='app'] {
	--app-fill: var(--color-neutral-300);
	--app-ink: var(--color-neutral-950);

	/* The real Windows 95 raised edge is two layers, lit from the top
	   left: white then light gray on the lit sides, near-black then dark
	   gray on the shaded ones. The 1px border takes the outermost dark
	   ring's color on its shaded sides only - drawn in box-shadow, so
	   nothing grows. */
	--app-stroke: var(--color-neutral-300);
	--app-shadow:
		inset 1px 1px 0 var(--color-neutral-50),
		inset -1px -1px 0 var(--color-neutral-950),
		inset 2px 2px 0 var(--color-neutral-200),
		inset -2px -2px 0 var(--color-neutral-500);
	--app-menu-link-color: var(--app-ink);
	--app-menu-link-decoration: none;
	--app-menu-row-current-fill: var(--color-blue-900);
	--app-menu-row-current-ink: var(--color-neutral-50);
}

/* Terminal - green on black, the current item inverted. */
.menu-example[data-family='terminal'] [data-ui='app'] {
	--app-fill: var(--color-neutral-950);
	--app-ink: var(--color-green-400);
	--app-stroke: var(--color-green-700);
	--app-shadow: none;
	--app-menu-link-color: var(--app-ink);
	--app-menu-link-decoration: none;
	--app-menu-row-current-fill: var(--color-green-400);
	--app-menu-row-current-ink: var(--color-neutral-950);
}

/* Claude Code - the desktop app's own menus: a warm cream surface and a
   warm near-black ink (never cold gray), a hairline warm border, generous
   corners, a soft shadow, line icons in the text's own ink, and the
   current row a soft rounded warm-gray fill. No underlines. */
.menu-example[data-family='claude-code'] [data-ui='app'] {
	--app-fill: var(--color-stone-50);
	--app-ink: var(--color-stone-900);
	--app-stroke: var(--color-stone-200);
	--app-corners: 0.875rem;
	--app-shadow: 0 6px 20px rgb(0 0 0 / 0.08);
	--app-menu-link-color: var(--app-ink);
	--app-menu-link-decoration: none;
	--app-menu-row-radius: 0.5rem;
	--app-menu-row-current-fill: var(--color-stone-100);
}


/* FAMILIES - a family painted down the whole panel (the Families row).
   A frame's forced scheme flips every light-dark() token inside it. */
.phone-context[data-scheme='light'] {
	color-scheme: light;
}

.phone-context[data-scheme='dark'] {
	color-scheme: dark;
}

/* Restate the ink inside a forced-scheme frame: an inherited color was
   already resolved in the page's own scheme, so the dark frame's caption
   came through light-scheme gray on black. */
.phone-context[data-scheme] {
	color: var(--ink-primary);
}

/* INTERFACE - Claude Code in the light, Linear in the dark, the flat ring
   for an edge (the contract, settings-panel.css). Paints the frames here,
   and the live chrome on a ?family=interface visit (index.php). One light-dark() pair per
   token, so the scheme flips it and nothing else. */
:is(html[data-family='interface'] [data-ui='app'], .phone-context[data-family='interface'], .phone-context[data-family='interface'] [data-ui='app']) {
	--app-fill: light-dark(var(--color-stone-50), var(--color-neutral-950));
	--app-ink: light-dark(var(--color-stone-900), var(--color-neutral-100));
	--app-stroke: light-dark(var(--color-stone-300), var(--color-neutral-800));
	--app-corners: 0.875rem;

	/* The flat ring: a solid band and a hairline outside it - zero blur,
	   zero offset, so the card extends into a frame without growing. */
	--app-shadow:
		0 0 0 3px light-dark(var(--color-stone-100), var(--color-neutral-900)),
		0 0 0 4px light-dark(var(--color-stone-300), var(--color-neutral-800));

	/* Pills: a soft rounded TRACK holds the options (so the row reads as
	   one control even when only one part is lit), the chosen one raised
	   on it in the card's own color with a hairline. */
	--app-pill-group-fill: light-dark(var(--color-stone-100), var(--color-neutral-900));
	--app-pill-group-radius: 0.5rem;
	--app-pill-fill: transparent;
	--app-pill-hover-fill: light-dark(var(--color-stone-200), var(--color-neutral-800));
	--app-pill-stroke: transparent;
	--app-pill-radius: 0.5rem;
	--app-pill-checked-fill: light-dark(var(--color-neutral-50), var(--color-neutral-800));
	--app-pill-checked-stroke: light-dark(var(--color-stone-300), var(--color-neutral-700));

	/* Menu, as in the Claude Code menu example - the row lights on HOVER;
	   the current page doesn't fill (you know where you are). */
	--app-menu-link-color: var(--app-ink);
	--app-menu-link-decoration: none;
	--app-menu-row-radius: 0.5rem;
	--app-menu-row-hover-fill: light-dark(var(--color-stone-100), var(--color-neutral-800));
	--app-menu-row-press-fill: light-dark(var(--color-stone-200), var(--color-neutral-700));
	--app-menu-row-current-fill: transparent;
}

/* Sliders: a small flat knob, no halo at rest (the grab still gets its
   halo - :not(.is-grabbed) leaves the grab rules alone), a hairline-toned
   track. The knobs live on the input itself, so the family names it. */
:is(html[data-family='interface'], .phone-context[data-family='interface']) .plain-range:not(.is-grabbed) {
	--range-dot: 12px;
	--range-halo-strength: 0%;
	--range-track: light-dark(var(--color-stone-200), var(--color-neutral-800));
}

/* INTERFACE x SWEET - Slack (Derek, 2026-09-25): the Sweet flavor carries
   Slack's aubergine into the Interface chrome. Dark is the aubergine
   sidebar - deep purple surfaces, white text and knobs; light is a purple
   tinted cream, so the flavor is purple in both schemes (the continuity
   rule). A deliberate color alias: the page's flavor choosing the chrome's
   palette, never a page rule reaching in. */
html[data-family='interface'][data-flavor='sweet'] [data-ui='app'] {
	/* Slack puts its purple at the EDGES only - the title bar and the
	   workspace rail - and reads on near-black with a hint of plum; the
	   chosen channel is a slightly lighter plum-gray row (Derek's Slack
	   screenshot, 2026-09-25: the all-purple card was "a bit over the
	   top"). So here the flat ring is Slack's frame and carries the
	   aubergine; the card is the near-black sidebar. Named in oklch -
	   fidelity is the point. */
	--slack-sidebar: oklch(19% 0.025 328);
	--slack-frame: oklch(27% 0.085 328);
	--slack-frame-edge: oklch(33% 0.09 328);
	--slack-hairline: oklch(30% 0.03 328);
	--slack-chosen: oklch(29% 0.035 328);

	--app-fill: light-dark(var(--color-purple-50), var(--slack-sidebar));
	--app-ink: light-dark(var(--color-purple-950), oklch(93% 0.01 328));
	--app-stroke: light-dark(var(--color-purple-200), var(--slack-hairline));
	--app-shadow:
		0 0 0 3px light-dark(var(--color-purple-100), var(--slack-frame)),
		0 0 0 4px light-dark(var(--color-purple-200), var(--slack-frame-edge));
	--app-pill-group-fill: light-dark(var(--color-purple-100), oklch(16% 0.02 328));
	--app-pill-checked-fill: light-dark(var(--color-neutral-50), var(--slack-chosen));
	--app-pill-checked-stroke: light-dark(var(--color-purple-200), var(--slack-hairline));
	--app-menu-row-hover-fill: light-dark(var(--color-purple-100), var(--slack-chosen));
}

html[data-family='interface'][data-flavor='sweet'] .plain-range:not(.is-grabbed) {
	--range-track: light-dark(var(--color-purple-200), oklch(30% 0.03 328));
}
