:root {
    /* Brand tokens, not the old cool greys. --bg was #f4f4f2, which read
       grey against the rest of the site. The surface stays near-white so
       the input areas keep their contrast against the cream page. */
    --bg: var(--color-cream);
    --surface: #fffcf7;
    --ink: var(--color-cocoa);
    --muted: #6b6259;
    /* Both line tokens are now derived from the palette. --line-strong was
       #dbcab8, which measured 1.48:1 on cream and failed WCAG 1.4.11 on every
       control boundary it drew. Mocha is 4.18:1 on cream and stays in palette. */
    --line-strong: var(--color-mocha);
    --warn: var(--color-coral-deep);
    --radius: 14px;
    --mono: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
    /* Tinted result fill, so the read-only output never looks like the input. */
    --result-fill: #fbf2e6;
}

* { box-sizing: border-box; }

html, body { background: var(--bg); }
body {
    margin: 0;
    color: var(--ink);
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    -webkit-font-smoothing: antialiased;
    accent-color: var(--ink);
}
[v-cloak] { display: none; }

.sr-only {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}

a.skip {
    position: absolute; left: -9999px; top: 0;
    background: var(--ink); color: #fff; padding: 0.6rem 1rem; z-index: 50;
    border-radius: 0 0 8px 0;
}
a.skip:focus { left: 0; }

.wrap {
    width: 100%;
    max-width: 640px;
    margin: 0 auto;
    padding: 1.25rem 1.25rem 4rem;
    flex: 1;
}

/* The doodles are absolutely positioned against this block. The skip link
   targets #tool, so it needs the same sticky-header clearance the steps get. */
header#tool { position: relative; scroll-margin-top: 140px; }

h1 {
    line-height: 1.25;
    margin: 0 0 0.6rem;
}
.lede {
    color: var(--muted);
    font-size: 1rem;
    line-height: 1.55;
    margin: 0 0 1.25rem;
    max-width: 50ch;
}

h2.step-label {
    font-size: 0.78rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: var(--muted);
    margin: 0 0 0.8rem;
}
/* cf- prefix, not the bare .step: daisyUI owns that name via `.steps &`. */
section.cf-step {
    margin-bottom: 1.5rem;
    /* Clears the sticky site header when a step is scrolled into view. */
    scroll-margin-top: 140px;
}

textarea.msg {
    width: 100%;
    min-height: 120px;
    resize: vertical;
    border: 1px solid var(--line-strong);
    border-radius: var(--radius);
    padding: 0.9rem 1rem;
    font-family: inherit;
    font-size: 0.98rem;
    line-height: 1.55;
    color: var(--ink);
    background: var(--surface);
}
textarea.msg:focus { border-color: var(--ink); }
textarea.msg:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
textarea.msg::placeholder { color: var(--muted); }
textarea.msg[readonly] { cursor: text; }

/* The read-only result. Same box, different surface, so it never reads as a
   second place to type. Matches the dashed empty state it replaces. */
textarea.msg-result {
    background: var(--result-fill);
    border-width: 1.5px;
    border-style: dashed;
}

.io-row {
    display: flex; justify-content: space-between; align-items: center;
    gap: 1rem; margin-top: 0.45rem; flex-wrap: wrap;
}
.counter { font-size: 0.78rem; color: var(--muted); }
/* Element selector on purpose: never a bare .btn rule in page CSS. */
.io-row button { --fontsize: 0.82rem; }

/* Style chips */
fieldset.cases, fieldset.tidy-set { border: 0; padding: 0; margin: 0; }
fieldset.cases legend, fieldset.tidy-set legend { padding: 0; }
.chips { display: flex; flex-wrap: wrap; gap: 8px; }
.chip {
    display: flex; flex-direction: column; gap: 1px;
    border: 1px solid var(--line-strong);
    border-radius: 11px;
    background: var(--surface);
    padding: 0.5rem 0.85rem;
    cursor: pointer;
    transition: background 0.15s, border-color 0.15s, box-shadow 0.15s;
}
/* Hover and selected live on different channels. They both used to flip
   border-color to --ink, so while the pointer was anywhere in the grid you
   could not tell which style was actually applied. */
