/* Direction A design system: foundational tokens + web fonts (issue #43).
   Source of truth for tone is docs/design/Direction A. The finder page must
   stay fast and fully functional without script (spec.md §13, stack-spec §3),
   so fonts are self-hosted (no fonts.gstatic.com round-trip on poor airport
   Wi-Fi, no third-party privacy cost) and loaded with font-display: swap so
   text paints immediately in the system-ui fallback and swaps in when ready. */

/* Newsreader (serif) — headings and the finder-facing note voice. Variable
   weight axis, latin subset; one file covers the 400–600 range we use. */
@font-face {
    font-family: "Newsreader";
    font-style: normal;
    font-weight: 400 600;
    font-display: swap;
    src: url("../fonts/newsreader-latin.woff2") format("woff2");
}
@font-face {
    font-family: "Newsreader";
    font-style: italic;
    font-weight: 400 600;
    font-display: swap;
    src: url("../fonts/newsreader-italic-latin.woff2") format("woff2");
}

/* Hanken Grotesk (body / UI). Variable weight axis, latin subset; one file
   covers the 400–700 range we use. */
@font-face {
    font-family: "Hanken Grotesk";
    font-style: normal;
    font-weight: 400 700;
    font-display: swap;
    src: url("../fonts/hanken-grotesk-latin.woff2") format("woff2");
}

/* IBM Plex Mono (codes, labels, eyebrows). Static instances, latin subset. */
@font-face {
    font-family: "IBM Plex Mono";
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url("../fonts/ibm-plex-mono-400-latin.woff2") format("woff2");
}
@font-face {
    font-family: "IBM Plex Mono";
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url("../fonts/ibm-plex-mono-500-latin.woff2") format("woff2");
}
@font-face {
    font-family: "IBM Plex Mono";
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url("../fonts/ibm-plex-mono-600-latin.woff2") format("woff2");
}

:root {
    /* Palette — Direction A (issue #43). */
    --bg: #f7f1e7; /* paper / page background */
    --ink: #241f1a; /* primary text. Reconciled: the comp's #241f1a wins over
                       the app's old #2b2620 — the comp is the source of truth,
                       and the darker value only raises contrast on --bg. */
    --muted: #6b6055; /* AA-compliant secondary text on --bg (spec.md §13) */
    --neutral: #a89c8d; /* meta / timestamps — large or non-essential text only */

    --accent: #c2613a; /* terracotta — the single brand accent */
    --accent-dark: #a8512f; /* pressed / emphasis terracotta */
    --accent-tint: #f3e4d8; /* terracotta wash — pills, chips */
    --accent-tint-warm: #fbe9da; /* warmer terracotta wash */
    --on-accent: #fff; /* text/icons on a terracotta fill */

    --card: #fffdf9; /* raised surfaces — cards, bubbles, inputs */
    --panel: #efe7d9; /* recessed surfaces — toolbars, chrome */
    --border: #ece2d2; /* hairline borders */
    --border-strong: #e0d5c4; /* input / interactive borders */

    --success: #5f8c4e; /* active / recovered green */

    /* #9a8f80 is the comp's eyebrow grey. On --bg it measures 2.83:1, below
       AA's 4.5:1, so it must NOT be used for small body text — restrict to
       large text only (≥18pt, or ≥14pt bold) per spec.md §13. Small eyebrows
       use --muted instead (see .eyebrow). */
    --eyebrow: #9a8f80;

    /* Spacing scale (4px base). */
    --space-1: 0.25rem; /* 4 */
    --space-2: 0.5rem; /* 8 */
    --space-3: 0.75rem; /* 12 */
    --space-4: 1rem; /* 16 */
    --space-5: 1.5rem; /* 24 */
    --space-6: 2rem; /* 32 */
    --space-7: 3rem; /* 48 */
    --space-8: 3.5rem; /* 56 */

    /* Radius scale — Direction A favours soft 14–18px corners. */
    --radius-sm: 0.5rem; /* 8 — small chips, code boxes */
    --radius: 0.875rem; /* 14 — inputs, buttons */
    --radius-lg: 1rem; /* 16 — cards, message bubbles */
    --radius-xl: 1.125rem; /* 18 — tags */
    --radius-pill: 999px; /* pills, status chips, round controls */

    /* Shadows — warm, soft, cast in the comp's rgba(50,38,24,…) ink. */
    --shadow-sm: 0 1px 2px rgba(50, 38, 24, 0.08);
    --shadow: 0 16px 40px -18px rgba(50, 38, 24, 0.4);
    --shadow-lg: 0 28px 64px -28px rgba(50, 38, 24, 0.45);

    /* Type families. System fallbacks keep the finder path readable before
       (or without) the web fonts loading. */
    --font-serif: "Newsreader", Georgia, "Times New Roman", serif;
    --font-sans: "Hanken Grotesk", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    --font-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

    /* Type scale (rem). */
    --text-xs: 0.75rem; /* 12 — eyebrows, labels */
    --text-sm: 0.875rem; /* 14 — secondary body */
    --text-base: 1rem; /* 16 — body */
    --text-lg: 1.0625rem; /* 17 — lead paragraph */
    --text-xl: 1.625rem; /* 26 — h3 */
    --text-2xl: 1.875rem; /* 30 — h2 */
    --text-3xl: 2.125rem; /* 34 */
    --text-4xl: 2.625rem; /* 42 — display heading */

    /* Line heights. */
    --leading-tight: 1.05;
    --leading-snug: 1.45;
    --leading-normal: 1.55;

    /* Letter spacing / tracking. */
    --tracking-tight: -0.01em; /* large serif headings */
    --tracking-eyebrow: 0.14em; /* mono eyebrows */
    --tracking-code: 0.18em; /* code glyphs */
}

* {
    box-sizing: border-box;
}

/* Visually hidden, but available to screen readers — used to spell out icon-only signals like the
   unread dot in the conversation list. The standard clip-rect pattern. */
.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    border: 0;
    overflow: hidden;
    clip: rect(0 0 0 0); /* legacy fallback */
    clip-path: inset(50%); /* modern equivalent; clip is deprecated */
    white-space: nowrap;
}

body {
    margin: 0;
    font-family: var(--font-sans);
    font-size: var(--text-base);
    color: var(--ink);
    background: var(--bg);
    line-height: 1.5;
}

/* Foundational type scale. Direction A speaks in a serif voice for headings,
   sans for body/UI, and mono for codes/labels/eyebrows. Per-page restyles
   build on these defaults; this issue just establishes the scale. */
h1,
h2,
h3 {
    font-family: var(--font-serif);
    font-weight: 600;
    color: var(--ink);
    letter-spacing: var(--tracking-tight);
    line-height: var(--leading-tight);
    margin: 0 0 var(--space-3);
}

h1 {
    font-size: var(--text-4xl);
}

h2 {
    font-weight: 500;
    font-size: var(--text-3xl);
}

h3 {
    font-weight: 500;
    font-size: var(--text-xl);
    line-height: var(--leading-snug);
}

/* Lead paragraph — the warm, human intro sentence. */
.lead {
    font-size: var(--text-lg);
    line-height: var(--leading-normal);
    color: var(--muted);
}

/* Mono eyebrow / kicker. Small, so it uses --muted (AA on --bg), NOT the
   comp's #9a8f80 which only clears AA at ≥18pt / ≥14pt bold (spec.md §13). */
.eyebrow {
    font-family: var(--font-mono);
    font-weight: 600;
    font-size: var(--text-xs);
    line-height: 1;
    letter-spacing: var(--tracking-eyebrow);
    text-transform: uppercase;
    color: var(--muted);
}

header,
main,
footer {
    max-width: 32rem;
    margin: 0 auto;
    padding: 1rem;
}

/* Wordmark — Newsreader serif in terracotta, the Direction A brand voice
   (outstanding §1, comp 01). One treatment for every header: finder, auth, and
   the owner chrome. --accent-dark keeps it AA on both --bg (finder/auth) and the
   owner header's --card (4.8–5.3:1); plain --accent measures ~4.1, under 4.5. */
.brand {
    font-family: var(--font-serif);
    font-weight: 400; /* base sits at book weight so the weighted initials read */
    font-size: var(--text-lg);
    letter-spacing: var(--tracking-tight);
    text-decoration: none;
    color: var(--accent-dark);
}

/* The initial of each word in "if you find me" (i·y·f·m) is weighted so the
   phrase reads at a glance while the wordmark stays lowercase. 600 is the top of
   the Newsreader axis we load (400–600, see @font-face); going higher would
   trigger a synthetic faux-bold that smears the serifs. */
.brand-ini {
    font-weight: 600;
}

/* The ".me" tail reads in plain --accent. The wordmark is large/bold, so it
   clears AA at the 3:1 floor (--accent is ~4.1:1) — the tail stays distinct and
   lands the "find me" pun while "ifyoufind" keeps the AA-safe --accent-dark. */
.brand-tld {
    color: var(--accent);
}

/* ── Finder code entry — Index.cshtml (Direction A, comp 01, issue #44) ───────
   The first screen a finder sees: a calm paper page with a serif headline, a
   framed code field with a terracotta text caret, a full-width terracotta CTA,
   and a privacy reassurance line. Mobile-first; no script (spec §13). */
