: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 search field keeps its contrast against the cream page. */
    --bg: var(--color-cream);
    --surface: #fffcf7;
    --ink: var(--color-cocoa);
    --muted: #6b6259;

    /* Every visible control boundary: the search field, the empty state, the
       kbd cap. It used to be #dbcab8, which measures 1.48:1 against the cream
       page and 1.56:1 against the surface, far under the 3:1 that WCAG 1.4.11
       asks of anything that identifies a control. Mocha is the lightest brand
       token that clears it, 4.18:1 on cream and 4.41:1 on the surface. */
    --line-strong: var(--color-mocha);

    /* Focus colour is espresso site-wide, per style.md. 6.58:1 on cream. */
    --focus: var(--color-espresso);

    /* A toffee tint, used for the hover wash behind an emoji and the clear
       button. Named rather than repeated as a magic hex in two places. */
    --hover-tint: #f6ece2;

    --radius: 14px;
    --mono: ui-monospace, 'SF Mono', 'JetBrains Mono', 'Fira Code', Menlo, Consolas, monospace;
    --emoji-font: 'Apple Color Emoji', 'Segoe UI Emoji', 'Noto Color Emoji', sans-serif;
}

* { 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: 20;
    border-radius: 0 0 8px 0;
}
a.skip:focus { left: 0; }

/* The grid of emoji IS the page, so it gets the screen. Everything above it is
   chrome and stays short: one line of heading, the search, the category row.
   The description that carries this page's search terms sits BELOW the grid,
   where it keeps every word of its value without pushing the emoji off the
   first screen.

   min-height subtracts a fixed allowance for the sticky header rather than
   taking a percentage of the viewport, so a short window never overflows. The
   header is 108px below 640px and 124px above, matching coco.css. 100svh, not
   100vh, so mobile browser chrome that comes and goes never clips the fold. */
.wrap {
    width: 100%;
    /* 1280px, style.md's width for a full-width grid. The old 880px reading
       column fitted 8 columns of emoji on a desktop and left the rest of the
       screen empty; this fits 13. */
    max-width: 1280px;
    margin: 0 auto;
    padding: 1.25rem 1.25rem 2.5rem;
    flex: 1;
    min-height: calc(100svh - 108px);
}
@media (min-width: 640px) {
    .wrap { min-height: calc(100svh - 124px); }
}

/* Compact, one line. Deliberately not .brand-heading: Pacifico is a connected
   script that branding.md reserves for large headings, and this one is small
   on purpose so the grid starts higher. */
header#tool {
    position: relative;
    margin-bottom: 1rem;
}
h1 {
    font-size: clamp(1.3rem, 2.4vw, 1.7rem);
    line-height: 1.25;
    letter-spacing: -0.015em;
    margin: 0;
    font-weight: 650;
}

/* Sits under the grid now, so it never competes for height. */
.lede {
    color: var(--muted);
    font-size: 0.95rem;
    line-height: 1.55;
    margin: 2.25rem auto 0;
    max-width: 60ch;
    text-align: center;
}

h2.step-label {
    font-size: 0.78rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: var(--muted);
    margin: 0 0 0.65rem;
}
/* Named cf-step, not step: daisyUI ships a .step component (a grid cell with a
   numbered ::after circle). It is currently scoped under .steps, so nothing is
   broken today, but the name is one daisyUI release away from being ours to
   lose, and style.md lists it as a known landmine. */
.cf-step { margin-bottom: 1.15rem; }
.row-head {
    display: flex; justify-content: space-between; align-items: baseline;
    gap: 1rem; flex-wrap: wrap; margin-bottom: 0.65rem;
}
.row-head h2.step-label { margin: 0; }
.row-head h2.step-label:focus { outline: none; }
.counter { font-size: 0.8rem; color: var(--muted); }

/* Recently used and Popular sit side by side once there is room, so two short
   rows cost one row of height instead of two. */
.quick-rows {
    display: flex; flex-wrap: wrap; gap: 1.15rem 2.5rem;
    margin-bottom: 1.15rem;
}
.quick-rows > .cf-step { flex: 1 1 20rem; margin-bottom: 0; min-width: 0; }