.chip:hover { border-color: var(--color-caramel); background: var(--surface); }
/* .on is a Vue class mirror of :checked, the working path in browsers
   without :has() support, harmless duplication everywhere else. */
.chip.on {
    background: var(--surface);
    border-color: var(--ink);
    /* Inset ring, so selected reads as a 2px edge with no layout shift. */
    box-shadow: inset 0 0 0 1px var(--ink), 0 1px 3px rgba(0,0,0,0.08);
}
.chip:has(input:focus-visible) { outline: 2px solid var(--ink); outline-offset: 2px; }
@supports not selector(.x:has(a)) {
    .chip:focus-within { outline: 2px solid var(--ink); outline-offset: 2px; }
}
.chip-name { font-weight: 600; font-size: 0.88rem; }
.chip-eg { font-size: 0.74rem; color: var(--muted); font-family: var(--mono); }

/* Element-qualified, so it beats the shared fieldset reset above. */
fieldset.tidy-set { margin-top: 1.5rem; }
.tidy-set legend {
    font-size: 0.78rem; font-weight: 700; text-transform: uppercase;
    letter-spacing: 0.07em; color: var(--muted); margin-bottom: 0.55rem;
}
.tidy-row { display: flex; flex-wrap: wrap; gap: 0.6rem 1.5rem; }
label.tidy {
    display: inline-flex; align-items: center; gap: 0.5rem;
    font-size: 0.9rem; cursor: pointer;
}
label.tidy input { width: 15px; height: 15px; }
label.tidy input:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }

/* Result */
.code-empty {
    /* Same height as the textarea that replaces it, so the first character
       typed does not shove the Copy and Download buttons out from under the
       pointer. */
    min-height: 120px;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 1.5px dashed var(--line-strong);
    border-radius: var(--radius);
    padding: 1.25rem;
    text-align: center;
    color: var(--muted);
    font-size: 0.9rem;
}
.result-actions { display: flex; gap: 0.6rem; margin-top: 0.8rem; flex-wrap: wrap; }
/* Element selector, not .btn: daisyUI owns that name and the buttons are
   real daisyUI buttons now. Everything else these rules used to hand-roll
   (padding, radius, inline-flex centring, gap, transition, focus-visible)
   ships in the bundle. */
.result-actions > button { flex: 1; min-width: 150px; }
/* Gated on hover:hover so touch devices do not get a stuck hover fill, matching
   how daisyUI guards its own .btn:hover. --btn-fg matters: without it the outline
   button kept dark text on the espresso fill, which measured 2.50:1. White on
   espresso is 7.09:1. */
@media (hover: hover) {
    .result-actions > button:hover {
        --btn-bg: var(--color-espresso);
        --btn-border: var(--color-espresso);
        --btn-fg: #fff;
    }
}
.result-actions > button:disabled {
    background-color: transparent;
    border-color: var(--line-strong);
    color: var(--muted);
    box-shadow: none;
}

.copy-note { font-size: 0.82rem; color: var(--muted); margin-top: 0.6rem; }
.copy-note.bad { color: var(--warn); font-weight: 600; }

.foot {
    text-align: center; padding: 1.5rem 1rem 2rem;
    font-size: 0.8rem; color: var(--muted);
}

@media (prefers-reduced-motion: reduce) {
    .chip, .result-actions > button { transition: none; }
}

@media (max-width: 480px) {
    .wrap { padding-top: 1.5rem; }
    .result-actions > button { min-width: 100%; }
    /* Thumb-sized targets. "Clear" is the only destructive control on the
       page and it used to be 32x20px. */
    .io-row button { min-height: 44px; }
    label.tidy { min-height: 44px; }
    label.tidy input { width: 20px; height: 20px; }
    /* Counter on its own line, action link right-aligned below, the row
       keeps one shape whether the link says Clear or Try an example. */
    .io-row { justify-content: flex-end; }
    .io-row .counter { flex: 1 0 100%; }
}

/* Not Tailwind's .scroll-smooth utility: that one is unconditional and ignores
   a reduced-motion preference. */
@media (prefers-reduced-motion: no-preference) {
    html { scroll-behavior: smooth; }
}