/* The two co-equal entry paths stack in reading order within the page's narrow column (issue #128
   follow-up): finder first (the time-critical path — someone is holding a found item), then the spoken
   "or", then the owner's get-started card. Both are full-width cards, so neither reads as the afterthought. */
.entry-paths {
    margin-top: var(--space-5);
    display: grid;
    gap: var(--space-4);
    align-items: start;
}

/* Each path is a raised card so neither reads as secondary chrome — both are first-class. The fields
   inside use --card, a shade lighter than the --panel card, so they stay legible surfaces-within-surfaces. */
.entry-path {
    padding: var(--space-5);
    background: var(--panel);
    border-radius: var(--radius-lg);
}

.entry-path h1,
.entry-path h2 {
    font-size: var(--text-2xl);
    font-weight: 600;
    margin: 0 0 var(--space-2);
}

.entry-path .lead {
    font-size: var(--text-base);
    margin: 0 0 var(--space-5);
}

/* "or" divider between the cards — a centered word on a hairline rule. Hidden from assistive tech in the
   markup (the two headings already read as alternatives); this is a sighted-reader cue only. */
.entry-or {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin: 0;
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    letter-spacing: var(--tracking-eyebrow);
    text-transform: uppercase;
    color: var(--muted);
}

.entry-or::before,
.entry-or::after {
    content: "";
    flex: 1;
    height: 1px;
    background: var(--border-strong);
}

/* The finder card keeps its own field/button treatment (below); only its outer spacing moves to the
   shared card, so its first child no longer needs a top margin. */
.finder-entry .lead {
    margin: 0 0 var(--space-6);
}

/* The code label reads as a quiet mono eyebrow above the field. */
.finder-entry label {
    display: block;
    margin-bottom: var(--space-2);
    font-family: var(--font-mono);
    font-weight: 500;
    font-size: var(--text-xs);
    letter-spacing: var(--tracking-eyebrow);
    text-transform: uppercase;
    color: var(--muted);
}

/* Framed code field — big mono glyphs with generous tracking, and a terracotta
   caret. caret-color tints the real text cursor, so the comp's terracotta caret
   needs no extra markup and stays in the no-JS finder path. */
.finder-entry input {
    display: block;
    width: 100%;
    padding: var(--space-4);
    font-family: var(--font-mono);
    font-size: var(--text-2xl);
    font-weight: 500;
    letter-spacing: var(--tracking-code);
    text-transform: uppercase;
    color: var(--ink);
    background: var(--card);
    border: 1.5px solid var(--border-strong);
    border-radius: var(--radius);
    caret-color: var(--accent);
}

.finder-entry input::placeholder {
    color: var(--neutral);
}

/* Full-width terracotta CTA with a trailing arrow (comp 01). */
.finder-entry button {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    width: 100%;
    min-height: 44px; /* ≥44px tap target (spec §13 / outstanding §8) */
    margin-top: var(--space-3);
    padding: var(--space-4) var(--space-5);
    font-family: var(--font-sans);
    font-weight: 600;
    font-size: var(--text-base);
    color: var(--on-accent);
    background: var(--accent);
    border: 0;
    border-radius: var(--radius);
    cursor: pointer;
}

.finder-entry button:hover {
    background: var(--accent-dark);
}

/* Submit readiness cue (issue #97): the box only enables submit once 8 in-alphabet characters are
   present — pure syntax, never a "valid!" claim (the keyed check symbol is server-only, spec §8). The
   disabled state reads as inert; .is-ready is a quiet lift, not a checkmark. JS-only — with no script
   the button stays its normal, always-enabled self. */
.finder-entry button:disabled {
    background: var(--neutral);
    cursor: not-allowed;
}

/* Live alphabet hint (issue #97): names the one out-of-alphabet character a finder typed, in the same
   warning voice as .form-error but quieter. Hidden until the script has something to say. */
.finder-hint {
    margin: var(--space-2) 0 0;
    font-size: var(--text-sm);
    color: #8a2b1f; /* matches .form-error — darker than the AA floor on --bg */
}

/* Privacy reassurance — a small lock glyph + the promise the finder stays
   anonymous (spec §10). --muted clears AA on --bg; the comp's #9a8f80 would not
   at this size (spec §13). */
.finder-reassure {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    margin: var(--space-5) 0 0;
    font-size: var(--text-sm);
    color: var(--muted);
    text-align: left;
}

.finder-reassure .lock {
    flex: none;
    color: var(--accent);
}

/* The owner path — the second co-equal way in (issue #128 follow-up). It mirrors the finder card's
   field-then-button rhythm so the two read as siblings, but the email field uses ordinary sans text
   (not the finder's big mono code glyphs) and the submit is an outlined accent button, so a finder can
   still tell the urgent code lookup from the "get started" action at a glance. */
.owner-entry label {
    display: block;
    margin-bottom: var(--space-2);
    font-family: var(--font-mono);
    font-weight: 500;
    font-size: var(--text-xs);
    letter-spacing: var(--tracking-eyebrow);
    text-transform: uppercase;
    color: var(--muted);
}

.owner-entry input {
    display: block;
    width: 100%;
    padding: var(--space-4);
    font-family: var(--font-sans);
    font-size: var(--text-base);
    color: var(--ink);
    background: var(--card);
    border: 1.5px solid var(--border-strong);
    border-radius: var(--radius);
    caret-color: var(--accent);
}

.owner-entry input::placeholder {
    color: var(--neutral);
}

/* Outlined accent CTA — same size and shape as the finder's filled button, so the paths weigh the same,
   but the lighter fill keeps the terracotta "look it up" the single loudest thing on the page. */
.owner-entry button {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    width: 100%;
    min-height: 44px; /* ≥44px tap target (spec §13) */
    margin-top: var(--space-3);
    padding: var(--space-4) var(--space-5);
    font-family: var(--font-sans);
    font-weight: 600;
    font-size: var(--text-base);
    color: var(--accent-dark);
    background: var(--card);
    border: 1.5px solid var(--accent);
    border-radius: var(--radius);
    cursor: pointer;
}

.owner-entry button:hover {
    color: var(--on-accent);
    background: var(--accent);
}

/* Hint under the owner email field — spells out what "get started" does (a one-time code, no password).
   Quiet --muted like the finder's privacy reassurance, so it informs without competing with the field. */
.owner-email-hint {
    margin: var(--space-3) 0 0;
    font-size: var(--text-sm);
    color: var(--muted);
}

/* Finder language switcher (issue #98), now a subtle disclosure in the footer. Collapsed it shows only
   the current language behind a globe glyph, so the footer never lists every language; opening it reveals
   the full set as quiet, wrap-friendly native-name links. A native <details>, so it needs no script on
   the finder critical path (stack-spec §3). The current language reads as plain emphasized text. The
   <nav> wrapper keeps the switcher a navigation landmark for assistive tech (it carries the label). */
.lang-switcher-nav {
    margin-top: var(--space-3);
}

.lang-switcher {
    font-size: var(--text-sm);
}

.lang-switcher > summary {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    width: fit-content;
    cursor: pointer;
    color: var(--muted);
    list-style: none; /* hide the default disclosure triangle — the globe carries the affordance */
}

.lang-switcher > summary::-webkit-details-marker {
    display: none;
}

.lang-switcher > summary:hover {
    color: var(--accent);
}

.lang-switcher .lang-globe {
    flex: none;
}

.lang-switcher ul {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-4);
    margin: var(--space-3) 0 0;
    padding: 0;
    list-style: none;
}

.lang-switcher a {
    color: var(--muted);
    text-decoration: none;
}

.lang-switcher a:hover {
    color: var(--accent);
    text-decoration: underline;
}

.lang-switcher .lang-current {
    color: var(--ink);
    font-weight: 600;
}

.lang-switcher > summary:focus-visible,
.lang-switcher a:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
    border-radius: 2px;
}

footer small {
    color: var(--muted);
}

/* Footer corporate links (About / Privacy / Contact). A quiet, wrap-friendly row
   under the tagline — muted until hover, matching the language switcher's voice. */
.footer-nav {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-4);
    margin-top: var(--space-3);
    font-size: var(--text-sm);
}

.footer-nav a {
    color: var(--muted);
    text-decoration: none;
}

.footer-nav a:hover {
    color: var(--accent);
    text-decoration: underline;
}

.footer-nav a:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
    border-radius: 2px;
}

.note {
    color: var(--muted);
    font-size: 0.9rem;
}

/* Finder messaging (spec §7). Stays legible and usable with no script (spec §13). */
.form-error {
    color: #8a2b1f; /* darker than the AA contrast floor on --bg */
    font-size: 0.9rem;
    margin: 0.25rem 0;
}

.form-notice {
    background: #e8efe3;
    padding: 0.5rem 0.75rem;
    border-radius: 0.25rem;
}

.auth label {
    display: block;
    margin-top: var(--space-3);
    font-weight: 600;
}

/* ── Finder conversation composer — Code.cshtml / Thread.cshtml ──────────────
   Framed textarea + terracotta send, matching the owner composer. The single-
   use email reply page (Reply.cshtml) shares these so it isn't left skeleton. */
.finder-thread label,
.reply label {
    display: block;
    margin: var(--space-4) 0 var(--space-2);
    font-family: var(--font-mono);
    font-weight: 500;
    font-size: var(--text-xs);
    letter-spacing: var(--tracking-eyebrow);
    text-transform: uppercase;
    color: var(--muted);
}