/* Search box, one big friendly field, front and center */
.search-row { display: flex; gap: 10px; flex-wrap: wrap; max-width: 640px; }
.search { position: relative; flex: 1 1 300px; min-width: 0; }
.search .mag {
    position: absolute; left: 1.1rem; top: 50%; transform: translateY(-50%);
    color: var(--muted); pointer-events: none;
}
.field {
    width: 100%;
    min-height: 56px;
    border: 1px solid var(--line-strong);
    border-radius: 16px;
    padding: 0.9rem 4.2rem 0.9rem 2.9rem;
    font-size: 1.1rem;
    font-family: inherit;
    line-height: 1.5;
    color: var(--ink);
    background: var(--surface);
    outline: none;
}
/* Was a 3px ring of rgba(22,22,26,0.08), which lands at roughly 1.05:1 over
   cream, i.e. invisible. A real espresso outline matches every other control
   on the page and measures 6.58:1. */
.field:focus {
    border-color: var(--focus);
    outline: 2px solid var(--focus);
    outline-offset: 2px;
}
.field::placeholder { color: var(--muted); }
.field::-webkit-search-cancel-button { display: none; }
.clear-btn {
    position: absolute; right: 0.6rem; top: 50%; transform: translateY(-50%);
    appearance: none; border: none; background: none;
    width: 36px; height: 36px; border-radius: 10px;
    color: var(--muted); font-size: 1rem; line-height: 1;
    cursor: pointer; font-family: inherit;
    display: inline-flex; align-items: center; justify-content: center;
}
.clear-btn:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.kbd-hint {
    position: absolute; right: 0.95rem; top: 50%; transform: translateY(-50%);
    pointer-events: none;
}
@media (max-width: 560px) {
    .kbd-hint { display: none; }
}

/* Surprise me, a daisyUI outline button sized to match the search field. */
.cf-surprise {
    --size: 56px;
    --btn-p: 1.25rem;
    --radius-field: 16px;
    --fontsize: 0.98rem;
}
.cf-surprise .die { font-family: var(--emoji-font); font-size: 1.25rem; line-height: 1; }

kbd {
    font-family: var(--mono); font-size: 0.72rem;
    border: 1px solid var(--line-strong); border-bottom-width: 2px;
    border-radius: 5px; padding: 0.05rem 0.35rem;
    background: var(--surface); color: var(--muted);
}

button.linkish {
    appearance: none; border: none; background: none; padding: 0;
    font-size: 0.82rem; color: var(--muted); text-decoration: underline;
    cursor: pointer; font-family: inherit; white-space: nowrap;
}
button.linkish:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; border-radius: 4px; }

/* Category chips are daisyUI buttons now. --btn-color paints the resting label
   and border; --btn-fg paints the label once daisyUI swaps the background in on
   hover and on .btn-active. Setting only the colour is how an outline button
   ends up with dark text on a dark fill. Espresso is the brand's "you are here"
   colour: 6.58:1 as a label on cream, and white on espresso is 7.09:1. */
.cats {
    display: flex; flex-wrap: nowrap; gap: 8px;
    overflow-x: auto; -webkit-overflow-scrolling: touch;
    scrollbar-width: none; -ms-overflow-style: none;
    padding: 5px; margin: -5px; /* room for focus outlines inside the scroller */
}
.cats::-webkit-scrollbar { display: none; }
/* The scrollbar is hidden, so fade the trailing edge instead. Without a cue,
   nobody discovers the categories that sit off the right of a phone screen. */
