/* The Kinetic site's stylesheet (kinetic.wildflowerjs.com).

   Two parts. The header is the main site's header, so its rules are
   main.css's header rules plus the Bootstrap 5.3 navbar rules they sit on,
   with the main site's own header colours; this site loads no Bootstrap.
   Everything under the header is Kinetic's: the colours come from a
   palette of five (steel blue #4280A2, sky #90CDEF, amber #EFC187,
   lavender #B1A8FF and coral #EF9481), deepened where the light theme
   needs text to read, and
   the type is Work Sans, the main site's self-hosted face, set heavy for
   headings as the showreel sets its titles.

   Dark is the default theme. html[data-theme] is set by the inline script in
   partials/head.html before the first paint, and by the theme toggle. */

/* ------------------------------------------------------------------------
   Tokens
   ------------------------------------------------------------------------ */

:root,
:root[data-theme="dark"] {
    color-scheme: dark;
    --bg: #14161f;
    --surface: #1b1e29;
    --line: #2b2f3d;
    --text: #ece8df;           /* the showreel's paper, a step down */
    --muted: #a3a7ba;
    --accent: #B1A8FF;         /* lavender: links and current items, 8.5:1 on --bg */
    --accent-fill: #B1A8FF;    /* lavender as a fill, with --on-accent text */
    --on-accent: #14161f;      /* text on --accent-fill, 8.5:1 */
    --cue: #EFC187;            /* pale amber: the stage's current moment, nowhere else */
    --stage: #0b0f1a;          /* the tutorial composition's background */
    --code-bg: #0f111a;
    --code-text: #e3dfd6;
    --note-fill: #417D9F;      /* a note or a tip: steel blue, white text at 4.5:1 */
    --warn-fill: #AA6354;      /* a warning: terracotta, white text at 4.5:1 */

    /* The header keeps the main site's dark theme (main.css .theme-dark). */
    --hdr-bg: #1a1a1a;
    --hdr-text: #f0f0f0;
    --hdr-border: #3a3a3a;
    --hdr-accent: #6b996a;
}

:root[data-theme="light"] {
    color-scheme: light;
    --bg: #f4f4f7;
    --surface: #ffffff;
    --line: #d9d9e2;
    --text: #18171d;
    --muted: #595766;
    --accent: #6351FF;         /* the lavender deepened to 4.6:1 on --bg */
    --accent-fill: #6351FF;
    --on-accent: #ffffff;
    --cue: #9F6215;            /* the amber deepened to 4.5:1 on --bg */
    --stage: #0b0f1a;
    --code-bg: #ebebf1;
    --code-text: #24232b;
    --note-fill: #417D9F;
    --warn-fill: #AA6354;

    /* main.css .theme-light, and its white header */
    --hdr-bg: #ffffff;
    --hdr-text: #333333;
    --hdr-border: #e0e0e0;
    --hdr-accent: #6b996a;
}

:root {
    --font-body: -apple-system, "Work Sans", BlinkMacSystemFont, "San Francisco", "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    --font-display: "Work Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
    --font-mono: ui-monospace, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
    --gutter: 24px;
}

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

html { scrollbar-gutter: stable; }

*, *::before, *::after { box-sizing: border-box; }

/* The main site's body font, line for line (www/css/main.css): the system
   font first, with self-hosted Work Sans behind it. */
body {
    margin: 0;
    background: var(--bg);
    color: var(--text);
    font-family: -apple-system, "Work Sans", BlinkMacSystemFont, "San Francisco", "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    font-optical-sizing: auto;
    font-style: normal;
    font-size: .85rem;
    font-weight: 400;
    /* font-variation-settings: "wdth" 100; */
    line-height: 1.6;
}

img, svg, iframe { display: block; }

a { color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 0.18em; }
a:hover { text-decoration-thickness: 2px; }

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

h1, h2, h3 {
    font-family: var(--font-display);
    line-height: 1.15;
    letter-spacing: 0.002em;
    text-wrap: balance;
}
h1 { font-size: clamp(2.25rem, 5vw, 3.25rem); font-weight: 800; margin: 0 0 0.4em; }
h2 { font-size: 1.6rem; font-weight: 750; margin: 2.2em 0 0.55em; }
h3 { font-size: 1.15rem; font-weight: 700; margin: 1.8em 0 0.4em; }
/* The Overview's Why Kinetic points: each a heading on its own line. */
h3.why-point { font-size: 1.4rem; margin: 1.6em 0 0.35em; }
p, ul, ol { margin: 0 0 1em; }
p { font-size: 1rem; }
li { margin-bottom: 0.35em; }
/* The docs' lists read at the paragraph size; a list inside a table keeps the
   table's. The sidebar and the page's table of contents set their own. */
.docs-content li { font-size: 1rem; }
.docs-content .table li { font-size: inherit; }
li > strong:first-child { color: var(--text); }

.lead { font-size: 1.2rem; line-height: 1.55; }
@media (max-width: 600px) { .lead { font-size: 1.08rem; } }

code {
    font-family: var(--font-mono);
    font-size: 0.88em;
}
:not(pre) > code {
    padding: 0.08em 0.32em;
    border-radius: 4px;
    background: var(--surface);
    border: 1px solid var(--line);
    white-space: nowrap;
}
pre {
    margin: 0 0 1.2em;
    padding: 14px 16px;
    overflow-x: auto;
    background: var(--code-bg);
    color: var(--code-text);
    border: 1px solid var(--line);
    border-radius: 6px;
    font-size: 0.82rem;
    line-height: 1.6;
    tab-size: 4;
}
pre code { font-size: inherit; }

/* Prism's token colours. The box around a sample is the site's own, above;
   Prism's theme stylesheets are not loaded. The dark palette is the main
   site's material-dark theme, the light one Prism's default theme, so a
   sample reads the same on both sites. */