.finder-thread textarea,
.finder-thread input[type="email"],
.reply textarea {
    display: block;
    width: 100%;
    padding: var(--space-3) var(--space-4);
    font: inherit;
    color: var(--ink);
    background: var(--card);
    border: 1.5px solid var(--border-strong);
    border-radius: var(--radius);
}

.finder-thread textarea,
.reply textarea {
    resize: vertical;
    line-height: var(--leading-snug);
}

.finder-thread textarea::placeholder,
.finder-thread input::placeholder {
    color: var(--neutral);
}

.finder-thread button,
.reply button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 44px; /* ≥44px tap target (spec §13) */
    margin-top: var(--space-3);
    padding: var(--space-3) var(--space-5);
    font-family: var(--font-sans);
    font-weight: 600;
    font-size: var(--text-sm);
    color: var(--on-accent);
    background: var(--accent);
    border: 0;
    border-radius: var(--radius);
    cursor: pointer;
}

.finder-thread button:hover,
.reply button:hover {
    background: var(--accent-dark);
}

/* Visible focus rings on every restyled finder/reply control (spec §13). */
.finder-entry input:focus-visible,
.finder-entry button:focus-visible,
.owner-entry input:focus-visible,
.owner-entry button:focus-visible,
.finder-thread textarea:focus-visible,
.finder-thread input:focus-visible,
.finder-thread button:focus-visible,
.reply textarea:focus-visible,
.reply button:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* Auth pages (sign-in / verify) — issue #46. Not in the Direction A comp, so
   they inherit the foundational scale (#43) and adopt the same terracotta
   button + soft radii used across the app. Kept token-driven so they stay in
   sync with the rest of the system. */
.auth input {
    display: block;
    width: 100%;
    padding: 0.75rem;
    font-size: 1.25rem;
    color: var(--ink);
    background: var(--card);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius);
}

.auth button {
    margin-top: 0.75rem;
    min-height: 2.75rem; /* ≥44px tap target (spec.md §13) */
    padding: 0.75rem 1.25rem;
    font: inherit;
    font-weight: 600;
    color: var(--on-accent);
    background: var(--accent);
    border: 0;
    border-radius: var(--radius);
    cursor: pointer;
}

.auth button:hover {
    background: var(--accent-dark);
}

/* Visible focus on the restyled controls (spec.md §13 / outstanding §8).
   Scoped to .auth so it stands alone without depending on the finder-path
   restyle's global focus rule. */
.auth input:focus-visible,
.auth button:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* "Send a new code" on the verify page: semantically a button (it POSTs and
   issues a code) but visually a link inside the "didn't get it?" note, so it
   never competes with the primary Verify action. Overrides the .auth button
   terracotta block styling above. */
.auth .resend button {
    display: inline;
    min-height: 0;
    margin: 0;
    padding: 0;
    font: inherit;
    color: inherit;
    background: none;
    border: 0;
    text-decoration: underline;
    cursor: pointer;
}

/* ── Corporate pages — About / Privacy / Contact ────────────────────────────
   Readable long-form prose and the contact form. Not in the Direction A comp;
   they inherit the foundational type scale and the shared terracotta controls so
   they stay in sync with the rest of the system. */
.content-page {
    line-height: var(--leading-normal);
}

.content-page h2 {
    margin-top: var(--space-6);
}

.content-page p,
.content-page ul,
.content-page ol {
    margin: 0 0 var(--space-4);
}

.content-page ul,
.content-page ol {
    padding-left: var(--space-5);
}

.content-page li {
    margin-bottom: var(--space-2);
}

.content-page a {
    color: var(--accent-dark);
}

/* Contact form. Block labels and full-width controls matching the auth pages,
   with a resizable message box like the finder/owner composers. */
.content-page label {
    display: block;
    margin-top: var(--space-4);
    font-weight: 600;
}

.content-page .optional {
    font-weight: 400;
    color: var(--muted);
}

.content-page input,
.content-page textarea {
    display: block;
    width: 100%;
    margin-top: var(--space-2);
    padding: 0.75rem;
    font: inherit;
    color: var(--ink);
    background: var(--card);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius);
}

.content-page textarea {
    resize: vertical;
    line-height: var(--leading-snug);
}

.content-page input::placeholder,
.content-page textarea::placeholder {
    color: var(--neutral);
}

.content-page button {
    display: block;
    margin-top: var(--space-4);
    min-height: 2.75rem; /* ≥44px tap target (spec.md §13) */
    padding: 0.75rem 1.25rem;
    font: inherit;
    font-weight: 600;
    color: var(--on-accent);
    background: var(--accent);
    border: 0;
    border-radius: var(--radius);
    cursor: pointer;
}

.content-page button:hover {
    background: var(--accent-dark);
}

.content-page input:focus-visible,
.content-page textarea:focus-visible,
.content-page button:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* Contact-form confirmation after a successful send (POST/redirect/GET). The
   calm-green notice voice used for confirmations elsewhere. */
.form-success {
    margin: 0 0 var(--space-4);
    padding: 0.5rem 0.75rem;
    background: #e8efe3;
    border-radius: var(--radius-sm);
    color: var(--ink);
}

/* ── Owner's finder-facing note ─────────────────────────────────────────────
   The warm "the owner left a note" card a finder sees first (Code.cshtml) and
   the owner's live setup-screen preview (CodeSetup). Serif italic in a card with a
   terracotta edge — the same finder-note voice used on the owner code detail. */
.owner-note-label {
    margin: 0 0 var(--space-2);
    font-family: var(--font-mono);
    font-weight: 500;
    font-size: var(--text-xs);
    letter-spacing: var(--tracking-eyebrow);
    text-transform: uppercase;
    color: var(--accent-dark); /* AA on --card (5.3:1); plain --accent would not */
}

.owner-message {
    margin: 0 0 var(--space-5);
    padding: var(--space-4);
    font-family: var(--font-serif);
    font-style: italic;
    font-size: var(--text-lg);
    line-height: var(--leading-snug);
    color: var(--ink);
    background: var(--card);
    border: 1.5px solid var(--border);
    border-left: 3px solid var(--accent);
    border-radius: 0 var(--radius) var(--radius) 0;
}

/* ── Conversation bubbles ───────────────────────────────────────────────────
   One chat transcript, shared by the finder thread (Code/Thread.cshtml), the
   owner conversation views (_MessageBubble), and the email reply page
   (Reply.cshtml). `message-you` is always the current viewer — owner OR finder —
   so it sits right in terracotta; the other party sits left in cream; system
   notes center. (MessagePresentation / the page switch set the modifier.) */
.messages {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    list-style: none;
    padding: 0;
    margin: var(--space-5) 0;
}

.message {
    max-width: 82%;
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius-lg);
}

/* The current viewer's own messages — right-aligned terracotta. --accent-dark
   keeps white body text AA (5.4:1); plain --accent is 4.15:1, under the 4.5
   floor for body text (spec §13). */
.message-you {
    align-self: flex-end;
    color: var(--on-accent);
    background: var(--accent-dark);
    border-bottom-right-radius: 4px;
}

/* The other party — left-aligned cream card (owner-view: finder; finder-view: owner). */
.message-owner,
.message-finder {
    align-self: flex-start;
    color: var(--ink);
    background: var(--card);
    border: 1.5px solid var(--border);
    border-bottom-left-radius: 4px;
}

/* System notes ("Owner notified…") — a centered, quiet line, no bubble. */
.message-system {
    align-self: center;
    max-width: 100%;
    padding: var(--space-1) 0;
    text-align: center;
    background: none;
}

.message-meta {
    margin: 0 0 var(--space-1);
    font-size: var(--text-xs);
    color: var(--muted);
}

/* On the terracotta bubble the meta reads in a warm tint that still clears AA
   on --accent-dark (4.6:1). */
.message-you .message-meta {
    color: var(--accent-tint-warm);
}

.message-system .message-meta {
    font-family: var(--font-mono);
    letter-spacing: 0.04em;
}

