/* Tokens come from themes.css (generated); this file only consumes them. */
@font-face { font-family: "Space Grotesk"; font-weight: 400; font-display: swap; src: url("fonts/SpaceGrotesk_400Regular.ttf") format("truetype"); }
@font-face { font-family: "Space Grotesk"; font-weight: 500; font-display: swap; src: url("fonts/SpaceGrotesk_500Medium.ttf") format("truetype"); }
@font-face { font-family: "Space Grotesk"; font-weight: 600; font-display: swap; src: url("fonts/SpaceGrotesk_600SemiBold.ttf") format("truetype"); }
@font-face { font-family: "Space Grotesk"; font-weight: 700; font-display: swap; src: url("fonts/SpaceGrotesk_700Bold.ttf") format("truetype"); }

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

/* The page wears the active app's theme (spec §5.2); the crossfade is the retheme.
   Its ground is the app's canvas, except where that canvas is near black: the
   page lifts those two to the lightness of Dear Child's and Author's canvases.
   Only the page: the frames keep each app's own canvas. */
[data-app="baby-sleep-tracker"] { --page: #1E1925; }
[data-app="rookshade"] { --page: #1D1D1D; }
html {
    background: var(--page, var(--canvas));
    color: var(--text);
    font-family: var(--font-sans), system-ui, sans-serif;
    font-weight: var(--font-sans-weight);
    font-size: var(--fs-md);
    line-height: var(--lh-md);
    transition: background-color 400ms ease, color 400ms ease;
}
@media (prefers-reduced-motion: reduce) {
    html { transition: none; }
}

/* Page (spec §3): title, carousel, app block, stacked and centered. The
   carousel runs edge to edge so the deck can be clipped at the viewport. */
main {
    /* The active frame's width: the deck sizes the frames from it, and the title aligns to the frame's left edge. */
    --frame-width: 320px;
    display: flex; flex-direction: column; align-items: center; gap: 16px; padding: 24px 0 64px;
}
/* Narrow viewports: the frame keeps a 44 px band each side for the neighbours to peek into. */
@media (max-width: 719px) {
    main { --frame-width: min(320px, calc(100vw - 88px)); }
}
/* Static content (search spec §3): what readers without script see; main.ts replaces it on mount.
   A scripted page hides it, but only for 3 s, so a bundle that never mounts still leaves it readable. */
[data-js] main > .static { visibility: hidden; animation: static-reveal 0s 3s forwards; }
@keyframes static-reveal { to { visibility: visible; } }
.static { display: flex; flex-direction: column; gap: 16px; width: min(40rem, 100% - 32px); }
.static section { display: flex; flex-direction: column; gap: 12px; }
.static h1, .static h2, .static p, .static ul { margin: 0; }
.static h1 { font-size: var(--fs-xl); line-height: var(--lh-xl); }
.static h2 { font-size: var(--fs-lg); line-height: var(--lh-lg); }
.static ul { display: flex; flex-direction: column; gap: 8px; padding-inline-start: 1.25em; }
.static nav { display: flex; flex-wrap: wrap; gap: 16px; }
.static a { color: var(--primary); }
.visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.skip { position: absolute; left: -9999px; color: var(--text); }
.skip:focus { position: static; }

/* Title (spec §3.1): wordmark, then the active app's logo beside its name, store icons and tagline.
   On wide viewports the wordmark and the text start at the active frame's screen edge and the logo
   hangs to the text's left, so switching apps changes only where the lines end. */
.title { display: flex; flex-direction: column; align-items: center; gap: 20px; padding: 0 16px; }
@media (min-width: 720px) {
    /* The title's 16 px padding plus 50 % of its content box is half the page width. The text starts
       past the frame's bezel (.phone's padding, 10 px of a 300 px frame) so it lines up with the
       screen, not the rounded outer corner. */
    /* No gap: the text is centred against the taller logo, so the name already sits 6 px into the row,
       and the wordmark's baseline then lies as far above the name's capitals as the name's baseline
       lies above the tagline's. */
    .title { --text-start: calc(50% - var(--frame-width) / 2 + var(--frame-width) * 10 / 300); align-self: stretch; align-items: stretch; gap: 0; }
    .wordmark { padding-left: var(--text-start); }
    /* 100 px is the 80 px logo and the row's 20 px gap. */
    .title-row { padding-left: calc(var(--text-start) - 100px); }
}
.wordmark { margin: 0; color: var(--text-muted); font-size: var(--fs-sm); line-height: var(--lh-sm); font-weight: var(--font-sans-semibold-weight); letter-spacing: 0.04em; }
.title-row { display: flex; align-items: center; gap: 20px; }
.marks { display: grid; flex: 0 0 auto; width: 80px; height: 80px; }
.brand-mark {
    grid-area: 1 / 1; width: 100%; height: 100%; color: var(--text);
    opacity: 0; transform: scale(0.8) rotate(-8deg);
    transition: opacity 300ms ease, transform 420ms cubic-bezier(0.3, 1.4, 0.5, 1);
}
.brand-mark[data-current] { opacity: 1; transform: none; }
.title-text { display: flex; flex-direction: column; gap: 4px; }
/* The icons stand on the name's baseline: a button has no text baseline, so its bottom edge takes it,
   and the logos sit at the buttons' bottoms. */
.name-line { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 16px; }
.title-store { display: flex; gap: 4px; }
.title-store:empty { display: none; }
.store-icon {
    display: inline-flex; align-items: flex-end; justify-content: center;
    width: 36px; height: 36px; padding: 0; border: 0; border-radius: var(--radius-pill);
    background: none; color: var(--text-muted); cursor: pointer;
}
.store-icon-logo { width: 22px; height: 22px; }
.store-icon:hover, .store-icon:focus-visible { color: var(--text); }
.store-icon:focus-visible { outline: 3px solid var(--primary); outline-offset: 2px; }
.title h1 {
    margin: 0; font-size: var(--fs-display); line-height: var(--lh-display);
    font-weight: var(--font-sans-bold-weight); letter-spacing: -0.01em; text-wrap: balance;
}
.title .tagline { margin: 0; color: var(--text-muted); font-size: var(--fs-lg); line-height: var(--lh-lg); text-wrap: balance; }
@media (max-width: 719px) {
    .title-row { flex-direction: column; gap: 16px; text-align: center; }
    /* The icons take their own row under the tagline, so a long name never wraps them beside it. */
    .name-line { display: contents; }
    .title-store { order: 1; justify-content: center; }
    .marks { width: 64px; height: 64px; }
}

/* Background (spec §5.3): the active app's drawn tile, an alpha-only image painted in the app's primary colour. */
.backdrop { position: fixed; inset: 0; z-index: -1; pointer-events: none; }
.backdrop-layer { position: absolute; inset: 0; opacity: 0; transition: opacity 400ms ease; }
.backdrop-layer[data-current] { opacity: 1; }
/* Positioned hosts only (.screen, .backdrop-layer); the tile sits under the host's content. */
.pattern { isolation: isolate; }
.pattern::before {
    content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
    --tile: calc(var(--pattern-width) * var(--pattern-scale, 1)) calc(var(--pattern-height) * var(--pattern-scale, 1));
    opacity: var(--pattern-opacity);
    background: var(--primary);
    /* Chrome and Edge before 120 (in the spec's browser range) read only the prefixed shorthand. */
    -webkit-mask: var(--pattern-url) 50% 0 / var(--tile) repeat;
    mask: var(--pattern-url) 50% 0 / var(--tile) repeat;
}
.screen.pattern { --pattern-scale: var(--frame-scale, 1); }

/* Carousel (spec §3.2): a stacked deck. The apps and a ghost form a ring; JS
   sets each frame's data-offset (its distance from the active frame, −2…2) and
   CSS places it. A frame is authored at 300×650; --frame-scale is set in JS
   from the measured width (frameWidth / 300) because CSS cannot divide two
   lengths, and every px inside a frame is written as calc(Npx * var(--frame-scale, 1)). */
.carousel { width: 100%; overflow-x: clip; padding: 12px 0 36px; }
.frames {
    position: relative; height: calc(var(--frame-width) * 650 / 300);
    list-style: none; margin: 0; padding: 0;
}
/* Horizontal drags are the deck's (carousel.ts); vertical ones still scroll the page and the screens. */
.frames, .frames * { touch-action: pan-y pinch-zoom; }
.frame {
    --x: 0; --s: 1;
    position: absolute; top: 0; left: calc(50% - var(--frame-width) / 2);
    width: var(--frame-width); height: 100%;
    transform: translateX(calc(var(--x) * var(--frame-width))) scale(var(--s));
    transition: transform 460ms cubic-bezier(0.22, 0.8, 0.24, 1);
}
.frame[data-offset="0"] { z-index: 3; }
.frame[data-offset="1"] { --x: 0.4; --s: 0.88; z-index: 2; }
.frame[data-offset="-1"] { --x: -0.4; --s: 0.88; z-index: 2; }
.frame[data-offset="2"] { --x: 0.7; --s: 0.76; z-index: 1; }
.frame[data-offset="-2"] { --x: -0.7; --s: 0.76; z-index: 1; }
.frame[data-instant] { transition: none; }
.frame-activate {
    position: absolute; inset: 0; z-index: 3;
    background: transparent; border: 0; border-radius: calc(48px * var(--frame-scale, 1)); cursor: pointer;
}
.frame-activate:focus-visible { outline: 3px solid var(--primary); outline-offset: 4px; }
/* The screen takes the pointer; the button stays the keyboard anchor (spec §3.2, §7). */
.frame[data-active] .frame-activate { pointer-events: none; }
.phone {
    position: absolute; inset: 0;
    padding: calc(10px * var(--frame-scale, 1)); border-radius: calc(48px * var(--frame-scale, 1));
    background: #0b0b0d; box-shadow: 0 24px 60px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(255, 255, 255, 0.06);
}
/* Frames behind the active one are shaded, not faded: a translucent frame would show the one under it. */
.phone::after {
    content: ""; position: absolute; inset: 0; z-index: 4; pointer-events: none;
    border-radius: inherit; background: #000; opacity: 0; transition: opacity 300ms ease;
}
.frame[data-offset="1"] .phone::after, .frame[data-offset="-1"] .phone::after { opacity: 0.4; }
.frame[data-offset="2"] .phone::after, .frame[data-offset="-2"] .phone::after { opacity: 0.62; }
.frame[data-kind="app"]:not([data-active]):hover .phone::after { opacity: 0.15; }
.phone-island {
    position: absolute; z-index: 2; left: 50%; transform: translateX(-50%);
    top: calc(20px * var(--frame-scale, 1)); width: calc(100px * var(--frame-scale, 1)); height: calc(30px * var(--frame-scale, 1));
    border-radius: calc(15px * var(--frame-scale, 1)); background: #000;
}
.screen {
    position: relative; height: 100%; overflow: hidden;
    display: flex; flex-direction: column;
    border-radius: calc(40px * var(--frame-scale, 1));
    background: var(--canvas); color: var(--text);
    font-family: var(--font-sans), system-ui, sans-serif;
    font-size: calc(var(--fs-md) * var(--frame-scale, 1));
}
.status-bar {
    display: flex; justify-content: space-between; align-items: center;
    padding: calc(18px * var(--frame-scale, 1)) calc(28px * var(--frame-scale, 1)) 0;
    font-size: calc(var(--fs-sm) * var(--frame-scale, 1)); font-weight: var(--font-sans-semibold-weight);
}
.status-glyphs { display: flex; align-items: center; gap: calc(6px * var(--frame-scale, 1)); }
.signal { display: flex; align-items: flex-end; gap: calc(2px * var(--frame-scale, 1)); height: calc(11px * var(--frame-scale, 1)); }
.signal i { width: calc(3px * var(--frame-scale, 1)); border-radius: 1px; background: currentColor; }
.signal i:nth-child(1) { height: 40%; }
.signal i:nth-child(2) { height: 60%; }
.signal i:nth-child(3) { height: 80%; }
.signal i:nth-child(4) { height: 100%; }
.battery {
    width: calc(24px * var(--frame-scale, 1)); height: calc(11px * var(--frame-scale, 1));
    padding: calc(1.5px * var(--frame-scale, 1));
    border: calc(1px * var(--frame-scale, 1)) solid currentColor; border-radius: calc(3px * var(--frame-scale, 1));
    background: currentColor content-box;
}
.screen-body { flex: 1; min-height: 0; display: flex; flex-direction: column; }

/* Baby Sleep Tracker slice: Today (spec §4.1). Laid out in the app's points:
   the 280 px screen of a 300 px frame stands for a 402 pt iPhone, so --u is one
   point. Measurements are the app's components' (LiveSessionCard,
   DiaryDayTotals, TimelineRows, FloatingActionButton, the native tab bar). */
.slice-baby-sleep {
    --u: calc(var(--frame-scale, 1) * 280 / 402);
    position: relative; flex: 1; min-height: 0; display: flex; flex-direction: column;
    line-height: calc(var(--lh-md) * var(--u));
}
.slice-baby-sleep h2, .slice-baby-sleep h3, .slice-baby-sleep p, .slice-baby-sleep dl, .slice-baby-sleep dd, .slice-baby-sleep ol { margin: 0; }
/* The native header: a standard centred title on the surface, which runs up under the status bar. */
.screen[data-app="baby-sleep-tracker"] .status-bar { background: var(--surface); }
.slice-baby-sleep .nav-bar {
    flex: 0 0 auto; display: flex; align-items: center; justify-content: center;
    height: calc(62px * var(--u)); background: var(--surface);
}
.slice-baby-sleep .nav-bar h2 { font-size: calc(17px * var(--u)); line-height: calc(22px * var(--u)); font-weight: var(--font-sans-bold-weight); }
/* Bottom padding clears the floating button and the tab bar, as the app's list does. */
.slice-baby-sleep .content {
    flex: 1; min-height: 0; overflow-y: auto; scrollbar-width: none;
    display: flex; flex-direction: column; gap: calc(24px * var(--u));
    padding: calc(24px * var(--u)) calc(16px * var(--u)) calc(180px * var(--u));
}
.slice-baby-sleep .summary { display: flex; flex-direction: column; gap: calc(8px * var(--u)); }
.slice-baby-sleep .card {
    display: flex; flex-direction: column; gap: calc(16px * var(--u));
    padding: calc(16px * var(--u)); border-radius: calc(var(--radius-lg) * var(--u)); background: var(--surface);
}
.slice-baby-sleep .live { padding-bottom: calc(12px * var(--u)); }
.slice-baby-sleep .state-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: calc(16px * var(--u)); }
.slice-baby-sleep .state { font-size: calc(var(--fs-xl) * var(--u)); line-height: calc(var(--lh-xl) * var(--u)); font-weight: var(--font-sans-bold-weight); }
.slice-baby-sleep .elapsed {
    font-family: var(--font-mono), var(--font-sans), monospace; font-weight: var(--font-mono-weight);
    font-size: calc(var(--fs-display) * var(--u)); line-height: calc(var(--lh-display) * var(--u));
    font-variant-numeric: tabular-nums;
}
.slice-baby-sleep .totals-heading { display: flex; flex-direction: column; gap: calc(4px * var(--u)); }
.slice-baby-sleep .totals-heading h3 { font-size: calc(var(--fs-md) * var(--u)); line-height: calc(var(--lh-md) * var(--u)); font-weight: var(--font-sans-semibold-weight); }
.slice-baby-sleep .boundary { color: var(--text-muted); font-size: calc(var(--fs-sm) * var(--u)); line-height: 1; }
.slice-baby-sleep .metrics { display: grid; grid-template-columns: 1fr 1fr; gap: calc(8px * var(--u)); }
.slice-baby-sleep .metrics > div {
    display: flex; flex-direction: column; gap: calc(8px * var(--u)); min-width: 0;
    padding: calc(16px * var(--u)) calc(16px * var(--u)) calc(12px * var(--u));
    border-radius: calc(var(--radius-md) * var(--u)); background: var(--surface-muted);
}
.slice-baby-sleep dt { color: var(--text-muted); font-size: calc(var(--fs-xs) * var(--u)); line-height: 1; }
.slice-baby-sleep dd { white-space: nowrap; font-family: var(--font-mono), var(--font-sans), monospace; font-size: calc(var(--fs-md) * var(--u)); line-height: 1; }
.slice-baby-sleep .timeline, .slice-baby-sleep .timeline ol { display: flex; flex-direction: column; gap: calc(8px * var(--u)); }
.slice-baby-sleep .timeline ol { list-style: none; padding: 0; }
.slice-baby-sleep .timeline-heading {
    display: flex; align-items: center; justify-content: space-between; gap: calc(16px * var(--u));
    min-height: calc(36px * var(--u));
}
.slice-baby-sleep .timeline-heading h3 {
    padding: 0 calc(16px * var(--u));
    font-size: calc(var(--fs-xl) * var(--u)); line-height: calc(var(--lh-xl) * var(--u)); font-weight: var(--font-sans-bold-weight);
}
.slice-baby-sleep .add-sleep {
    padding: 0 calc(16px * var(--u)); color: var(--primary);
    font-size: calc(var(--fs-sm) * var(--u)); line-height: 1.25; font-weight: var(--font-sans-semibold-weight);
}
/* Timeline rows: awake stretches on the muted fill, sleeps as surface cards (TimelineRows). */
.slice-baby-sleep .row {
    display: flex; flex-direction: column; gap: calc(4px * var(--u));
    padding: calc(16px * var(--u)); border-radius: calc(var(--radius-lg) * var(--u));
    border: calc(1px * var(--u)) solid transparent; background: var(--surface);
}
.slice-baby-sleep .row.awake { border: 0; background: var(--surface-muted); }
.slice-baby-sleep .row-main, .slice-baby-sleep .row-meta { display: flex; align-items: center; justify-content: space-between; gap: calc(16px * var(--u)); }
.slice-baby-sleep .row-title {
    display: flex; align-items: center; gap: calc(5px * var(--u)); min-width: 0;
    font-size: calc(var(--fs-md) * var(--u)); line-height: calc(var(--lh-md) * var(--u)); font-weight: var(--font-sans-semibold-weight);
}
/* The app's reporting palette: day #F1A45B for awake, night #6686E8 for sleep. */
.slice-baby-sleep .row-icon { flex: 0 0 auto; width: calc(16px * var(--u)); height: calc(16px * var(--u)); color: #6686E8; }
.slice-baby-sleep .row.awake .row-icon { color: #F1A45B; }
.slice-baby-sleep .row .duration { flex-shrink: 0; font-size: calc(var(--fs-sm) * var(--u)); line-height: calc(var(--lh-sm) * var(--u)); }
.slice-baby-sleep .row-meta { color: var(--text-muted); font-size: calc(var(--fs-xs) * var(--u)); line-height: calc(var(--lh-xs) * var(--u)); }
.slice-baby-sleep .row-edit { flex: 0 0 auto; width: calc(14px * var(--u)); height: calc(14px * var(--u)); color: var(--primary); }
.slice-baby-sleep .empty { display: flex; flex-direction: column; gap: calc(8px * var(--u)); padding: calc(24px * var(--u)) calc(8px * var(--u)); text-align: center; }
.slice-baby-sleep .empty h3 { font-size: calc(var(--fs-md) * var(--u)); font-weight: var(--font-sans-semibold-weight); }
.slice-baby-sleep .empty p { color: var(--text-muted); font-size: calc(var(--fs-sm) * var(--u)); line-height: calc(var(--lh-sm) * var(--u)); }
.slice-baby-sleep .status { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
/* Full width over the tab bar: 16 pt in from each side, 17 pt above the bar. */
.slice-baby-sleep .fab {
    position: absolute; left: calc(16px * var(--u)); right: calc(16px * var(--u)); bottom: calc(99px * var(--u));
    height: calc(52px * var(--u)); padding: 0 calc(8px * var(--u));
    border: 0; border-radius: var(--radius-pill);
    background: var(--primary); color: var(--on-primary);
    font: inherit; font-size: calc(var(--fs-md) * var(--u)); font-weight: var(--font-sans-semibold-weight);
    white-space: nowrap; cursor: pointer;
    box-shadow: 0 calc(4px * var(--u)) calc(8px * var(--u)) color-mix(in srgb, var(--overlay) 35%, transparent);
}
.slice-baby-sleep .fab:focus-visible { outline: calc(3px * var(--u)) solid var(--text); outline-offset: calc(3px * var(--u)); }
/* The floating tab bar of iOS 26, drawn: a translucent pill with the current tab in its own capsule. */
.slice-baby-sleep .tab-bar {
    position: absolute; left: calc(21px * var(--u)); right: calc(21px * var(--u)); bottom: calc(22px * var(--u));
    height: calc(60px * var(--u)); padding: calc(4px * var(--u));
    display: grid; grid-template-columns: repeat(5, 1fr);
    border-radius: var(--radius-pill);
    border: calc(1px * var(--u)) solid color-mix(in srgb, var(--text) 14%, transparent);
    background: color-mix(in srgb, var(--surface-muted) 82%, transparent);
    -webkit-backdrop-filter: blur(calc(12px * var(--u))); backdrop-filter: blur(calc(12px * var(--u)));
    box-shadow: 0 calc(6px * var(--u)) calc(16px * var(--u)) rgba(0, 0, 0, 0.35);
}
.slice-baby-sleep .tab {
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: calc(2px * var(--u));
    border-radius: var(--radius-pill); color: var(--text);
    font-size: calc(10px * var(--u)); line-height: calc(12px * var(--u)); font-weight: var(--font-sans-medium-weight);
}
.slice-baby-sleep .tab.current { background: color-mix(in srgb, var(--canvas) 70%, transparent); font-weight: var(--font-sans-semibold-weight); }
.slice-baby-sleep .tab-icon-slot { display: flex; color: var(--primary); }
.slice-baby-sleep .tab-icon { width: calc(24px * var(--u)); height: calc(24px * var(--u)); }
/* Last in the block: it must beat the equally specific display rules above. */
.slice-baby-sleep [hidden] { display: none; }

/* Rookshade slice: three one-move levels (spec §4.2), as the app's game screen draws them: a form
   sheet at the 0.85 detent over the pack's level list. Laid out in the app's points, as the sleep
   slice is; measurements are the game route's ([index].tsx) and packages/ui's tokens. */
.slice-rookshade {
    --u: calc(var(--frame-scale, 1) * 280 / 402);
    position: relative; flex: 1; min-height: 0; display: flex; flex-direction: column;
    line-height: calc(var(--lh-md) * var(--u));
}
.slice-rookshade h2, .slice-rookshade p { margin: 0; }
/* The level list behind the sheet, dimmed as iOS dims a sheet's presenter; with the status bar it
   fills the top 15 % of the screen. */
.screen[data-app="rookshade"] { background: color-mix(in srgb, var(--canvas) 70%, #000); }
.slice-rookshade .presenter {
    flex: 0 0 auto; display: flex; align-items: center; justify-content: center;
    height: calc(80px * var(--u));
    color: color-mix(in srgb, var(--text) 55%, #000);
    font-size: calc(17px * var(--u)); line-height: calc(22px * var(--u)); font-weight: var(--font-sans-semibold-weight);
}
.slice-rookshade .game-sheet {
    flex: 1; min-height: 0; display: flex; flex-direction: column; overflow: hidden;
    border-radius: calc(36px * var(--u)) calc(36px * var(--u)) 0 0; background: var(--sheet);
}
/* The sheet's native header: a back chevron, the mode's name centred, the help button. */
.slice-rookshade .sheet-header {
    flex: 0 0 auto; display: grid; grid-template-columns: calc(44px * var(--u)) 1fr calc(44px * var(--u)); align-items: center;
    gap: calc(8px * var(--u)); padding: calc(12px * var(--u)) calc(16px * var(--u)) 0;
}
.slice-rookshade .sheet-header h2 {
    text-align: center; font-size: calc(17px * var(--u)); line-height: calc(22px * var(--u)); font-weight: var(--font-sans-semibold-weight);
}
.slice-rookshade .sheet-header h2:focus { outline: none; }
.slice-rookshade .sheet-header h2:focus-visible { outline: calc(2px * var(--u)) solid var(--primary); outline-offset: calc(2px * var(--u)); }
.slice-rookshade .header-button {
    display: flex; align-items: center; justify-content: center;
    width: calc(44px * var(--u)); height: calc(44px * var(--u)); padding: 0;
    border: 0; border-radius: var(--radius-pill); background: color-mix(in srgb, var(--text) 10%, transparent); color: var(--text);
}
.slice-rookshade button.header-button { cursor: pointer; }
.slice-rookshade .header-button:focus-visible { outline: calc(3px * var(--u)) solid var(--primary); outline-offset: calc(2px * var(--u)); }
.slice-rookshade .header-icon { width: calc(24px * var(--u)); height: calc(24px * var(--u)); }
/* The board fits this box; the view measures it, so it must take its size from the column, not the board. */
.slice-rookshade .board-area {
    flex: 1; min-height: 0; overflow: hidden;
    display: flex; align-items: center; justify-content: center;
    padding: calc(8px * var(--u)) 0;
}
.slice-rookshade .board-wrap { position: relative; display: flex; }
.slice-rookshade .board-buttons { position: absolute; inset: 0; display: grid; }
.slice-rookshade .board-buttons button { background: transparent; border: 0; padding: 0; cursor: pointer; }
.slice-rookshade .board-buttons button:focus-visible { outline: calc(3px * var(--u)) solid var(--primary); outline-offset: calc(-3px * var(--u)); }
/* The bottom panel: clear glass on iOS 26, drawn as a lifted edge over the sheet. */
.slice-rookshade .panel {
    flex: 0 0 auto;
    padding: calc(16px * var(--u)) calc(24px * var(--u)) calc(34px * var(--u));
    border-radius: calc(var(--radius-lg) * var(--u)) calc(var(--radius-lg) * var(--u)) 0 0;
    border-top: calc(1px * var(--u)) solid color-mix(in srgb, var(--text) 16%, transparent);
    background: color-mix(in srgb, var(--text) 6%, var(--sheet));
}
/* Its least height is one title line, a small gap and a medium control, as the app reserves. */
.slice-rookshade .panel-body {
    display: flex; flex-direction: column; justify-content: center; gap: calc(16px * var(--u));
    min-height: calc((32px + 8px + 44px) * var(--u));
}
.slice-rookshade .playing { display: flex; align-items: center; justify-content: space-between; gap: calc(16px * var(--u)); }
.slice-rookshade .labels { flex: 1; display: flex; flex-direction: column; gap: calc(4px * var(--u)); }
.slice-rookshade .labels p {
    font-size: calc(var(--fs-md) * var(--u)); line-height: calc(20px * var(--u)); font-weight: var(--font-sans-semibold-weight);
}
.slice-rookshade .how-to-play {
    flex-shrink: 0; min-height: calc(44px * var(--u)); padding: calc(4px * var(--u)) calc(24px * var(--u));
    border: 0; border-radius: var(--radius-pill); background: var(--surface-muted); color: var(--text);
    font: inherit; font-size: calc(var(--fs-md) * var(--u)); font-weight: var(--font-sans-semibold-weight); cursor: pointer;
}
.slice-rookshade .undo {
    flex-shrink: 0; display: flex; align-items: center; justify-content: center;
    width: calc(52px * var(--u)); height: calc(52px * var(--u)); padding: 0;
    border: 0; border-radius: var(--radius-pill); background: var(--primary); color: var(--on-primary); cursor: pointer;
}
.slice-rookshade .undo-icon { width: calc(24px * var(--u)); height: calc(24px * var(--u)); }
.slice-rookshade .how-to-play:focus-visible, .slice-rookshade .undo:focus-visible {
    outline: calc(3px * var(--u)) solid var(--text); outline-offset: calc(2px * var(--u));
}
.slice-rookshade .solved { font-size: calc(var(--fs-xl) * var(--u)); line-height: calc(var(--lh-xl) * var(--u)); font-weight: var(--font-sans-bold-weight); }
/* The app's neutral Callout. */
.slice-rookshade .callout {
    padding: calc(16px * var(--u));
    border: calc(1px * var(--u)) solid var(--separator); border-radius: calc(var(--radius-md) * var(--u));
    background: var(--surface-muted);
    font-size: calc(var(--fs-md) * var(--u)); line-height: calc(var(--lh-md) * var(--u)); font-weight: var(--font-sans-semibold-weight);
}
.slice-rookshade .status { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
/* Last in the block: it must beat the equally specific display rules above. */
.slice-rookshade [hidden] { display: none; }

/* Ghost frames (spec §3.3, §5.2): neutral greys from the active surface, softly blurred. */
.frame[data-kind="ghost"] .screen { background: color-mix(in srgb, var(--canvas) 80%, grey); }
.frame[data-kind="ghost"] .screen-body {
    padding: calc(64px * var(--frame-scale, 1)) calc(20px * var(--frame-scale, 1)) calc(28px * var(--frame-scale, 1));
    gap: calc(14px * var(--frame-scale, 1));
}
.ghost-block { border-radius: calc(12px * var(--frame-scale, 1)); background: color-mix(in srgb, var(--surface) 75%, grey); filter: blur(2px); }

/* Live apps' cover (drawings spec §3): the drawing over the running demo while the
   app is not current, and for a beat after it becomes current. Fades back fast,
   in slow; the status bar stays above it. */
.frame-cover {
    position: absolute; inset: 0; z-index: 1;
    display: flex; flex-direction: column;
    /* Clears the status bar, so the picture sits where a placeholder's does. */
    padding-top: calc(40px * var(--frame-scale, 1));
    background: var(--canvas);
    transition: opacity 75ms ease;
}
.frame-cover[data-phase="live"] { opacity: 0; pointer-events: none; transition-duration: 150ms; }
.frame-cover[data-instant] { transition: none; }
.frame-cover.pattern { --pattern-scale: var(--frame-scale, 1); }
.screen > .status-bar { position: relative; z-index: 2; transition: background-color 75ms ease; }
/* Baby Sleep Tracker's header band belongs to the demo, not to its drawing. */
.screen[data-app="baby-sleep-tracker"]:has(> .frame-cover[data-phase="drawn"]) .status-bar { background: transparent; }

/* Placeholder screens (spec §4.3): an app in development shows its drawing and name. */
.slice-placeholder {
    --u: var(--frame-scale, 1);
    flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: calc(12px * var(--u)); padding: 0 calc(24px * var(--u)) calc(48px * var(--u)); text-align: center;
}
.slice-placeholder .scene { width: calc(210px * var(--u)); height: auto; color: var(--primary); }
.slice-placeholder h2 { margin: 0; font-size: calc(var(--fs-xl) * var(--u)); line-height: calc(var(--lh-xl) * var(--u)); font-weight: var(--font-sans-bold-weight); }
.slice-placeholder p { margin: 0; color: var(--text-muted); font-size: calc(var(--fs-sm) * var(--u)); line-height: calc(var(--lh-sm) * var(--u)); }

/* App block (spec §3.4). */
.app-block { width: 100%; max-width: calc(720px + 32px); padding: 0 16px; }
/* One element per app; app-block.ts fades the leaving one out and the entering one in. */
.app-block-body { display: flex; flex-direction: column; align-items: center; gap: 36px; }
.app-block h2:focus { outline: none; }
.app-block h2:focus-visible { outline: 3px solid var(--primary); outline-offset: 4px; }
/* Features (spec §3.4): an icon, then a run-in head and its sentence. Two
   columns where there is room; the type carries it, so no cards or rules. */
.features {
    align-self: stretch; list-style: none; margin: 0; padding: 0;
    display: grid; grid-template-columns: 1fr; gap: 24px 40px;
}
@media (min-width: 720px) {
    .features { grid-template-columns: 1fr 1fr; }
}
.features li { display: flex; align-items: flex-start; gap: 14px; }
/* A lone feature sits centred under the frame rather than in the left column. */
.features li:only-child { grid-column: 1 / -1; justify-self: center; max-width: calc((100% - 40px) / 2); }
@media (max-width: 719px) {
    .features li:only-child { max-width: none; }
}
.feature-icon {
    flex: 0 0 auto; width: 22px; height: 22px; color: var(--primary);
    /* Centres the 22 px icon on the paragraph's first line. */
    margin-top: calc((var(--lh-md) - 22px) / 2);
}
.features p { margin: 0; color: var(--text-muted); text-wrap: pretty; }
.features strong { color: var(--text); font-weight: var(--font-sans-semibold-weight); }
.in-development {
    margin: 0; padding: 10px 20px; border: 1.5px dashed var(--border); border-radius: var(--radius-pill);
    color: var(--text-muted); font-weight: var(--font-sans-medium-weight);
}
/* Store links (spec §3.4): the store's logo and name, nothing around them. */
.store { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px 32px; }
.badge {
    display: inline-flex; align-items: center; gap: 10px;
    min-height: 44px; padding: 0 4px;
    border: 0; border-bottom: 2px solid transparent; background: none; color: var(--text);
    font: inherit; font-size: var(--fs-lg); font-weight: var(--font-sans-semibold-weight); text-decoration: none;
    cursor: pointer;
}
.badge-logo { width: 24px; height: 24px; flex: 0 0 auto; }
/* The solid Play triangle fills its whole box and reads larger and higher than the Apple glyph beside
   it; scaled about its centre it matches optically, in the badges and the title icons alike. */
.store-logo-googlePlay { transform: scale(0.86); }
.store-icon .store-logo-googlePlay { transform-origin: 50% 100%; }
a.badge:hover, a.badge:focus-visible { border-bottom-color: var(--primary); }
.badge:focus-visible { outline: 3px solid var(--primary); outline-offset: 4px; }
.app-block nav { display: flex; gap: 24px; font-size: var(--fs-sm); }
.app-block nav a, .credit a { color: var(--text); opacity: 0.7; text-decoration: none; border-bottom: 1px solid transparent; }
.app-block nav a:hover, .app-block nav a:focus-visible, .credit a:hover, .credit a:focus-visible { opacity: 1; border-bottom-color: var(--primary); }
.credit { margin: 0; font-size: var(--fs-xs); line-height: var(--lh-xs); color: var(--text-muted); text-align: center; }

/* Reduced motion (spec §7): states apply without animation. */
@media (prefers-reduced-motion: reduce) {
    .frame, .phone::after, .brand-mark, .backdrop-layer, .frame-cover, .screen > .status-bar { transition: none; }
}