.token.comment, .token.prolog, .token.doctype { color: #616161; }
.token.punctuation, .token.operator { color: #89ddff; }
.token.keyword, .token.atrule, .token.boolean, .token.constant, .token.function, .token.symbol, .token.id, .token.important { color: #c792ea; }
.token.attr-name, .token.builtin, .token.class { color: #ffcb6b; }
.token.string, .token.attr-value, .token.attribute, .token.pseudo-class, .token.pseudo-element { color: #a5e844; }
.token.property, .token.cdata, .token.char, .token.inserted { color: #80cbc4; }
.token.class-name, .token.hexcode, .token.regex { color: #f2ff00; }
.token.tag, .token.selector, .token.deleted, .token.entity, .token.url, .token.variable { color: #ff6666; }
.token.number, .token.unit { color: #fd9170; }
.token.id, .token.important, .token.bold { font-weight: bold; }
.token.italic { font-style: italic; }
.token.namespace { opacity: 0.7; }

:root[data-theme="light"] .token.comment, :root[data-theme="light"] .token.prolog, :root[data-theme="light"] .token.doctype, :root[data-theme="light"] .token.cdata { color: #708090; }
:root[data-theme="light"] .token.punctuation { color: #999; }
:root[data-theme="light"] .token.tag, :root[data-theme="light"] .token.property, :root[data-theme="light"] .token.boolean, :root[data-theme="light"] .token.number, :root[data-theme="light"] .token.constant, :root[data-theme="light"] .token.symbol, :root[data-theme="light"] .token.deleted { color: #905; }
:root[data-theme="light"] .token.string, :root[data-theme="light"] .token.attr-name, :root[data-theme="light"] .token.selector, :root[data-theme="light"] .token.builtin, :root[data-theme="light"] .token.char, :root[data-theme="light"] .token.inserted { color: #690; }
:root[data-theme="light"] .token.operator, :root[data-theme="light"] .token.entity, :root[data-theme="light"] .token.url { color: #9a6e3a; }
:root[data-theme="light"] .token.keyword, :root[data-theme="light"] .token.atrule, :root[data-theme="light"] .token.attr-value { color: #07a; }
:root[data-theme="light"] .token.function, :root[data-theme="light"] .token.class-name { color: #dd4a68; }
:root[data-theme="light"] .token.regex, :root[data-theme="light"] .token.important, :root[data-theme="light"] .token.variable { color: #e90; }
:root[data-theme="light"] .token.id, :root[data-theme="light"] .token.class, :root[data-theme="light"] .token.attribute, :root[data-theme="light"] .token.pseudo-class, :root[data-theme="light"] .token.pseudo-element, :root[data-theme="light"] .token.hexcode, :root[data-theme="light"] .token.unit { color: inherit; }

/* Tables and alerts, as the reference pages write them (the main site's
   Bootstrap class names, styled here since this site loads no Bootstrap). */
.table-responsive { overflow-x: auto; margin: 0 0 1.2em; }
.table {
    width: 100%;
    margin: 0;
    border-collapse: collapse;
    font-size: 0.92rem;
    line-height: 1.5;
}
.table th, .table td {
    padding: 8px 12px;
    border-bottom: 1px solid var(--line);
    text-align: left;
    vertical-align: top;
}
.table th { color: var(--muted); font-size: 0.8rem; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; }
.table-striped tbody tr:nth-child(odd) { background: color-mix(in srgb, var(--surface) 60%, transparent); }
.table ul, .table ol { padding-left: 1.1em; }
.mb-0 { margin-bottom: 0; }
/* Breakouts: solid fills with rounded corners, as the main site's alerts.
   A note or a tip is teal, a warning amber, white text on both in either
   theme. Links and inline code take the box's white, the code on a dark wash,
   since the page's chip colours fight a saturated fill. */
.alert {
    margin: 0 0 1.2em;
    padding: 14px 18px;
    border-radius: 8px;
    background: var(--note-fill);
    color: #fff;
}
.alert-warning { background-color: var(--warn-fill); }
.alert a { color: #fff; font-weight: 600; text-decoration: underline; }
.alert code { background: rgba(0, 0, 0, 0.24); color: #fff; border: 0; }
/* A warning carries the main site's attention icon and a tip its bulb, painted
   as a background so the box's loose text and inline markup keep their flow;
   the text indents past it, and the minimum height keeps a one-line box from
   clipping it. A plain .alert (the note) has no icon. */
.alert-warning, .alert-tip {
    padding-left: 68px;
    min-height: 80px;
    background-repeat: no-repeat;
    background-position: 10px 16px;
    background-size: 48px 48px;
}
.alert-warning { background-image: url("/assets/icons/attention.svg"); }
.alert-tip { background-image: url("/assets/icons/tip.svg"); }
.alert p:last-child, .alert ul:last-child, .alert ol:last-child { margin-bottom: 0; }

/* An interactive on a docs page: a small Kinetic page of its own in a frame
   the width of the text (scripts/build-kinetic-site.cjs, interactiveMarkup). */
figure.interactive { margin: 0 0 1.4em; }
figure.interactive iframe {
    display: block;
    width: 100%;
    border: 3px solid var(--line);
    border-radius: 10px;
    background: var(--surface);
}
figure.interactive figcaption { margin-top: 8px; font-size: 0.85rem; color: var(--muted); }
/* The prompted examples (pages/prompted.html): each fits its 16:9 stage,
   a lesson's controls included, to the frame. */
/* The ratio is the inside's, so the stage fits it exactly: on the border box,
   the 3 px border would leave the inside wider than 16:9, and each piece
   would overflow it or leave a strip at its sides. */
.prompted-frame iframe { box-sizing: content-box; width: calc(100% - 6px); aspect-ratio: 16 / 9; color-scheme: normal; }
.prompted-who { margin: 12px 0 0; }

.skip-link {
    position: absolute;
    left: 8px;
    top: -48px;
    z-index: 2000;
    padding: 8px 12px;
    background: var(--surface);
    color: var(--text);
    border-radius: 4px;
}
.skip-link:focus { top: 8px; }

.button {
    display: inline-block;
    padding: 10px 18px;
    border-radius: 6px;
    background: var(--accent-fill);
    color: var(--on-accent);
    font-weight: 600;
    text-decoration: none;
}
.button:hover { background: color-mix(in srgb, var(--accent-fill) 85%, #fff); }

/* ------------------------------------------------------------------------
   Header: the main site's header, with Kinetic's links
   ------------------------------------------------------------------------ */

.site-header {
    position: sticky;
    top: 0;
    z-index: 1020;
}

.navbar {
    position: relative;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    padding: 0.2rem 0;
    background-color: var(--hdr-bg);
    border-bottom: 1px solid var(--hdr-border);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
    color: var(--hdr-text);
    font-family: -apple-system, "Work Sans", BlinkMacSystemFont, "San Francisco", "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    font-size: 0.85rem;
    line-height: 1.6;
}
.navbar > .container-fluid {
    display: flex;
    flex-wrap: inherit;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    padding: 0 0.75rem;
}
.d-flex { display: flex; }
.align-items-center { align-items: center; }
.me-auto { margin-right: auto; }
.me-2 { margin-right: 0.5rem; }
.ms-3 { margin-left: 1rem; }

.navbar-brand {
    padding: 0.3125rem 0;
    margin-right: 1rem;
    font-family: "Work Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
    font-size: 1.25rem;
    color: #6b996a;
    text-decoration: none;
    white-space: nowrap;
}
.navbar-brand img { opacity: 0.9; }
.brand-wf { font-weight: 520; }
.brand-js { font-weight: 700; }

.navbar-nav {
    display: flex;
    flex-direction: column;
    margin: 0;
    padding-left: 0;
    list-style: none;
}
.navbar-nav .nav-item { margin: 0; }
.nav-link {
    display: block;
    padding: 0.5rem 0;
    color: var(--hdr-text);
    text-decoration: none;
    white-space: nowrap;
}
.nav-link .bi {
    display: inline-block;
    width: 1em;
    height: 1em;
    vertical-align: -0.125em;
}

.navbar-collapse {
    flex-basis: 100%;
    flex-grow: 1;
    align-items: center;
}

.navbar-toggler {
    padding: 0.25rem 0.75rem;
    font-size: 1.25rem;
    line-height: 1;
    color: var(--hdr-text);
    background: transparent;
    border: 1px solid rgba(128, 128, 128, 0.25);
    border-radius: 0.375rem;
    cursor: pointer;
}
.navbar-toggler-icon {
    display: inline-block;
    width: 1.5em;
    height: 1.5em;
    vertical-align: middle;
    background: center / 100% no-repeat url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%2833, 37, 41, 0.75%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");
}
:root[data-theme="dark"] .navbar-toggler-icon { filter: invert(1) brightness(0.7); }

/* The search box, as the main site's: the field with the icon and the "/"
   hint, and a fixed dropdown of results that the component positions. */
.search-container { position: relative; margin-left: auto; }
.search-input-wrapper { position: relative; display: flex; align-items: center; }
.search-icon {
    position: absolute;
    left: 10px;
    width: 0.85em;
    height: 0.85em;
    color: var(--muted);
    pointer-events: none;
}
.search-input {
    width: 220px;
    padding: 5px 34px 5px 30px;
    border: 1px solid var(--hdr-border);
    border-radius: 8px;
    background: var(--surface);
    color: var(--text);
    font: inherit;
    font-size: 0.85rem;
}
.search-input:focus { border-color: var(--accent-fill); outline: 2px solid color-mix(in srgb, var(--accent-fill) 35%, transparent); outline-offset: 0; }
.search-input::placeholder { color: var(--muted); }
.search-input::-webkit-search-cancel-button { display: none; }
.search-shortcut {
    position: absolute;
    right: 8px;
    padding: 1px 6px;
    border: 1px solid var(--hdr-border);
    border-radius: 4px;
    color: var(--muted);
    font-family: var(--font-mono);
    font-size: 0.7rem;
}
.search-container:focus-within .search-shortcut { display: none; }
.search-dropdown {
    position: fixed;
    z-index: 2000;
    min-width: 300px;
    max-height: 420px;
    overflow-y: auto;
    padding: 4px;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--surface);
    box-shadow: 0 8px 28px rgba(0, 0, 0, 0.4);
    font-family: var(--font-body);
    font-size: 1rem;
    line-height: 1.5;
}
.search-dropdown[data-cloak] { display: none; }
.search-result {
    display: block;
    padding: 8px 12px;
    border-radius: 6px;
    color: var(--text);
    text-decoration: none;
}
.search-result:hover, .search-result.selected { background: color-mix(in srgb, var(--text) 8%, transparent); }
.search-result-title { display: block; font-weight: 600; font-size: 0.9rem; }
.search-result-section { display: block; color: var(--accent); font-size: 0.7rem; letter-spacing: 0.06em; text-transform: uppercase; }
.search-result-excerpt {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    color: var(--muted);
    font-size: 0.8rem;
    line-height: 1.4;
}
.search-empty { margin: 0; padding: 12px; color: var(--muted); font-size: 0.85rem; text-align: center; }
@media (max-width: 1250px) { .search-input { width: 170px; } }
@media (max-width: 1100px) { .search-input { width: 130px; padding-right: 10px; } .search-shortcut { display: none; } }
@media (max-width: 991.98px) {
    .search-container { width: 100%; margin: 0.25rem 0 0.5rem; }
    .search-input { width: 100%; }
}

/* GitHub link, sized to sit level with the theme toggle */
.navbar-github-link {
    display: flex;
    align-items: center;
    color: var(--hdr-text);
    font-size: 1.35rem;
    line-height: 1;
    text-decoration: none;
}
.navbar-github-link:hover { color: var(--hdr-accent); }
.navbar-github-link .bi { width: 1em; height: 1em; }

[data-component="theme-toggle"] { display: flex; align-items: center; }
[data-component="theme-toggle"] .btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 32px;
    margin: 0;
    padding: 0;
    background: transparent;
    border: 0;
    border-radius: 0.25rem;
    color: inherit;
    font-size: 0.875rem;
    cursor: pointer;
}
.theme-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    line-height: 1;
    overflow: hidden;
}

@media (min-width: 992px) {
    .navbar-expand-lg { flex-wrap: nowrap; justify-content: flex-start; }
    .navbar-expand-lg .navbar-nav { flex-direction: row; }
    .navbar-expand-lg .navbar-nav .nav-link { padding-right: 0.5rem; padding-left: 0.5rem; }
    .navbar-expand-lg .navbar-collapse { display: flex !important; flex-basis: auto; }
    .navbar-expand-lg .navbar-toggler { display: none; }
}
@media (max-width: 1050px) {
    .navbar-github-link.ms-3,
    .navbar-collapse > .ms-3 { margin-left: 0.5rem; }
    .navbar-nav .nav-link { padding-left: 0.3rem; padding-right: 0.3rem; }
}
/* The flyout below 992 px, as main.css draws it: links stacked, then the
   GitHub icon and the theme toggle side by side. */
@media (max-width: 991.98px) {
    .navbar-collapse {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        max-height: 0;
        overflow: hidden;
        transition: max-height 0.3s ease;
    }
    .navbar-collapse.show { max-height: 500px; padding-bottom: 0.5rem; }
    .navbar-collapse .navbar-nav { width: 100%; }
    .navbar-collapse .navbar-github-link.ms-3 { margin-left: 0.25rem; }
    .navbar-collapse > [data-component="theme-toggle"].ms-3 { margin-left: 1rem; }
}

/* The KINETIC wordmark, beside the WildflowerJS brand and separated from it by
   a rule: outlined Work Sans 800, kerned, as an SVG path 0.68em tall (the
   caps' height) on the brand's baseline. White on the dark header; on the
   light header, which is white, it takes the header's text colour. */
.kinetic-brand {
    flex: none;
    display: flex;
    align-items: center;
    margin-right: 1rem;
    padding: 0.3125rem 0 0.3125rem 0.9rem;
    border-left: 1px solid var(--hdr-border);
    font-size: 1.25rem;
    line-height: 1.5;
    color: var(--hdr-text);
    text-decoration: none;
}
:root[data-theme="dark"] .kinetic-brand { color: #fff; }
.kinetic-brand svg {
    display: block;
    width: auto;
    height: .68em;
}
.nav-link[aria-current="page"] { color: var(--hdr-accent); font-weight: 600; }
.nav-link:hover { color: var(--hdr-accent); }
@media (max-width: 400px) {
    .navbar-brand > span { display: none; }   /* the logo alone leaves room for the wordmark */
    .navbar-brand { margin-right: 0.5rem; }
}

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

.site-footer {
    margin-top: 96px;
    padding: 32px var(--gutter) 24px;
    border-top: 1px solid var(--line);
    color: var(--muted);
    font-size: 0.9rem;
}
.footer-inner {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: 24px 64px;
    max-width: 1120px;
    margin: 0 auto;
}
.footer-about { max-width: 34em; }
.footer-name {
    margin-bottom: 0.4em;
    font-family: var(--font-display);
    font-size: 1.1rem;
    font-weight: 800;
    letter-spacing: 0.002em;
    color: var(--text);
}
.footer-links { list-style: none; padding: 0; }
.footer-legal { max-width: 1120px; margin: 24px auto 0; font-size: 0.8rem; }

/* ------------------------------------------------------------------------
   Plain pages: the stubs, the demos list
   ------------------------------------------------------------------------ */

.page {
    max-width: 46rem;
    margin: 0 auto;
    padding: 48px var(--gutter) 0;
}
.page .lead { color: var(--text); }
.page h2 { font-size: 1.3rem; }
.planned { padding-left: 1.2em; }
.planned li::marker { color: var(--muted); }
.meanwhile {
    padding: 12px 16px;
    border: 1px solid var(--line);
    border-radius: 6px;
    background: var(--surface);
}

/* The Demos page: a card per demo, as the framework's demos page has, with
   its name, one line, the parts it uses, and Demo and Code. */
.page-wide { max-width: 60rem; }
.demo-cards { margin: 32px 0 64px; }
.demo-card {
    display: flex;
    align-items: center;
    gap: 20px;
    margin: 0 0 12px;
    padding: 18px 22px;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: 8px;
}
.demo-card-body { flex: 1; min-width: 0; }
.demo-card h2 { margin: 0 0 4px; font-size: 1.05rem; font-weight: 600; }
.demo-card p { margin: 0 0 8px; color: var(--muted); font-size: 0.95rem; line-height: 1.45; }
.demo-features { display: flex; flex-wrap: wrap; gap: 5px; }
.demo-features span {
    padding: 2px 8px;
    border-radius: 4px;
    background: color-mix(in srgb, var(--accent) 14%, transparent);
    color: var(--accent);
    font-size: 0.75rem;
    font-weight: 500;
}
.demo-actions { display: flex; gap: 6px; flex-shrink: 0; }
.demo-actions .button { padding: 6px 14px; font-size: 0.9rem; }
.button-quiet { background: color-mix(in srgb, var(--text) 9%, transparent); color: var(--text); }
.button-quiet:hover { background: color-mix(in srgb, var(--text) 16%, transparent); }
@media (max-width: 600px) {
    .demo-card { flex-direction: column; align-items: stretch; gap: 12px; }
}

/* A demo's code, at /demos/<name>/source/. */
.source-page { max-width: 72rem; padding-bottom: 64px; }
.source-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.source-files { display: flex; flex-wrap: wrap; gap: 6px 16px; margin: 24px 0 8px; }
.source-page h2 { margin: 32px 0 10px; font-size: 1.05rem; }
.source-page h2 code { white-space: normal; }

/* ------------------------------------------------------------------------
   The landing
   ------------------------------------------------------------------------ */

/* The landing follows the framework's homepage: a centred title, three
   cards and a full-row showcase in a 1200 px grid with 32 px gaps, the two
   buttons, then feature sections that alternate text with a square demo or
   a code block. */
.home-hero {
    max-width: 1200px;
    margin: 64px auto 0;
    padding: 0 var(--gutter);
    text-align: center;
}
.home-title { margin: 0; display: flex; flex-direction: column; align-items: center; gap: 6px; }
.home-brand {
    font-family: var(--font-display);
    font-size: clamp(4rem, 11vw, 7.5rem);
    font-weight: 900;
    line-height: 0.9;
    letter-spacing: -0.05em;
}
/* The hero's KINETIC is the navbar's wordmark, its outlines and kerning, at
   the size the title's capitals had. */
.home-brand svg { display: block; height: clamp(2.9rem, 8vw, 5.4rem); width: auto; }
.home-tagline {
    margin-top: 18px;
    font-family: var(--font-display);
    font-size: clamp(1.6rem, 4vw, 2.6rem);
    font-weight: 800;
    letter-spacing: 0.002em;
    color: var(--accent);
}
.home-lead { max-width: 40em; margin: 20px auto 40px; color: var(--muted); }
.home-cards {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 32px;
    text-align: left;
}
.home-card {
    min-width: 0;
    padding: 24px;
    border-radius: 12px;
    background: var(--surface);
    border: 1px solid var(--line);
}
.home-card h3 { margin-top: 0; font-size: 1.3rem; }
.home-card p { margin: 0 0 0.8em; }
.home-card-coda { margin-top: 1rem !important; font-weight: 700; color: var(--text); }
.home-showcase { grid-column: 1 / -1; padding: 16px; }
/* 16:9, the showcase composition's own frame, at every width. */
.home-showcase-frame {
    display: block;
    width: 100%;
    aspect-ratio: 16 / 9;
    border: 0;
    border-radius: 8px;
    background: var(--stage);
    color-scheme: normal;
}
/* The proof under the hero: four pieces made from a prompt, two to a row,
   each live in its 16:9 frame over the start of its prompt. */
.home-prompted {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 32px;
    text-align: left;
}
.home-prompted figure { margin: 0; }
.home-prompted iframe {
    display: block;
    width: 100%;
    aspect-ratio: 16 / 9;
    border: 0;
    border-radius: 8px;
    background: var(--stage);
    color-scheme: normal;
}
.home-prompted figcaption { margin-top: 10px; font-size: 0.95rem; color: var(--muted); }
.home-prompted-note { max-width: 40em; margin: 32px auto 0; color: var(--muted); }
/* Why Kinetic: the three cards and the showcase, after the proof. */
.home-why { max-width: 1200px; margin: 96px auto 0; padding: 0 var(--gutter); text-align: center; }
.home-cta { display: flex; flex-wrap: wrap; justify-content: center; gap: 16px; margin: 40px 0 0; }
.button-lg { padding: 12px 28px; font-size: 1.1rem; }
.button-alt { background: #417D9F; color: #fff; }
.button-alt:hover { background: color-mix(in srgb, #417D9F 85%, #fff); }

.home-features { max-width: 1200px; margin: 96px auto 0; padding: 0 var(--gutter); }
.home-feature {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 48px;
    align-items: center;
    padding: 56px 0;
    border-top: 1px solid var(--line);
}
.home-feature-alt .home-feature-text { order: 2; }
.home-feature h2 { margin-top: 0; font-size: 2rem; }
.home-feature-text p:last-child { margin-bottom: 0; }
.home-feature-demo iframe {
    display: block;
    width: 100%;
    max-width: 520px;
    aspect-ratio: 1 / 1;
    margin: 0 auto;
    border: 0;
    border-radius: 12px;
    background: var(--stage);
    color-scheme: normal;
}
.home-feature-code pre { margin: 0; }

@media (max-width: 860px) {
    .home-cards, .home-feature, .home-prompted { grid-template-columns: minmax(0, 1fr); }
    .home-feature-alt .home-feature-text { order: 0; }
}

/* ------------------------------------------------------------------------
   Documentation: the sidebar, the page, previous and next, the TOC column
   ------------------------------------------------------------------------ */

/* Three columns from 1200 px: the sidebar, the page and the TOC column. A
   wide page (body.docs-wide, one that places its own TOC) has no TOC column.
   Between 992 and 1199 px the TOC column goes; below 992 px the sidebar is a
   drawer opened by the button above the page. */
.docs {
    display: grid;
    /* The sidebar and the TOC column grow with the window, as the main
       site's sidebar does (two of its twelve columns), so a wide screen gives
       the page names room to sit on one line: 250 px up to 1470 px wide, 17%
       of the window above that, 340 px at most. */
    grid-template-columns: clamp(250px, 17vw, 340px) minmax(0, 1fr) clamp(240px, 13vw, 300px);
    min-height: calc(100svh - var(--header-h, 60px));
}
.docs-wide .docs { grid-template-columns: clamp(250px, 17vw, 340px) minmax(0, 1fr); }
/* The footer follows the grid at full width and meets it: its usual top
   margin would show as a blank band under the sidebar and the page. */
.docs + .site-footer { margin-top: 0; }
.docs-sidebar {
    position: sticky;
    top: var(--header-h, 60px);
    align-self: start;
    height: calc(100svh - var(--header-h, 60px));
    overflow-y: auto;
    padding: 20px 0 48px;
    background: var(--surface);
    border-right: 1px solid var(--line);
    scrollbar-width: thin;
}
.docs-nav-group {
    margin: 18px 0 4px;
    padding: 0 20px;
    color: var(--muted);
    font-family: var(--font-display);
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}
.docs-nav-group:first-child { margin-top: 0; }
.docs-nav ul { margin: 0; padding: 0; list-style: none; }
.docs-nav li { margin: 0; }
.docs-nav a {
    display: block;
    padding: 5px 20px 5px 28px;
    border-left: 3px solid transparent;
    color: var(--text);
    font-size: 0.9rem;
    line-height: 1.35;
    text-decoration: none;
}
.docs-nav a:hover { background: color-mix(in srgb, var(--text) 6%, transparent); }
.docs-nav a[aria-current="page"] {
    color: #90CDEF;
    font-weight: 600;
    border-radius: 5px;
    margin: 0;
    background: #4280A2;
}
.docs-main { min-width: 0; padding: 40px 48px 64px; }
/* The page takes its column's width, as the main site's does, so a wide
   screen gives it more room. The interactives and the live examples keep
   the width they were made at: their stages have fixed heights, and a wider
   frame would only add empty width beside them. */
.docs-content figure.interactive, .docs-content .example { max-width: 50rem; }
/* A heading reached by its hash stops under the sticky header, not behind it. */
.docs-content [id] { scroll-margin-top: calc(var(--header-h, 60px) + 20px); }
.docs-content > h1:first-child { margin-top: 0; }
/* A placeholder page still wrapped in .page (the stubs) loses its own frame. */
.docs-content .page { max-width: none; margin: 0; padding: 0; }
.docs-toc {
    position: sticky;
    top: var(--header-h, 60px);
    display: flex;
    flex-direction: column;
    align-self: start;
    height: calc(100svh - var(--header-h, 60px));
    padding: 40px 20px 24px 0;
}
.docs-toc .page-toc { flex: 1 1 auto; min-height: 0; overflow-y: auto; scrollbar-width: thin; }
.docs-toc-utils {
    margin-top: auto;
    padding-top: 12px;
    border-top: 1px solid var(--line);
}
.docs-toc-utils a {
    display: block;
    padding: 3px 0 3px 12px;
    color: var(--muted);
    font-size: 0.8rem;
    text-decoration: none;
}
.docs-toc-utils a:hover { color: var(--accent); }

/* The table of contents: a link per h2 and h3, the one in view marked. On a
   wide page it sits where the page put it, under First video's stage. */
.page-toc-title {
    margin: 0 0 6px;
    padding-left: 12px;
    color: var(--muted);
    font-family: var(--font-display);
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}
.page-toc ul { margin: 0; padding: 0; list-style: none; }
.page-toc li { margin: 0; }
.page-toc a {
    display: block;
    padding: 3px 0 3px 10px;
    border-left: 2px solid transparent;
    color: var(--muted);
    font-size: 0.85rem;
    line-height: 1.35;
    text-decoration: none;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.page-toc .toc-h2 a { font-weight: 600; color: var(--text); }
.page-toc .toc-h2 + .toc-h2 a, .page-toc .toc-h3 + .toc-h2 a { margin-top: 4px; }
.page-toc .toc-h3 a { padding-left: 22px; }
.page-toc a:hover { color: var(--accent); }
.page-toc a[aria-current="true"] { border-left-color: var(--accent-fill); color: var(--accent); }
.tutorial-stage .page-toc { margin-top: 20px; padding-top: 16px; border-top: 1px solid var(--line); }

.docs-prev-next {
    display: flex;
    justify-content: space-between;
    gap: 16px;
    margin-top: 56px;
    padding-top: 20px;
    border-top: 1px solid var(--line);
}
.docs-prev-next a {
    display: flex;
    flex-direction: column;
    max-width: 48%;
    color: var(--text);
    font-family: var(--font-display);
    font-weight: 700;
    letter-spacing: 0.002em;
    text-decoration: none;
}
.docs-prev-next a:hover { color: var(--accent); }
.docs-prev-next a span { color: var(--muted); font-family: var(--font-body); font-size: 0.8rem; font-weight: 400; }
.docs-prev-next .docs-next { margin-left: auto; text-align: right; }

/* The drawer and its button, below 992 px. */
.docs-menu-toggle { display: none; }
.docs-backdrop { display: none; }
@media (max-width: 1199.98px) {
    .docs, .docs-wide .docs { grid-template-columns: 230px minmax(0, 1fr); }
    .docs-toc { display: none; }
    .docs-main { padding: 32px 32px 56px; }
}
@media (max-width: 991.98px) {
    .docs, .docs-wide .docs { display: block; }
    .docs-menu-toggle {
        display: block;
        width: 100%;
        padding: 10px 16px;
        border: 0;
        border-bottom: 1px solid var(--line);
        background: var(--surface);
        color: var(--accent);
        font: inherit;
        font-weight: 600;
        text-align: left;
        cursor: pointer;
    }
    .docs-menu-toggle::before { content: "\2630\00a0\00a0"; color: var(--muted); }
    .docs-sidebar {
        position: fixed;
        top: 0;
        bottom: 0;
        left: 0;
        z-index: 1040;
        width: min(300px, 85vw);
        height: 100%;
        max-height: none;
        padding-top: 16px;
        border-right: 1px solid var(--line);
        box-shadow: 4px 0 24px rgba(0, 0, 0, 0.35);
        transform: translateX(-100%);
        transition: transform 0.2s ease;
        visibility: hidden;
    }
    .menu-open .docs-sidebar { transform: none; visibility: visible; }
    .docs-backdrop {
        position: fixed;
        inset: 0;
        z-index: 1030;
        background: rgba(0, 0, 0, 0.45);
    }
    .menu-open .docs-backdrop { display: block; }
    .docs-main { padding: 24px 16px 48px; }
}

/* ------------------------------------------------------------------------
   A live example on a docs page: the preview, then the three files
   ------------------------------------------------------------------------ */

.example {
    margin: 0 0 1.6em;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--surface);
    overflow: hidden;
}
/* The main site's stacked example: the code in tabs (HTML, JavaScript, CSS),
   then the preview at full width, with the title and Replay in its header.
   The build writes the markup from the fragment's figure (liveExampleMarkup
   in build-kinetic-site.cjs); site.js switches the tabs. */
.example .file-tabs {
    display: flex;
    border-bottom: 1px solid var(--line);
    background: var(--bg);
}
.example .tab-button {
    padding: 10px 14px;
    border: 0;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    background: transparent;
    color: var(--muted);
    font: inherit;
    font-size: 0.82rem;
    font-weight: 600;
    cursor: pointer;
}
.example .tab-button:hover { color: var(--text); }
.example .tab-button.active { color: var(--accent); border-bottom-color: var(--accent); }
.example .tab-button:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.example .tab-content { display: none; }
.example .tab-content.active { display: block; }
.example .preview-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 8px 14px;
    border-top: 1px solid var(--line);
    border-bottom: 1px solid var(--line);
    color: var(--muted);
    font-size: 0.85rem;
    font-weight: 600;
}
.example .preview-replay {
    padding: 4px 10px;
    border: 1px solid var(--line);
    border-radius: 4px;
    background: transparent;
    color: var(--muted);
    font: inherit;
    font-size: 0.78rem;
    cursor: pointer;
}
.example .preview-replay:hover { color: var(--text); border-color: var(--muted); }
/* Open in playground (site.js adds it), at the right with Replay after it. */
.example .playground-link { margin-left: auto; color: var(--accent); font-size: 0.78rem; text-decoration: none; }
.example .playground-link:hover { text-decoration: underline; }
.example .playground-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.example .preview-replay:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.example-frame {
    container-type: inline-size;
    background: var(--stage);
}
/* The runner's page fits its stage to the frame's width, with the preview
   bar under it; the runner sends the bar's height as --bar-h. */
.example-iframe {
    width: 100%;
    height: calc(100cqw * 9 / 16 + var(--bar-h, 44px));
    border: 0;
    background: var(--stage);
    color-scheme: normal;
}
@media (max-width: 560px) {
    .example-iframe { height: calc(100cqw * 9 / 16 + var(--bar-h, 92px)); }
}
.example pre {
    margin: 0;
    max-height: 24em;
    border: 0;
    border-radius: 0;
}
/* A sample the cap would cut by only a few lines shows in full (the build's EXAMPLE_FITS). */
.example .tab-content.fits pre { max-height: none; }
.example-status { padding: 6px 14px; color: #EF9481; font-family: var(--font-mono); font-size: 0.75rem; }
.example-status:empty { display: none; }

/* ------------------------------------------------------------------------
   A tutorial: the text scrolls, the stage stays
   ------------------------------------------------------------------------ */

/* Inside the documentation layout the tutorial fills the page column. */
.tutorial {
    display: grid;
    grid-template-columns: minmax(0, 36rem) minmax(0, 1fr);
    gap: 56px;
}
.tutorial-text { min-width: 0; padding: 0 0 45vh; }
.tutorial-text > h1 { margin-top: 0; }

/* A beat is the stretch of text that drives the stage. The beats are
   numbered, and the stage's caption carries the current one's number. The
   current one is outlined in the cue colour, and once
   the stage script runs (.is-live) the others dim, so the text that goes
   with the stage stands out. Without the script every beat reads at full
   strength. */
.tutorial-text { counter-reset: beat; }
.beat {
    position: relative;
    counter-increment: beat;
    padding: 0 16px 4px 20px;
    margin-left: -20px;
    border: 2px solid transparent;
    border-radius: 6px;
    transition: border-color 0.2s, background-color 0.2s, opacity 0.2s;
}
.beat.is-current {
    border-color: var(--cue);
    background: color-mix(in srgb, var(--cue) 6%, transparent);
}
.tutorial.is-live .beat:not(.is-current) { opacity: 0.55; }
.beat > h2:first-child { margin-top: 1.6em; padding-top: 0.6em; }
.beat > h2::before {
    content: counter(beat);
    display: inline-block;
    min-width: 1.6em;
    margin-right: 0.5em;
    border-radius: 999px;
    background: var(--line);
    color: var(--text);
    font-size: 0.75em;
    line-height: 1.6em;
    text-align: center;
    vertical-align: 0.12em;
}
.beat.is-current > h2::before { background: var(--cue); color: var(--bg); }

/* A line a beat adds or changes in code shown before it: tinted across the
   whole line, with a bar at its left edge that reads without the colour. */
pre mark.new {
    display: inline-block;
    min-width: calc(100% + 32px);
    margin: 0 -16px;
    padding: 0 16px;
    background: color-mix(in srgb, var(--cue) 14%, transparent);
    box-shadow: inset 3px 0 0 var(--cue);
    color: inherit;
}

/* A beat's detail, closed until the reader opens it. */
details.more {
    margin: 0 0 1.2em;
    border: 1px solid var(--line);
    border-radius: 6px;
    background: var(--surface);
}
details.more > summary {
    padding: 8px 14px;
    color: var(--accent);
    font-weight: 600;
    cursor: pointer;
}
details.more[open] > summary { border-bottom: 1px solid var(--line); }
details.more > :not(summary) { margin-left: 14px; margin-right: 14px; }
details.more > summary + * { margin-top: 12px; }
details.more > :last-child { margin-bottom: 12px; }

.tutorial-stage {
    position: sticky;
    top: var(--header-h, 104px);
    align-self: start;
    min-width: 0;
    padding-top: 48px;
}
.stage-frame {
    container-type: inline-size;
    background: var(--stage);
    border: 1px solid var(--line);
    border-radius: 6px;
    overflow: hidden;
    outline: 3px solid transparent;
    outline-offset: -3px;
}
/* When a new beat takes the stage, its frame flashes in the cue colour, also where
   the step page stays the same. An outline is painted over the iframe, so it
   shows on the one-column layout too, where the frame has no border. */
@keyframes stage-change {
    from { outline-color: var(--cue); }
    to { outline-color: transparent; }
}
.stage-frame.is-changing { animation: stage-change 0.9s ease-out; }
/* The step page fits its composition to the iframe's width, and the preview
   bar is fixed to the bottom of the iframe. site.js measures the bar and sets
   --bar-h, since the bar wraps to a second row on a narrow stage. */
.stage-frame iframe {
    width: 100%;
    height: calc(100cqw * 9 / 16 + var(--bar-h, 37px));
    border: 0;
    background: var(--stage);
}
/* A frame whose color-scheme differs from its document's gets an opaque
   white canvas in Chrome. The step pages and the showreel declare none, so
   the frames declare none either, and the frame's own background shows. */
.stage-frame iframe,
.reel-frame iframe { color-scheme: normal; }
.stage-caption {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 4px 16px;
    padding: 10px 2px 0;
    color: var(--muted);
    font-size: 0.9rem;
}
.stage-step {
    padding: 1px 9px;
    border-radius: 999px;
    background: var(--cue);
    color: var(--bg);
    font-size: 0.8rem;
    font-weight: 700;
}
.stage-step:empty { display: none; }
.stage-section { color: var(--text); font-weight: 600; }
.stage-time { font-family: var(--font-mono); font-size: 0.85rem; color: var(--cue); }
.stage-caption .stage-links { margin-left: auto; display: flex; gap: 16px; }
.stage-replay {
    padding: 0;
    border: 0;
    background: none;
    color: var(--accent);
    font: inherit;
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 0.18em;
    cursor: pointer;
}

/* One column below 1024 px: the stage on top, the text under it. The stage
   is what stays in view, so on a page with a tutorial the header scrolls
   away with the page there instead of sticking above the stage. */
@media (max-width: 1023.98px) {
    body:has(.tutorial) .site-header { position: static; }
    .tutorial { grid-template-columns: minmax(0, 1fr); gap: 0; padding: 0; }
    .tutorial-stage {
        order: -1;
        top: 0;
        z-index: 10;
        padding: 0;
        background: var(--bg);
        border-bottom: 1px solid var(--line);
    }
    .stage-frame { border: 0; border-radius: 0; }
    .tutorial-stage .page-toc { display: none; }   /* the stage block stays short */
    .stage-caption { padding: 6px 16px 8px; font-size: 0.8rem; }
    .stage-caption .stage-section { display: none; }   /* the section is the text just below */
    .stage-caption .stage-links { gap: 12px; }
    /* width: 100%, or the auto margins size the column to its widest code
       sample and the page scrolls sideways */
    .docs-wide .docs-main { padding: 0; }   /* the stage runs edge to edge */
    .tutorial-text { width: 100%; max-width: 40rem; margin: 0 auto; padding: 28px 16px 50vh 16px; }
    .docs-wide .docs-prev-next { margin: 0 16px; }
    .beat { padding-left: 14px; padding-right: 10px; margin-left: -16px; }
}

/* ------------------------------------------------------------------------
   Patterns: the gallery
   ------------------------------------------------------------------------ */

.gallery {
    max-width: 1180px;
    margin: 8px auto 0;
    padding: 0 var(--gutter);
}
.pattern-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 340px), 1fr));
    gap: 24px;
    margin: 0 0 32px;
    padding: 0;
    list-style: none;
}
.pattern-tile {
    display: flex;
    flex-direction: column;
    min-width: 0;
    margin: 0;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: 8px;
    overflow: hidden;
}
/* The preview is the runner's page in a frame on another origin. It takes no
   pointer, so the page scrolls over it. A waiting tile shows the empty stage. */
.tile-frame { background: var(--stage); border-bottom: 1px solid var(--line); }
.tile-frame iframe {
    width: 100%;
    aspect-ratio: 16 / 9;
    border: 0;
    background: var(--stage);
    pointer-events: none;
    color-scheme: normal;
}
.tile-body {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-width: 0;
    padding: 14px 16px 16px;
}
.tile-body h2 { margin: 0 0 6px; font-size: 1.2rem; }
.tile-summary { color: var(--muted); font-size: 0.95rem; }
.tile-open { margin: 0 0 14px; font-weight: 600; }
/* The code sits at the foot of the tile, so the tiles in a row line up. */
.tile-file { margin: auto 0 4px; color: var(--muted); font-family: var(--font-mono); font-size: 0.75rem; }
.tile-code { margin: 0; max-height: 16em; overflow: auto; font-size: 0.75rem; }

/* A pattern's tile at the top of its page, as wide as the live examples. */
.docs-content .pattern-grid-one { grid-template-columns: minmax(0, 1fr); max-width: 50rem; margin: 24px 0 32px; }
.tile-title { margin: 0 0 4px; font-weight: 700; }

/* ------------------------------------------------------------------------
   Patterns: the landing's filter and cards, and a pattern page's related
   links, after the main site's (www/css/patterns.css), in this site's colors
   ------------------------------------------------------------------------ */

.patterns-landing [data-cloak] { display: none; }
.pattern-filter-bar { margin: 1.25rem 0 1.25rem; }
.pattern-search-wrap { position: relative; max-width: 420px; margin-bottom: 0.85rem; }
.pattern-search-wrap input {
    width: 100%;
    padding: 0.5rem 2.25rem 0.5rem 0.75rem;
    border: 1px solid var(--line);
    border-radius: 6px;
    background: var(--bg);
    color: var(--text);
    font: inherit;
    font-size: 0.95rem;
}
.pattern-search-wrap input:focus { outline: none; border-color: var(--accent); }
/* The browser's own clear button goes, so the custom one is the only one. */
.pattern-search-wrap input[type="search"]::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; }
.pattern-search-clear {
    position: absolute;
    top: 50%;
    right: 0.4rem;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 1.6rem;
    height: 1.6rem;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: transparent;
    color: var(--muted);
    font-size: 1.25rem;
    line-height: 1;
    cursor: pointer;
    transform: translateY(-50%);
}
.pattern-search-clear:hover, .pattern-search-clear:focus-visible { background: var(--surface); color: var(--text); outline: none; }
.pattern-cat-buttons { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.pattern-cat-btn {
    padding: 0.3rem 0.75rem;
    border: 1px solid var(--line);
    border-radius: 999px;
    background: var(--surface);
    color: var(--muted);
    font: inherit;
    font-size: 0.85rem;
    cursor: pointer;
    transition: color 0.15s, border-color 0.15s, background 0.15s;
}
.pattern-cat-btn:hover { border-color: var(--muted); color: var(--text); }
.pattern-cat-btn.active {
    border-color: var(--accent);
    background: color-mix(in srgb, var(--accent) 12%, transparent);
    color: var(--accent);
}
.pattern-filter-status { margin: 0.85rem 0 0; color: var(--muted); font-size: 0.85rem; }
.pattern-cat-intro { max-width: 46rem; margin: 0 0 1rem; }
.pattern-card-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 240px), 1fr));
    gap: 0.85rem;
    margin-top: 0.5rem;
}
.pattern-card {
    display: block;
    padding: 1rem 1.1rem;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--surface);
    color: inherit;
    text-decoration: none;
    transition: border-color 0.15s, transform 0.15s;
}
.pattern-card:hover { border-color: var(--accent); transform: translateY(-2px); }
.pattern-card-cat { color: var(--accent); font-size: 0.68rem; font-weight: 600; letter-spacing: 0.05em; text-transform: uppercase; }
.pattern-card-title { margin: 0.3rem 0 0.25rem; font-size: 1rem; font-weight: 600; }
.pattern-card-desc { margin: 0; color: var(--muted); font-size: 0.85rem; line-height: 1.45; }
.pattern-empty { margin-top: 1.5rem; color: var(--muted); }

/* The other patterns of a pattern's category, at the foot of its page. */
.pattern-related { max-width: 50rem; margin-top: 2.5rem; padding-top: 1.25rem; border-top: 1px solid var(--line); }
.pattern-related h2 { margin-top: 0; }
.pattern-related li { margin: 0.35rem 0; }

/* ------------------------------------------------------------------------
   The playground
   ------------------------------------------------------------------------ */

.playground-head {
    max-width: 1480px;
    margin: 0 auto;
    padding: 28px var(--gutter) 0;
}
.playground-head h1 { margin-bottom: 0.2em; }
.playground-head .lead { max-width: 52em; margin-bottom: 0.4em; font-size: 1.05rem; }

.playground {
    max-width: 1480px;
    margin: 0 auto;
    padding: 0 var(--gutter);
}
.pg-noscript { padding: 12px 16px; border: 1px solid var(--line); border-radius: 6px; background: var(--surface); }

.pg-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 10px;
    padding: 10px 0;
}
.pg-bar button,
.pg-pick select {
    padding: 5px 12px;
    border: 1px solid var(--line);
    border-radius: 6px;
    background: var(--surface);
    color: var(--text);
    font: inherit;
    font-size: 0.9rem;
    cursor: pointer;
}
.pg-bar button:hover,
.pg-pick select:hover { border-color: var(--accent-fill); }
.pg-bar .pg-run { background: var(--accent-fill); border-color: var(--accent-fill); color: var(--on-accent); font-weight: 600; }
.pg-pick { display: flex; align-items: center; gap: 8px; color: var(--muted); font-size: 0.9rem; }
.pg-example { color: var(--muted); font-size: 0.9rem; }
.pg-example-title { color: var(--text); font-weight: 600; }
.pg-status { color: var(--muted); font-size: 0.85rem; }
.pg-origin { margin-left: auto; color: var(--muted); font-family: var(--font-mono); font-size: 0.8rem; }

.pg-main {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.2fr);
    gap: 16px;
    height: clamp(480px, calc(100svh - var(--header-h, 104px) - 64px), 900px);
}
.pg-code {
    display: flex;
    flex-direction: column;
    min-height: 0;
    border: 1px solid var(--line);
    border-radius: 8px;
    overflow: hidden;
    background: #212121;   /* material-darker's background */
}
.pg-tabs-row {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: space-between;
    gap: 4px 12px;
    padding: 6px 8px 0;
    background: var(--surface);
    border-bottom: 1px solid var(--line);
}
.pg-tabs { display: flex; gap: 2px; }
.pg-hint { margin: 0 4px 6px; color: var(--muted); font-size: 0.75rem; }
.pg-tabs button {
    padding: 6px 12px;
    border: 1px solid transparent;
    border-bottom: 0;
    border-radius: 6px 6px 0 0;
    background: transparent;
    color: var(--muted);
    font-family: var(--font-mono);
    font-size: 0.8rem;
    cursor: pointer;
}
.pg-tabs button[aria-selected="true"] { background: #212121; border-color: var(--line); color: #eeffff; }
.pg-editors { position: relative; flex: 1; min-height: 0; }
.pg-panel { position: absolute; inset: 0; }
.pg-panel[hidden] { display: none; }
.pg-panel .CodeMirror { position: absolute; inset: 0; height: auto; font: 13px/1.55 var(--font-mono); }

.pg-view { display: flex; flex-direction: column; gap: 12px; min-width: 0; min-height: 0; }
/* The runner's page fits its stage to the frame's width, with Kinetic's
   preview bar fixed under it. The runner sends the bar's height, which
   playground.js sets as --bar-h, since the bar wraps onto more rows in a
   narrow frame. */
.pg-frame-box {
    flex: none;
    container-type: inline-size;
    border: 1px solid var(--line);
    border-radius: 8px;
    overflow: hidden;
    background: #0d0f14;
}
.pg-frame {
    width: 100%;
    height: calc(100cqw * 9 / 16 + var(--bar-h, 44px));
    border: 0;
    background: #0d0f14;
    color-scheme: normal;
}
.pg-console {
    --pg-warn: #EFC187;
    --pg-error: #EF9481;
    flex: 1;
    min-height: 120px;
    overflow: auto;
    padding: 8px 10px;
    background: var(--code-bg);
    color: var(--code-text);
    border: 1px solid var(--line);
    border-radius: 8px;
    font: 12px/1.5 var(--font-mono);
}
:root[data-theme="light"] .pg-console { --pg-warn: #9F6215; --pg-error: #CF391A; }
.pg-line { white-space: pre-wrap; overflow-wrap: anywhere; }
.pg-line.warn { color: var(--pg-warn); }
.pg-line.error { color: var(--pg-error); }
.pg-line.quiet { color: var(--muted); }

/* On a phone the bar wraps onto three rows. The runner sends its real height
   once the frame is on the screen; until then the frame keeps room for that. */
@media (max-width: 560px) {
    .pg-frame { height: calc(100cqw * 9 / 16 + var(--bar-h, 92px)); }
}

@media (max-width: 900px) {
    .pg-main { grid-template-columns: minmax(0, 1fr); height: auto; }
    .pg-code { height: 60vh; min-height: 320px; }
    .pg-console { flex: none; height: 200px; }
    .pg-origin { width: 100%; margin-left: 0; }
}

@media (prefers-reduced-motion: reduce) {
    .beat, .navbar-collapse { transition: none; }
    .stage-frame.is-changing { animation: none; }
}

/* The outline baker page. */
.baker textarea, .baker input[type="text"] { width: 100%; max-width: 640px; padding: 8px 10px; border: 1px solid var(--border, #ccc); border-radius: 6px; font: inherit; }
.baker .button { margin: 0 6px 6px 0; }
.baker-axis { margin-right: 18px; }
.baker-preview { position: relative; width: 100%; max-width: 640px; aspect-ratio: 640 / 200; background: #efe8db; border-radius: 8px; }
.baker-preview canvas { position: absolute; inset: 0; width: 100%; height: 100%; }
.baker-sliders label { display: block; max-width: 640px; margin: 10px 0; }
.baker-sliders label[hidden] { display: none; }
.baker-sliders input[type="range"] { width: 100%; }