.message-body {
    margin: 0;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

/* "Read" receipt — a small, right-aligned line under the viewer's own latest message, the side their
   bubbles sit on (issue #79). Server-rendered for the no-script case; site.js toggles it live. */
.read-receipt {
    margin: 0 0 var(--space-4);
    text-align: right;
    font-size: var(--text-xs);
    color: var(--muted);
}

.read-receipt[hidden] {
    display: none;
}

.read-receipt-label {
    font-weight: 600;
}

/* Conversation header bar — the thread's status on the left with the sound toggle pinned right, so the
   mute control sits in the header where chat apps put it rather than floating above the composer. */
.conversation-bar {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin: 0 0 var(--space-4);
}

.conversation-bar .thread-status {
    margin: 0;
}

/* Slot site.js fills with the sound toggle; right-aligned, and with no script it is empty and collapses
   (the header bar then shows the status line alone). */
.conversation-controls {
    display: flex;
    justify-content: flex-end;
    margin: 0 0 var(--space-4);
}

.conversation-controls:empty {
    display: none;
}

/* Inside the header bar the slot hugs the right edge and drops its own bottom gap — the bar owns spacing. */
.conversation-bar .conversation-controls {
    margin: 0 0 0 auto;
}

/* Modern mute toggle — a compact icon + label pill. Scoped under .conversation-controls so it wins over
   the full-width terracotta .finder-thread button styling on the finder path. The bell rings in the
   brand accent while sound is on and goes quiet grey once muted; the icon itself flips to a struck bell. */
.conversation-controls .chime-toggle {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    min-height: 36px;
    margin: 0;
    padding: var(--space-2) var(--space-3);
    border: 1.5px solid var(--border-strong);
    border-radius: var(--radius-pill);
    background: var(--card);
    color: var(--muted);
    font: inherit;
    font-size: var(--text-xs);
    font-weight: 600;
    line-height: 1;
    cursor: pointer;
    transition: color 0.15s ease, background 0.15s ease, border-color 0.15s ease;
}

.conversation-controls .chime-toggle:hover {
    color: var(--ink);
    background: var(--panel);
    border-color: var(--border-strong);
}

.conversation-controls .chime-toggle:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

.conversation-controls .chime-toggle.is-muted {
    color: var(--neutral);
}

.chime-toggle-icon {
    display: inline-flex;
    color: var(--accent); /* the bell rings in the brand accent while sound is on */
}

.chime-toggle.is-muted .chime-toggle-icon {
    color: var(--neutral);
}

.chime-toggle-icon svg {
    display: block;
}

.report {
    margin-top: var(--space-6);
    font-size: var(--text-sm);
}

/* The report disclosure is a quiet secondary control, not a loud action. */
.report > summary {
    cursor: pointer;
    color: var(--muted);
}

.report > summary:hover {
    color: var(--ink);
}

code {
    overflow-wrap: anywhere;
}

.validation {
    color: #a3201b; /* readable error red on --bg */
}

/* ── "Save this link" — the finder's only way back (no account) ──────────────
   The bookmarkable thread URL, framed so it reads as something to keep. With no
   script it can't bookmark for them, so it presents the link clearly to save. */
.save-link {
    margin: 0 0 var(--space-5);
    padding: var(--space-3) var(--space-4);
    background: var(--card);
    border: 1px solid var(--border);
    border-left: 3px solid var(--accent);
    border-radius: 0 var(--radius) var(--radius) 0;
}

.save-link-label {
    margin: 0 0 var(--space-2);
    font-family: var(--font-mono);
    font-weight: 500;
    font-size: var(--text-xs);
    letter-spacing: var(--tracking-eyebrow);
    text-transform: uppercase;
    color: var(--accent-dark); /* AA on --card (5.3:1) */
}

.save-link-url {
    font-family: var(--font-mono);
    font-size: var(--text-sm);
    color: var(--ink);
    overflow-wrap: anywhere;
}

/* ── Optional "email me when they reply" (Code.cshtml, comp 02) ──────────────
   A distinct warm inline box so it reads as a quiet opt-in, not a required
   field. The owner never sees it (spec §10), as the help line states. */
.finder-callback {
    margin-top: var(--space-5);
    padding: var(--space-4);
    background: var(--accent-tint-warm);
    border: 1px solid var(--border);
    border-radius: var(--radius);
}

.finder-callback label {
    margin-top: 0;
}

.finder-callback input[type="email"] {
    background: var(--card);
}

.finder-callback .note {
    margin-bottom: 0;
}

/* ── Finder dead-ends & read-only notices ───────────────────────────────────
   Used as a full screen (no-longer-active / already-home / not-found) and as a
   single read-only line (closed/frozen threads). A calm paper card either way. */
/* The full-screen variant (no-longer-active / already-home / not-found) is a
   calm paper card. Scoped to section. so the inline status <p> below — same
   class — never inherits the card background, border, or radius. */
section.finder-notice {
    margin: var(--space-5) 0;
    padding: var(--space-6);
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    text-align: center;
}

section.finder-notice h1 {
    margin-bottom: var(--space-3);
}

section.finder-notice p {
    color: var(--muted);
}

section.finder-notice a {
    color: var(--accent-dark);
    font-weight: 600;
    text-decoration: none;
}

section.finder-notice a:hover {
    text-decoration: underline;
}

/* The inline read-only / status variant (closed/frozen threads) — one quiet
   centered line, not a card. */
p.finder-notice {
    margin: var(--space-5) 0;
    color: var(--muted);
    text-align: center;
}


/* ── Owner desktop chrome (issue #45) ───────────────────────────────────────
   The owner area is a desktop product (Direction A, comp A5/A6 ≈ 1040px), not
   the finder's narrow mobile column. The shared layout tags <body> with
   .owner-page on every authenticated page (OwnerPageModel); these rules widen
   the container and dress the chrome, while finder/auth pages keep the 32rem
   column above. Still server-rendered and script-free, like the finder path. */
.owner-page header,
.owner-page main,
.owner-page footer {
    max-width: 65rem; /* ≈1040px — the comp's desktop width */
}

/* Top nav bar — wordmark left, links + avatar right (comp A5). */
.owner-page header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    margin-top: var(--space-4);
    padding: var(--space-3) var(--space-5);
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
}

.owner-nav {
    display: inline-flex;
    align-items: center;
    gap: var(--space-5);
    margin: 0;
    font-family: var(--font-sans);
    font-size: var(--text-sm);
}

.owner-nav a {
    color: var(--muted);
    text-decoration: none;
}

.owner-nav a:hover {
    color: var(--ink);
}

/* Dashboard is the primary action — a tinted terracotta pill so it reads as the
   obvious home, with the other controls sitting quieter around it. */
.owner-nav a.owner-nav-primary {
    padding: var(--space-2) var(--space-4);
    border-radius: var(--radius-pill);
    background: var(--accent-tint);
    color: var(--accent-dark);
    font-weight: 600;
}

.owner-nav a.owner-nav-primary:hover {
    background: var(--accent);
    color: var(--on-accent);
}

/* "+ New code" lives in the header as a primary action (a POST that mints a code). The form is
   layout-transparent so the button sits inline with the nav links. */
.owner-nav-new-form {
    display: inline-flex;
    margin: 0;
}

/* A compact solid-terracotta pill — the bar's call to action. The appearance is styled in full here so it
   reads correctly even on the finder/auth pages an authenticated owner may visit (where the owner-page
   submit-button rule that would otherwise paint it doesn't apply). */
.owner-nav-new {
    display: inline-flex;
    align-items: center;
    font-family: var(--font-sans);
    font-weight: 600;
    font-size: var(--text-sm);
    color: var(--on-accent);
    background: var(--accent);
    border: 0;
    cursor: pointer;
}

.owner-nav-new:hover {
    background: var(--accent-dark);
}

/* Pill geometry, one source of truth: the bare class covers other pages, and the three-classes-deep
   selector carries the same values past the global submit-button rule (44px min-height, wider padding,
   square radius) on owner pages — so it can't drift between the two. */
.owner-nav-new,
.owner-page .owner-nav .owner-nav-new {
    min-height: 0;
    padding: var(--space-2) var(--space-4);
    border-radius: var(--radius-pill);
}

/* The Conversations link carries an unread count, so it lays out the text and badge in a row. */
.owner-nav-conversations {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
}

/* Unread count badge — a small terracotta pill, matching the dashboard's "Needs reply" flag, sized to
   sit comfortably against the nav text without enlarging the bar. */
.nav-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.25rem;
    height: 1.25rem;
    padding: 0 var(--space-2);
    border-radius: var(--radius-pill);
    background: var(--accent);
    color: var(--on-accent);
    font-size: var(--text-xs);
    font-weight: 700;
    line-height: 1;
}

button.link {
    border: 0;
    background: none;
    padding: 0;
    color: var(--muted);
    text-decoration: none;
    cursor: pointer;
    font: inherit;
}

button.link:hover {
    color: var(--ink);
}

/* Section wrappers. The dashboard and code detail span the full desktop width;
   the form/reading pages (account, new code, thread) stay in a comfortable
   reading column even inside the wide owner container. */
.owner-account,
.owner-code-new,
.owner-thread {
    max-width: 40rem;
    margin: 0 auto;
}

/* Solid terracotta button — primary owner action (also the finder CTA shape). */
a.button,
.owner-page button[type="submit"],
.owner-page .code-actions a.button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    min-height: 44px; /* tap target ≥44px (§8) */
    padding: var(--space-3) var(--space-5);
    font-family: var(--font-sans);
    font-weight: 600;
    font-size: var(--text-sm);
    color: var(--on-accent);
    background: var(--accent);
    border: 0;
    border-radius: var(--radius);
    text-decoration: none;
    cursor: pointer;
}

a.button:hover,
.owner-page button[type="submit"]:hover {
    background: var(--accent-dark);
}

/* A disabled submit (e.g. at the per-owner code cap, spec §6 §14.4) reads as inert, not actionable. */
.owner-page button[type="submit"]:disabled,
.owner-page button[type="submit"]:disabled:hover {
    background: var(--muted);
    cursor: not-allowed;
    opacity: 0.55;
}

/* Small usage line under the create-code button: "N of M codes used" (spec §6, §14.4). */
.code-quota {
    margin: var(--space-3) 0 0;
    color: var(--muted);
    font-size: var(--text-sm);
}

/* ── Dashboard (comp A5) ────────────────────────────────────────────────────
   Header row (title + count, "+ New" on the right) over a 3-up card grid. */
.owner-dashboard-head {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: var(--space-4);
    margin: var(--space-5) 0 var(--space-5);
}

.owner-dashboard-head h1 {
    margin: 0 0 var(--space-2);
    font-size: var(--text-2xl);
}