@media (max-width: 1023px) {
    .cats {
        mask-image: linear-gradient(to right, #000 calc(100% - 2.5rem), transparent);
    }
}
@media (min-width: 1024px) {
    .cats { flex-wrap: wrap; overflow-x: visible; mask-image: none; }
}
.cf-cat {
    --btn-color: var(--color-espresso);
    --btn-fg: #fff;
    --radius-field: 999px;
    --fontsize: 0.85rem;
    --btn-p: 0.85rem;
    flex: 0 0 auto;
}
.cf-cat .ico { font-family: var(--emoji-font); }

/* Emoji buttons, the emoji are the color, the chrome recedes */
.ebtn {
    appearance: none; font-family: inherit;
    background: transparent;
    border: none;
    border-radius: 12px;
    padding: 0.55rem 0.3rem 0.5rem;
    min-width: 48px; min-height: 48px;
    cursor: pointer;
    display: flex; flex-direction: column; align-items: center; gap: 0.3rem;
    transition: background 0.15s;
}
.ebtn:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.ebtn .glyph {
    font-size: 2.5rem; line-height: 1.15; font-family: var(--emoji-font);
    transition: transform 0.12s ease;
}
.ebtn:focus-visible .glyph { transform: scale(1.12); }
.ebtn:active .glyph { transform: scale(0.92); }
.ebtn .ename {
    font-size: 0.7rem; color: var(--muted); line-height: 1.25; text-align: center;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
    overflow: hidden; overflow-wrap: anywhere;
}
.ebtn.mini {
    width: 52px; height: 52px; padding: 0;
    justify-content: center; gap: 0;
}
.ebtn.mini .glyph { font-size: 1.8rem; }

/* Hover states live behind @media (hover: hover), the way daisyUI wraps its
   own. Without it a tap on a touch screen leaves the emoji stuck with a beige
   wash and a scaled-up glyph until you tap something else. */
@media (hover: hover) {
    .clear-btn:hover { color: var(--ink); background: var(--hover-tint); }
    button.linkish:hover { color: var(--ink); }
    .ebtn:hover { background: var(--hover-tint); }
    /* The wash comes with its matching foreground: cocoa on the tint is
       11.52:1, where the resting muted grey would have been 5.12:1. */
    .ebtn:hover .ename { color: var(--ink); }
    .ebtn:hover .glyph { transform: scale(1.12); }
}

.egrid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(92px, 1fr));
    gap: 6px 4px;
}
.mini-row { display: flex; flex-wrap: wrap; gap: 6px; }

/* Empty state */
.code-empty {
    border: 1.5px dashed var(--line-strong);
    border-radius: var(--radius);
    padding: 2.4rem 1.25rem;
    text-align: center;
    color: var(--muted);
    font-size: 0.92rem;
    line-height: 1.6;
}
.code-empty .big { font-size: 2.2rem; font-family: var(--emoji-font); display: block; margin-bottom: 0.5rem; }

.load-wrap { display: flex; justify-content: center; margin-top: 1.4rem; }

/* Copied toast (decorative twin of the screen-reader announcement).
   Named .toast-brand, not .toast: daisyUI ships an unscoped .toast that
   pins to the bottom-right corner and stacks its children in a column.
   The page rules win on the properties they set, but flex-direction,
   inset-inline-end and width are ones this pill never declared, so
   daisyUI's values leaked through and stretched it. The Vue transition
   is still called "toast", so .toast-enter-active and friends stay. */
.toast-brand {
    position: fixed; left: 50%; bottom: 1.4rem; transform: translateX(-50%);
    background: var(--ink); color: #fff;
    border-radius: 999px; padding: 0.5rem 1.3rem 0.5rem 0.8rem;
    display: flex; align-items: center; gap: 0.7rem;
    font-size: 0.95rem; font-weight: 700;
    box-shadow: 0 6px 24px rgba(0,0,0,0.18);
    z-index: 30; max-width: calc(100vw - 2rem);
}
.toast-brand .glyph { font-size: 1.9rem; line-height: 1; font-family: var(--emoji-font); }
.toast-brand .tname { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@keyframes toast-pop {
    0% { opacity: 0; transform: translate(-50%, 10px) scale(0.9); }
    60% { opacity: 1; transform: translate(-50%, -2px) scale(1.03); }
    100% { opacity: 1; transform: translate(-50%, 0) scale(1); }
}
.toast-enter-active { animation: toast-pop 0.25s ease; }
.toast-leave-active { transition: opacity 0.18s ease, transform 0.18s ease; }
.toast-leave-to { opacity: 0; transform: translate(-50%, 8px); }

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

@media (prefers-reduced-motion: reduce) {
    .ebtn, .ebtn .glyph { transition: none; }
    .ebtn:focus-visible .glyph, .ebtn:active .glyph { transform: none; }
    .toast-enter-active, .toast-leave-active { animation: none; transition: none; }
}
@media (prefers-reduced-motion: reduce) and (hover: hover) {
    .ebtn:hover .glyph { transform: none; }
}

@media (max-width: 480px) {
    .wrap { padding-top: 1rem; }
    .egrid { grid-template-columns: repeat(auto-fill, minmax(78px, 1fr)); }
}