.owner-dashboard-sub {
    margin: 0;
    color: var(--muted);
    font-size: var(--text-sm);
}

/* The 3-up item grid. Collapses gracefully on narrower viewports. */
.code-grid {
    list-style: none;
    margin: 0 0 var(--space-7);
    padding: 0;
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--space-5);
}

@media (max-width: 60rem) {
    .code-grid {
        grid-template-columns: repeat(2, 1fr);
    }
}

@media (max-width: 40rem) {
    .owner-page header,
    .owner-page main,
    .owner-page footer {
        max-width: 32rem;
    }
    .code-grid {
        grid-template-columns: 1fr;
    }
}

.code-card {
    position: relative;
    background: var(--card);
    border: 1.5px solid var(--border);
    border-radius: var(--radius-lg);
}

/* A card with unread/open conversations is ringed in terracotta (comp). */
.code-card.has-new {
    border-color: var(--accent);
}

/* Recovered / disabled items recede — recessed surface, no pull (comp). */
.code-card.status-recovered,
.code-card.status-disabled {
    background: var(--panel);
    border-color: var(--border-strong);
}

.code-card-link {
    display: block;
    padding: var(--space-5);
    text-decoration: none;
    color: inherit;
}

/* "N new" badge — top-right pill (comp). */
.code-card-badge {
    position: absolute;
    top: var(--space-4);
    right: var(--space-4);
    padding: var(--space-1) var(--space-3);
    font-weight: 600;
    font-size: var(--text-xs);
    color: var(--on-accent);
    background: var(--accent);
    border-radius: var(--radius-pill);
}

.code-card-name {
    display: block;
    margin-bottom: var(--space-1);
    font-weight: 600;
    font-size: var(--text-lg);
    color: var(--ink);
}

.code-card-code {
    display: block;
    margin-bottom: var(--space-4);
    font-family: var(--font-mono);
    font-weight: 500;
    font-size: var(--text-sm);
    letter-spacing: var(--tracking-eyebrow);
    color: var(--muted);
}

.code-card-foot {
    display: flex;
    align-items: center;
    gap: var(--space-3);
}

.code-card-meta {
    margin-left: auto;
    font-size: var(--text-xs);
    color: var(--neutral);
}

/* ── Status dot + label (comp) ──────────────────────────────────────────────
   Markup emits `status-<state>` on the status span; the leading dot is drawn
   with ::before so no extra markup is needed. Colour is paired with the text
   label already in the markup (never colour alone — §8). */
.code-status,
.thread-status {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    font-family: var(--font-sans);
    font-weight: 500;
    font-size: var(--text-sm);
    text-transform: none;
    letter-spacing: 0;
    color: var(--muted);
}

.code-status::before,
.thread-status::before {
    content: "";
    flex: none;
    width: 7px;
    height: 7px;
    border-radius: var(--radius-pill);
    background: currentColor;
}

/* Live, healthy states read green; ended/closed states read neutral grey. */
.status-active,
.status-open {
    color: var(--success);
}

.status-recovered,
.status-disabled,
.status-closedbyowner,
.status-frozen {
    color: var(--neutral);
}

/* "Needs reply" — promoted from plain red text to a terracotta pill (§4). */
.flag {
    display: inline-flex;
    align-items: center;
    padding: var(--space-1) var(--space-3);
    font-weight: 600;
    font-size: var(--text-xs);
    color: var(--accent-dark);
    background: var(--accent-tint);
    border-radius: var(--radius-pill);
    white-space: nowrap; /* "Needs reply" stays on one line, even in the narrow summary sidebar */
}

.muted-flag {
    font-size: var(--text-xs);
    color: var(--neutral);
}

/* "Actively lost" — a terracotta pill on the code header, the owner-side counterpart to the finder's
   active-loss note (issue #51). Mirrors the "Needs reply" .flag treatment. */
.code-flag-lost {
    display: inline-flex;
    align-items: center;
    padding: var(--space-1) var(--space-3);
    font-weight: 600;
    font-size: var(--text-xs);
    color: var(--accent-dark);
    background: var(--accent-tint);
    border-radius: var(--radius-pill);
}

/* The one-line helper under the code's Manage actions explaining what active-loss does. */
.action-note {
    margin: var(--space-3) 0 0;
    font-size: var(--text-sm);
    color: var(--muted);
}

/* ── Recent activity / thread lists ─────────────────────────────────────────
   A calm, carded row list — the dashboard's recent activity. */
.owner-dashboard h2 {
    font-size: var(--text-xl);
    margin-bottom: var(--space-4);
}

.activity-list {
    list-style: none;
    margin: 0 0 var(--space-6);
    padding: 0;
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    overflow: hidden;
    background: var(--card);
}

.activity-item {
    border-bottom: 1px solid var(--border);
}

.activity-item:last-child {
    border-bottom: 0;
}

.activity-item.flagged {
    border-left: 3px solid var(--accent);
}

/* The whole row is one link, so the entire area is clickable — not just the name.
   The flex layout and padding live on the anchor so its hit area fills the row. */
.activity-item > a {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2) var(--space-4);
    padding: var(--space-4) var(--space-5);
    color: var(--ink);
    text-decoration: none;
    transition: background 0.15s ease;
}

/* :focus-visible mirrors :hover so keyboard users get the same full-row affordance. */
.activity-item > a:hover,
.activity-item > a:focus-visible {
    background: var(--panel);
}

/* The code's label leads the row in bold; it picks up the accent on hover/focus. */
.activity-item-name {
    font-weight: 600;
}

.activity-item > a:hover .activity-item-name,
.activity-item > a:focus-visible .activity-item-name {
    color: var(--accent-dark);
}

.preview {
    flex-basis: 100%;
    color: var(--muted);
    font-size: var(--text-sm);
}

.activity-item time {
    margin-left: auto;
    color: var(--neutral);
    font-size: var(--text-xs);
}

/* ── Code detail — main rail + compact conversations summary ─────────────────
   The code (QR, finder note, actions) is the page; conversations is now just a
   summary linking to the Inbox, so it sits in a narrow sidebar rather than
   claiming half the width (comp A6 paired it with a full thread list). The panel
   is capped to a focused width and centred, like the owner form pages. */
.owner-code-detail {
    margin-top: var(--space-5);
    max-width: 50rem;
    margin-inline: auto;
}

.owner-code-detail .back {
    margin: 0 0 var(--space-4);
}

.owner-code-detail .back a {
    color: var(--muted);
    text-decoration: none;
    font-size: var(--text-sm);
}

.code-detail-rail {
    padding: var(--space-6);
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    overflow: hidden;
}

.code-detail-rail .rail-head {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-3);
    margin-bottom: var(--space-2);
}

.code-detail-rail .rail-head h1 {
    margin: 0;
    font-size: var(--text-2xl);
}

.rail-section {
    margin-top: var(--space-5);
}

.rail-section > .eyebrow {
    display: block;
    margin-bottom: var(--space-3);
}

/* Code chip — QR thumbnail beside the canonical code and its thread count. */
.code-chip {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    padding: var(--space-3) var(--space-4);
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius);
}

.code-chip .canonical {
    font-family: var(--font-mono);
    font-weight: 500;
    font-size: var(--text-base);
    letter-spacing: var(--tracking-eyebrow);
    color: var(--ink);
}

.code-chip .chip-meta {
    margin-top: var(--space-1);
    font-size: var(--text-xs);
    color: var(--muted);
}

/* QR thumbnail — the code's real QR (generated by the /qr handler), shown beside
   the canonical code. A small white-matted tile so the dark modules read clearly. */
.qr-thumb {
    flex: none;
    width: 46px;
    height: 46px;
    border-radius: var(--radius-sm);
    background: #fff;
    border: 1px solid var(--border-strong);
    padding: 3px;
    box-sizing: border-box;
    image-rendering: pixelated; /* keep module edges crisp when the PNG is scaled */
}

/* Finder-facing note — the warm, serif-italic message shown on the tag. */
.finder-note {
    padding: var(--space-4);
    font-family: var(--font-serif);
    font-style: italic;
    font-size: var(--text-base);
    line-height: var(--leading-snug);
    color: var(--ink);
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius);
}

.finder-note.is-empty {
    font-style: normal;
    color: var(--muted);
}

/* Structured owner fields (Label / Reward) — quiet definition rows. */
.code-fields,
.account-fields {
    margin: var(--space-5) 0 0;
}

.code-fields dt,
.account-fields dt {
    font-family: var(--font-mono);
    font-weight: 500;
    font-size: var(--text-xs);
    letter-spacing: var(--tracking-eyebrow);
    text-transform: uppercase;
    color: var(--muted);
}

.code-fields dd,
.account-fields dd {
    margin: var(--space-1) 0 var(--space-4);
    color: var(--ink);
}

/* The sign-out controls (moved here from the header) sit side by side, wrapping on a narrow screen. */
.account-signout {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
}

/* "Edit label & message" link on the code detail rail (spec §11): a quiet secondary control that opens
   the dedicated setup editor — the single place a code's metadata is authored. */
.code-edit-link {
    margin: var(--space-4) 0 0;
    font-family: var(--font-sans);
    font-weight: 600;
    font-size: var(--text-sm);
}

.code-edit-link a {
    color: var(--accent);
    text-decoration: none;
}

.code-edit-link a:hover {
    text-decoration: underline;
}

/* Action cluster — primary (Mark recovered) plus quieter secondaries. */
.code-actions,
.thread-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    margin: var(--space-5) 0 0;
}

.code-actions form,
.thread-actions form {
    display: inline-flex;
    margin: 0;
}

/* Quiet/secondary owner buttons — tertiary actions sit below the terracotta
   primary so it stays the obvious next step. Marked with .secondary in markup;
   every button in .thread-actions is secondary too (the primary there is the
   reply composer's own Send button, which lives outside this cluster). */
.owner-page button.secondary,
.owner-page a.button.secondary,
.thread-actions button[type="submit"] {
    color: var(--muted);
    background: var(--card);
    border: 1.5px solid var(--border-strong);
}

.owner-page button.secondary:hover,
.owner-page a.button.secondary:hover,
.thread-actions button[type="submit"]:hover {
    color: var(--ink);
    background: var(--panel);
}

/* ── Conversations inbox ─────────────────────────────────────────────────────
   A messaging-app two-pane: the chat list (every conversation across all codes,
   newest first) beside the open conversation. Desktop shows both; below 52rem it
   becomes one pane at a time like a phone — the list, or the open thread with a
   back link. Still server-rendered and script-free (spec §13). */
.conversations-head {
    margin: var(--space-5) 0 var(--space-5);
}

.conversations-head h1 {
    margin: 0 0 var(--space-2);
    font-size: var(--text-2xl);
}

.conversations-sub {
    margin: 0;
    color: var(--muted);
    font-size: var(--text-sm);
}

.conversations-pane {
    display: grid;
    grid-template-columns: 22rem 1fr;
    gap: 0;
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    overflow: hidden;
    /* A fixed app-shell height so both columns share one height and each scrolls on its own — the
       left rail's border/background then always reaches the bottom, however long the open thread is.
       min-height is the floor on short viewports. The mobile layout below resets this to auto. */
    height: 75vh;
    min-height: 30rem;
}

/* Left rail — the chat list, scrolling within the pane's height. */
.conversation-list {
    border-right: 1px solid var(--border);
    overflow-y: auto;
}

.conversation-list ul {
    list-style: none;
    margin: 0;
    padding: 0;
}

.conversation-empty {
    padding: var(--space-6);
}

.conversation-row + .conversation-row {
    border-top: 1px solid var(--border);
}

/* A row waiting on the owner gets the terracotta edge used elsewhere for flags. */
.conversation-row.flagged {
    border-left: 3px solid var(--accent);
}

/* An unread conversation reads bolder, like a chat/mail list, and carries a terracotta dot before its
   name. The dot is the same accent used by the nav badge and "Needs reply" flag, so "new" looks the
   same everywhere. */
.conversation-row.is-unread .conversation-name {
    font-weight: 700;
    color: var(--ink);
}

.conversation-row.is-unread .conversation-preview {
    color: var(--ink);
}

.conversation-unread-dot {
    display: inline-block;
    width: 0.5rem;
    height: 0.5rem;
    margin-right: var(--space-2);
    border-radius: var(--radius-pill);
    background: var(--accent);
    vertical-align: middle;
}

.conversation-row > a {
    display: flex;
    gap: var(--space-3);
    align-items: flex-start;
    padding: var(--space-4);
    text-decoration: none;
    color: inherit;
}

.conversation-row > a:hover {
    background: var(--panel);
}

/* The open conversation is held lit in the list, like a desktop mail/chat client. */
.conversation-row.is-active > a {
    background: var(--accent-tint);
}

/* Round avatar swatch — the woven-tape motif from the code cards, in a disc. */
.conversation-swatch {
    flex: none;
    width: 38px;
    height: 38px;
    border-radius: var(--radius-pill);
    background: repeating-linear-gradient(
        135deg,
        var(--accent-tint) 0,
        var(--accent-tint) 6px,
        var(--accent-tint-warm) 6px,
        var(--accent-tint-warm) 12px
    );
}

.conversation-main {
    flex: 1 1 auto;
    min-width: 0; /* let the children truncate instead of overflowing the rail */
}

.conversation-row-top {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-2);
}

.conversation-name {
    font-weight: 600;
    color: var(--ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.conversation-row-top time {
    flex: none;
    color: var(--neutral);
    font-size: var(--text-xs);
}

/* One-line message preview — truncates with an ellipsis like a chat list. */
.conversation-preview {
    display: block;
    margin-top: var(--space-1);
    color: var(--muted);
    font-size: var(--text-sm);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.conversation-preview.is-empty {
    color: var(--neutral);
}

.conversation-row-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2) var(--space-3);
    margin-top: var(--space-2);
}

.conversation-row-meta .thread-status {
    font-size: var(--text-xs);
}

/* Right pane — the open conversation (the shared _ConversationDetail partial). Scrolls within the
   pane's height so a long thread never stretches the rail beside it. */
.conversation-detail {
    padding: var(--space-6);
    min-width: 0;
    overflow-y: auto;
}

.conversation-title {
    margin: 0 0 var(--space-4);
    font-size: var(--text-xl);
}

/* Empty-state prompt shown on desktop when no conversation is open. */
.conversation-placeholder {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 18rem;
    height: 100%;
    text-align: center;
}

/* "← All conversations" — only meaningful on the one-pane mobile layout. */
.back-mobile {
    display: none;
}

.back-mobile a {
    color: var(--muted);
    text-decoration: none;
    font-size: var(--text-sm);
}

@media (max-width: 52rem) {
    /* One pane at a time, full width, scrolling with the page — drop the desktop app-shell height
       AND its 30rem floor so the visible pane is exactly as tall as its content (no empty space on a
       short list/thread, no overflow in landscape) instead of a fixed viewport slice. */
    .conversations-pane {
        grid-template-columns: 1fr;
        height: auto;
        min-height: auto;
    }

    .conversation-list {
        border-right: 0;
        border-bottom: 1px solid var(--border);
    }

    .conversation-detail {
        overflow-y: visible;
    }

    /* One pane at a time: the list, or — once a conversation is open — the thread. */
    .conversations.has-selection .conversation-list {
        display: none;
    }

    .conversations:not(.has-selection) .conversation-detail {
        display: none;
    }

    .back-mobile {
        display: block;
        margin: 0 0 var(--space-4);
    }
}

/* ── Owner forms (new code, account) ────────────────────────────────────────
   Carded reading column with framed inputs in the Direction A field style. */
.owner-code-new,
.owner-account {
    padding: var(--space-6);
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    margin-top: var(--space-5);
}

.owner-code-new label,
.owner-account label,
.owner-thread form label,
.conversation-detail form label {
    display: block;
    margin: var(--space-4) 0 var(--space-2);
    font-family: var(--font-mono);
    font-weight: 500;
    font-size: var(--text-xs);
    letter-spacing: var(--tracking-eyebrow);
    text-transform: uppercase;
    color: var(--muted);
}

.owner-code-new input[type="text"],
.owner-code-new textarea,
.owner-thread form textarea,
.conversation-detail form textarea {
    display: block;
    width: 100%;
    padding: var(--space-3) var(--space-4);
    font: inherit;
    color: var(--ink);
    background: var(--card);
    border: 1.5px solid var(--border-strong);
    border-radius: var(--radius);
}

.owner-code-new textarea,
.owner-thread form textarea,
.conversation-detail form textarea {
    resize: vertical;
    line-height: var(--leading-snug);
}

.owner-code-new input::placeholder,
.owner-code-new textarea::placeholder,
.owner-thread form textarea::placeholder,
.conversation-detail form textarea::placeholder {
    color: var(--neutral);
}

.owner-code-new button[type="submit"],
.owner-thread form button[type="submit"],
.conversation-detail form button[type="submit"] {
    margin-top: var(--space-3);
}

.owner-code-new .back,
.owner-account .back {
    margin: var(--space-5) 0 0;
    font-size: var(--text-sm);
}

/* Destructive action — outlined, never the loud terracotta of a safe action. */
button.danger {
    min-height: 44px;
    padding: var(--space-3) var(--space-5);
    font-family: var(--font-sans);
    font-weight: 600;
    font-size: var(--text-sm);
    color: #8a2b1f; /* AA-safe danger red on --card */
    background: var(--card);
    border: 1.5px solid #d8b3a8;
    border-radius: var(--radius);
    cursor: pointer;
}

button.danger:hover {
    color: var(--on-accent);
    background: #8a2b1f;
    border-color: #8a2b1f;
}

/* Notices. Confirmations read calm-green; alerts reuse .form-error above. */
.form-notice {
    color: #1f5130; /* readable confirmation green */
    background: #e8efe3;
    border-radius: var(--radius-sm);
    padding: var(--space-2) var(--space-3);
}

/* Owner-thread page — status line, reply link, read-only notice. */
.owner-thread .back {
    margin: 0 0 var(--space-4);
    font-size: var(--text-sm);
}

.owner-thread .thread-status {
    margin: 0 0 var(--space-4);
}

/* Generic small-print classes (also used by the standalone admin view). */
.metric {
    font-size: var(--text-2xl);
    font-weight: 600;
    color: var(--ink);
}

.muted {
    color: var(--muted);
}

/* ── Printable QR labels (issue #54, spec §12/§15) ───────────────────────────
   The three Direction A label designs (comp 05–07) plus the print stylesheet.
   On screen: a preview with a design switcher. In print (@media print, below):
   only the .label-sheet survives, so "Save as PDF" yields a clean tag sheet. */
.label-page-chrome {
    margin-bottom: var(--space-6);
}

.label-page-chrome .back {
    margin: 0 0 var(--space-4);
    font-size: var(--text-sm);
}

.label-howto {
    max-width: 46rem;
    font-size: var(--text-sm);
}

.label-howto code {
    font-family: var(--font-mono);
    color: var(--ink);
}

/* Configurator — one calm card: chip toggles (types), a segmented control (size), and switch toggles
   (QR / web address). A GET form so the configured sheet stays shareable; owner.js re-fetches the
   preview on every change and intercepts "Print" to open the print dialog on the PDF. */
.label-config {
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
    max-width: 44rem;
    margin-top: var(--space-4);
    padding: var(--space-5);
    background: var(--card);
    border: 1.5px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
}

.label-config-group {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

/* Size + toggles sit side by side on wide screens, stack on narrow. */
.label-config-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-6);
}

.label-config-label {
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: var(--tracking-eyebrow);
    text-transform: uppercase;
    color: var(--eyebrow);
}

.label-config-hint {
    margin: 0;
    font-size: var(--text-xs);
    color: var(--muted);
}

/* The real inputs drive state but are visually replaced by the styled chips/segments/switches. */
.label-chip input,
.label-seg input,
.label-ink input,
.label-switch > input[type="checkbox"] {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    pointer-events: none;
}

/* Type chips — pill toggles that fill terracotta when selected. */
.label-chip-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}

.label-chip {
    display: inline-flex;
    align-items: center;
    padding: 0.45rem 0.95rem;
    border: 1.5px solid var(--border-strong);
    border-radius: var(--radius-pill);
    background: var(--bg);
    color: var(--muted);
    font-size: var(--text-sm);
    font-weight: 500;
    cursor: pointer;
    user-select: none;
    transition: background 0.12s ease, color 0.12s ease, border-color 0.12s ease;
}

.label-chip:hover {
    color: var(--ink);
    border-color: var(--accent);
}

.label-chip:has(input:checked) {
    background: var(--accent);
    border-color: var(--accent);
    color: var(--on-accent);
}

.label-chip:has(input:focus-visible) {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* Size — a segmented control (connected pills on a recessed track). */
.label-segmented {
    display: inline-flex;
    flex-wrap: wrap; /* the size options stay one row when they fit, wrapping on narrow screens */
    gap: 2px;
    padding: 3px;
    background: var(--panel);
    border-radius: var(--radius-pill);
}

.label-seg {
    position: relative;
    cursor: pointer;
}

.label-seg span {
    display: block;
    padding: 0.35rem 0.95rem;
    border-radius: var(--radius-pill);
    font-size: var(--text-sm);
    color: var(--muted);
    transition: background 0.12s ease, color 0.12s ease;
}

.label-seg:has(input:checked) span {
    background: var(--card);
    color: var(--ink);
    box-shadow: var(--shadow-sm);
}

.label-seg:has(input:focus-visible) span {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* Toggle switches — QR / web address. */
.label-switch-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-5);
}

.label-switch {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-sm);
    color: var(--ink);
    cursor: pointer;
}

.label-switch-track {
    position: relative;
    flex: none;
    width: 38px;
    height: 22px;
    border-radius: var(--radius-pill);
    background: var(--border-strong);
    transition: background 0.15s ease;
}

.label-switch-track::after {
    content: "";
    position: absolute;
    top: 2px;
    left: 2px;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: #fff;
    box-shadow: var(--shadow-sm);
    transition: transform 0.15s ease;
}

.label-switch:has(input:checked) .label-switch-track {
    background: var(--accent);
}

.label-switch:has(input:checked) .label-switch-track::after {
    transform: translateX(16px);
}

.label-switch:has(input:focus-visible) .label-switch-track {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* Ink — round colour swatches (one per LabelInk); the chosen one carries a ring. The colour applies to
   the QR modules (re-encoded server-side) and the code text (via --label-ink on the sheet). */
.label-ink-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}

.label-ink {
    display: inline-flex;
    cursor: pointer;
}

.label-ink-swatch {
    display: block;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    border: 2px solid var(--card);
    box-shadow: 0 0 0 1.5px var(--border-strong);
    transition: box-shadow 0.12s ease, transform 0.12s ease;
}

.label-ink:hover .label-ink-swatch {
    box-shadow: 0 0 0 1.5px var(--accent);
}

.label-ink:has(input:checked) .label-ink-swatch {
    box-shadow: 0 0 0 2px var(--ink);
    transform: scale(1.08);
}

.label-ink:has(input:focus-visible) .label-ink-swatch {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* Action row — the primary "Print" and a quiet note. */
.label-config-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    align-items: center;
}

.label-config-note {
    font-size: var(--text-xs);
    color: var(--muted);
}

/* The sheet of repeated labels. Flex-wrap so it reflows; each label avoids a
   page break so it never splits across printed pages. */
.label-sheet {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-5);
    align-items: flex-start;
}

.label-sheet > * {
    break-inside: avoid;
    page-break-inside: avoid; /* legacy spelling for older print engines */
}

/* Size scales the whole tile in the preview (the PDF lays out a denser/looser grid). zoom reflows the
   flex wrap, unlike transform: scale, so the sheet stays tightly packed at any size. */
.label-sheet.size-small > * {
    zoom: 0.78;
}

.label-sheet.size-large > * {
    zoom: 1.22;
}

/* Avery 8293 is a sheet of small 1½″ round labels, so the preview tiles read smaller than "Small". */
.label-sheet.size-avery8293 > * {
    zoom: 0.62;
}

/* Avery 35523 is a sheet of larger 2″×4″ rectangular labels, so the preview tiles read a touch larger. */
.label-sheet.size-avery35523 > * {
    zoom: 1.1;
}

/* When the QR is off the re-fetched sheet just omits the QR markup and carries a .qr-hidden marker; this
   rule is a belt-and-suspenders hide for any QR node that lingers mid-swap. */
.label-sheet.qr-hidden .label-qr {
    display: none;
}

/* Same belt-and-suspenders for the code toggle: the server omits the code markup and marks the sheet. */
.label-sheet.code-hidden .label-code {
    display: none;
}

/* The owner's ink option (?ink=) lands as an inline --label-ink on the sheet — set only for a
   non-default ink, so each design's own palette holds otherwise. It recolours the code text on the
   dark-on-light designs (the QR is re-encoded server-side in the same colour); the cream-on-terracotta
   text (luggage tag, clay stickers) keeps its design colour, where a dark ink would vanish. */

/* Shared finder-URL line printed beside the code (ifyoufind.me/XXXX-XXXX). Mono and quiet so it reads
   as the "where to go" under the prominent code. */
.label-url,
.lt-url,
.st-url,
.pt-url,
.bs-url,
.wc-url {
    font-family: var(--font-mono);
    font-size: 9px;
    letter-spacing: 0.01em;
    word-break: break-all;
}

/* The QR itself: the SVG is viewBox-sized, so it fills whatever box it sits in. */
.label-qr {
    line-height: 0;
}

.label-qr svg {
    display: block;
    width: 100%;
    height: auto;
}

/* 05 · Luggage tag — terracotta card, cream ink, prominent QR. */
.lt {
    width: 188px;
    background: var(--accent);
    border-radius: 18px;
    padding: 22px 20px 24px;
    box-shadow: 0 10px 24px -10px rgba(120, 60, 30, 0.6);
    position: relative;
    text-align: center;
}

.lt-hole {
    display: block;
    width: 26px;
    height: 26px;
    border: 4px solid var(--bg);
    border-radius: 50%;
    margin: 0 auto 14px;
}

.lt-qr {
    background: var(--card);
    border-radius: 10px;
    padding: 12px;
    margin-bottom: 12px;
}

.lt-code {
    font-family: var(--font-mono);
    font-weight: 500;
    font-size: 16px;
    letter-spacing: 0.12em;
    color: var(--card);
}

.lt-tagline {
    font-size: 10px;
    color: #f3cdb8;
    margin-top: 8px;
}

/* 06 · Sticker set — round two-tone stickers, alternating paper / clay. */
.label-sheet.design-sticker {
    max-width: 460px;
}

.st {
    width: 150px;
    height: 150px;
    border-radius: 50%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: 14px;
    box-sizing: border-box;
}

.st.paper {
    background: var(--bg);
    border: 1.5px solid var(--border);
}

.st.clay {
    background: var(--accent);
}

.st-qr {
    width: 58px;
    background: var(--card);
    border-radius: 6px;
    padding: 4px;
    margin-bottom: 6px;
}

.st-code {
    font-family: var(--font-mono);
    font-weight: 500;
    font-size: 12px;
    letter-spacing: 0.06em;
}

.st.paper .st-code {
    color: var(--label-ink, var(--ink));
}

.st.clay .st-code {
    color: var(--card);
}

/* 07 · Pet collar tag — round disc, warm gradient, "scan to reach my human". */
.pt {
    width: 168px;
    height: 168px;
    border-radius: 50%;
    background: radial-gradient(circle at 35% 30%, #fbe9da, #e9b694 70%);
    border: 3px solid #d9a787;
    box-shadow: inset 0 2px 6px rgba(255, 255, 255, 0.6), 0 8px 18px -8px rgba(120, 60, 30, 0.5);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: 18px;
    box-sizing: border-box;
    position: relative;
}

.pt-hole {
    display: block;
    width: 13px;
    height: 13px;
    border: 2.5px solid #b9805e;
    border-radius: 50%;
    margin-bottom: 4px;
}

.pt-qr {
    width: 56px;
    background: var(--card);
    border-radius: 6px;
    padding: 4px;
    margin-bottom: 5px;
}

.pt-code {
    font-family: var(--font-mono);
    font-weight: 500;
    font-size: 13px;
    letter-spacing: 0.08em;
    color: var(--label-ink, #5c3a26);
}

.pt-tagline {
    font-size: 8.5px;
    color: #9a5230;
    margin-top: 5px;
    max-width: 96px;
}

/* Per-design finder-URL colours. The URL is the QR-less fallback, so it takes each design's
   highest-contrast text colour (its own code colour) rather than the dimmer tagline tint — as legible
   as the brand terracotta allows (size, not a faint colour, keeps it secondary to the code). */
.lt-url {
    color: var(--card);
    margin-top: 4px;
}

.st-url {
    font-size: 8px;
    margin-top: 3px;
    max-width: 100%;
}

.st.paper .st-url {
    color: var(--ink);
}

.st.clay .st-url {
    color: var(--card);
}

.pt-url {
    color: #5c3a26;
    font-size: 8px;
    margin-top: 3px;
    max-width: 128px;
}

/* Basic — a plain rectangular label: optional QR, code, finder URL. "Just the basics," no tag styling,
   no brand wordmark (the URL carries it). The most economical option. */
.bs {
    width: 188px;
    box-sizing: border-box;
    background: var(--card);
    border: 1.5px solid var(--border-strong);
    border-radius: var(--radius-sm);
    padding: 18px 16px;
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
}

.bs-qr {
    width: 96px;
    background: var(--card);
    margin-bottom: 10px;
}

.bs-code {
    font-family: var(--font-mono);
    font-weight: 500;
    font-size: 16px;
    letter-spacing: 0.12em;
    color: var(--label-ink, var(--ink));
}

.bs-url {
    color: var(--muted);
    margin-top: 6px;
}

/* Wallet card — a credit-card-proportioned insert for a wallet, bag pocket, or laptop sleeve. QR beside
   the code/URL, a short tagline below. */
.wc {
    width: 280px;
    box-sizing: border-box;
    background: var(--card);
    border: 1.5px solid var(--accent);
    border-radius: 12px;
    padding: 16px;
    box-shadow: var(--shadow-sm);
}

.wc-main {
    display: flex;
    align-items: center;
    gap: 14px;
}

.wc-qr {
    width: 64px;
    flex: none;
    background: var(--card);
}

.wc-text {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 3px;
    min-width: 0;
}

.wc-code {
    font-family: var(--font-mono);
    font-weight: 500;
    font-size: 17px;
    letter-spacing: 0.1em;
    color: var(--label-ink, var(--ink));
}

.wc-url {
    color: var(--muted);
}

.wc-tagline {
    margin-top: 10px;
    font-size: 9px;
    color: var(--muted);
}

/* Print: strip every chrome element so the page is just the tag sheet. The owner
   prints to PDF or paper from here. No app today carries any other @media print
   rules — these are scoped tightly to the label sheet. */
@media print {
    /* Drop the warm page background so tags print on white without wasting ink. */
    body {
        background: #fff;
    }

    body > header,
    body > footer,
    .label-page-chrome {
        display: none !important;
    }

    main {
        margin: 0;
        padding: 0;
        max-width: none;
    }

    .label-sheet {
        gap: 16px;
    }

    /* Keep the colored tag fills when printing (owners expect the terracotta). */
    .lt,
    .st,
    .pt,
    .bs,
    .wc {
        -webkit-print-color-adjust: exact;
        print-color-adjust: exact;
    }

    /* Size scaling is a preview affordance only; the page-print fallback uses the unscaled tags. */
    .label-sheet.size-small > *,
    .label-sheet.size-large > *,
    .label-sheet.size-avery8293 > *,
    .label-sheet.size-avery35523 > * {
        zoom: 1;
    }
}

/* ---------------------------------------------------------------------------
   Code-authoring UX: the setup-screen form, suggestion chips, character counters,
   the collapsible finder preview, the detail-page finder URL + print CTA, and the
   dashboard welcome/empty state. Progressively enhanced by wwwroot/js/owner.js.
   --------------------------------------------------------------------------- */

/* One-tap label suggestions. */
.suggest-chips {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin: 0 0 var(--space-3);
}

.suggest-chips .chip {
    padding: var(--space-1) var(--space-3);
    font-family: var(--font-sans);
    font-size: var(--text-sm);
    color: var(--accent-dark);
    background: var(--accent-tint);
    border: 1px solid transparent;
    border-radius: var(--radius-pill);
    cursor: pointer;
}

.suggest-chips .chip:hover {
    border-color: var(--accent);
}

/* Live character counter appended after a [data-char-count] field. */
.char-count {
    display: block;
    margin-top: var(--space-1);
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    color: var(--neutral);
    text-align: right;
}

.char-count.is-full {
    color: var(--accent-dark);
}

/* The finder preview, demoted to a quiet disclosure on the setup screen (issue: signup UX): a calm,
   underlined "unimportant link" by default that reveals the "what a finder sees" card only on demand,
   instead of a card competing with the form. */
.finder-preview-disclosure {
    margin: var(--space-4) 0;
}

.finder-preview-disclosure > summary {
    display: inline-block;
    cursor: pointer;
    font-family: var(--font-sans);
    font-size: var(--text-sm);
    color: var(--muted);
    text-decoration: underline;
    list-style: none;
}

.finder-preview-disclosure > summary::-webkit-details-marker {
    display: none;
}

.finder-preview-disclosure > summary:hover {
    color: var(--ink);
}

.finder-preview-disclosure[open] > summary {
    margin-bottom: var(--space-3);
}

.finder-preview-card {
    padding: var(--space-5);
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
}

.finder-preview-brand {
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    color: var(--accent-dark);
}

.finder-preview-card h2 {
    margin: var(--space-2) 0 var(--space-3);
    font-family: var(--font-serif);
    font-size: var(--text-xl);
    line-height: var(--leading-tight);
}

.finder-preview-card .owner-message.is-empty {
    color: var(--muted);
    font-style: italic;
}

/* Honour the owner's line breaks and wrap long unbroken tokens — in the live previews AND the real
   finder landing (both use .owner-message), so the preview matches exactly what a finder sees. */
.owner-message,
.finder-note,
[data-preview-target] {
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.finder-preview-box {
    margin-top: var(--space-4);
    padding: var(--space-3) var(--space-4);
    color: var(--neutral);
    background: var(--bg);
    border: 1.5px solid var(--border-strong);
    border-radius: var(--radius);
}

.finder-preview-btn {
    margin-top: var(--space-3);
    padding: var(--space-2) var(--space-4);
    font-weight: 600;
    font-size: var(--text-sm);
    text-align: center;
    color: var(--on-accent);
    background: var(--accent);
    border-radius: var(--radius);
}

/* The setup screen: the inline "your code is ready" chip and the quiet "skip for now" link. */
.code-inline {
    font-family: var(--font-mono);
    font-weight: 500;
    letter-spacing: var(--tracking-eyebrow);
    color: var(--accent-dark);
}

.code-setup-skip {
    margin: var(--space-4) 0 0;
    font-size: var(--text-sm);
}

.code-setup-skip a {
    color: var(--muted);
    text-decoration: underline;
}

.code-setup-skip a:hover {
    color: var(--ink);
}

/* Detail page: the "add this to your item" instruction and the "print a label" action. */
.finder-hint {
    margin: var(--space-3) 0 0;
    font-size: var(--text-sm);
    color: var(--muted);
}

/* The code address itself is monospace so it reads as a literal thing to copy onto the item. */
.finder-hint-url {
    font-family: var(--font-mono);
    color: var(--accent-dark);
}

/* Content-width, not full-bleed: one action among the rail's controls, sized to its label. */
.code-print-cta {
    margin-top: var(--space-4);
}

/* The lifecycle actions are secondary chrome under a quiet "Manage" eyebrow. */
.code-actions > .eyebrow {
    display: block;
    margin-bottom: var(--space-2);
}

/* Account page default-message form spacing. */
.account-default-message {
    margin-bottom: var(--space-5);
}

/* Dashboard empty state — teach the concept, then the 1-2-3, then the CTA. */
.empty-state {
    max-width: 42rem;
    padding: var(--space-6);
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
}

.empty-state h2 {
    margin: 0 0 var(--space-3);
    font-family: var(--font-serif);
}

.empty-steps {
    margin: var(--space-4) 0 var(--space-5);
    padding-left: var(--space-5);
    display: grid;
    gap: var(--space-2);
    line-height: var(--leading-snug);
}

/* The dashboard "+ New code" button is a POST form; keep it laying out like the link it replaced so the
   header row's baseline alignment is unchanged. */
.dashboard-new-code {
    margin: 0;
}

/* First-run welcome: the auto-created starter code, surfaced inside "Tag your first thing" so the owner
   sees the real code they're about to name and print. */
.first-run-code {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin: var(--space-4) 0;
    padding: var(--space-4);
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius);
}

.first-run-code .code-card-code {
    margin: 0;
}
