/* Website Stylesheet */

:root {
    --spacer: 2rem;
    /* Surfaces: rounded rect (cards, panels) — Arland's house radius. */
    --bubble-radius: 2rem;
    /* Buttons: true pill, ( DELETE ) not [ DELETE ]. A fixed rem value
       only looks like a pill while the button happens to be short enough;
       this stays semicircular at any height. */
    --pill-radius: 999px;
    /* Fields and list rows — inputs, selects, textareas, document rows.
       One token so they can't drift apart. */
    --field-radius: 0.5rem;

    /* Field metrics, all rem so the box height is arithmetic rather than
       whatever the font happens to produce. The only px is the border:
       hairlines shouldn't scale with text size. */
    --field-pad-y: 0.75rem;
    --field-line: 1.5rem;
    --field-border: 1px;
    /* padding top + bottom + one line + border top and bottom */
    --field-height: calc((var(--field-pad-y) * 2) + var(--field-line) + (var(--field-border) * 2));
}

.ai-only {
    display: none;
}

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

html {
    font-size: 15px;
    height: 100%;
}

body {
    font-family:
        -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu,
        Cantarell, sans-serif;
    font-size: 15px;
    line-height: 1.6;
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

.container {
    max-width: 1200px;
    margin: 0 auto;
    padding: 0 var(--spacer);
    /* body is a flex column, so this is a flex item: without min-width it
       refuses to shrink below its content and pushes the page sideways. */
    min-width: 0;
    width: 100%;
}

a {
    color: var(--complement);
    text-decoration: none;
}

a:hover {
    text-decoration: underline;
}

/* TYPOGRAPHY - Simple and consistent */

h1, h2, h3, h4, h5, h6 {
    color: var(--text-primary);
    font-weight: 600;
    line-height: 1.3;
    margin-bottom: 1rem;
    margin-top: 0;
}

h1 {
    font-size: 2rem;
}

h2 {
    font-size: 1.5rem;
}

h3 {
    font-size: 1.25rem;
}

h4, h5, h6 {
    font-size: 1rem;
}

.docs-section p {
    color: var(--text-secondary);
    margin-bottom: var(--spacer);
}

.docs-section pre {
    line-height: 1.25;
}

.docs-section pre code {
    font-size: 1rem;
}

.docs-section a {
    color: var(--complement);
    text-decoration: none;
    transition: opacity 0.2s;
}

.docs-section a:hover {
    opacity: 0.8;
    text-decoration: underline;
}

.docs-section ul,
ol {
    margin-bottom: var(--spacer);
    margin-left: 1.5rem;
    color: var(--text-secondary);
}

.docs-section li {
    list-style-position: outside;
    padding-left: 0.5rem;
    text-indent: 0;
    position: relative;
}

.docs-section li code:first-of-type {
    margin-right: 0.5rem;
}

/*
.docs-section li::before {
  content: "•";
  position: absolute;
  left: 0;
}
 */
/*
.docs-section li:not(:last-child) {
  margin-bottom: 0.5rem;
}
 */

.docs-section hr {
    border: none;
    border-top: 1px solid var(--border);
    margin: calc(var(--spacer) * 2) 0;
}

/* TABLES */
table {
    width: 100%;
    border-collapse: collapse;
    margin: var(--spacer) 0;
    background-color: var(--bg-primary);
    border: 1px solid var(--border);
    border-radius: 0.5rem;
    overflow: hidden;
}

table thead {
    background-color: var(--bg-tertiary);
}

table th {
    padding: 0.75rem 1rem;
    text-align: left;
    font-weight: 600;
    color: var(--text-primary);
    border-bottom: 1px solid var(--border);
}

table td {
    padding: 0.75rem 1rem;
    color: var(--text-secondary);
    border-bottom: 1px solid var(--border);
}

table tr:last-child td {
    border-bottom: none;
}

table tbody tr:hover {
    background-color: var(--bg-secondary);
    transition: background-color 0.15s ease;
}

/* NAV RAIL

   One shell for the control plane and for every bot server: a rail down
   the left on desktop, a drawer behind a hamburger below 60rem. See
   nav.du, which is copied verbatim between the two repos.

   The drawer is `:target` and nothing else — #rail opens it, following any
   link closes it, Back dismisses it. There is no state to script and so no
   state that can jam. */

/* body is already a flex column with min-height 100vh, so the shell is a
   flex item that fills it rather than a second copy of those rules. */
.app-shell {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
}

.rail {
    display: flex;
    flex-direction: column;
    gap: 1.25rem;
    background-color: var(--bg-secondary);
    border-right: 1px solid var(--border);
    padding: 1.25rem 1rem;
}

/* Pushes the account block to the bottom however short the link list is. */
.rail-body {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
}

.rail-foot {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    border-top: 1px solid var(--border);
    padding-top: 0.75rem;
}

.rail-group {
    list-style: none;
    margin: 0 0 1rem 0;
    padding: 0;
}

.rail-group + .rail-group {
    border-top: 1px solid var(--border);
    padding-top: 1rem;
}

.rail-group li {
    margin: 0;
}

.rail-link {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    padding: 0.5rem 0.65rem;
    border-radius: 0.5rem;
    color: var(--complement);
    font-weight: 500;
    text-decoration: none;
}

.rail-link:hover {
    background-color: var(--bg-tertiary);
    color: var(--text-primary);
    text-decoration: none;
}

/* The current page, marked by aria-current rather than a class: which page
   you are on is a fact about the document, so the attribute is the source
   of truth and the styling reads off it. */
.rail-link[aria-current="page"] {
    background-color: var(--bg-tertiary);
    color: var(--text-primary);
    font-weight: 600;
}

.rail-icon {
    width: 1.25rem;
    height: 1.25rem;
    flex: 0 0 auto;
}

/* A page this person's permissions don't reach. Shown rather than hidden,
   so the rail doesn't change shape between colleagues and it stays clear
   the page exists and is closed to them. */
.rail-link.is-disabled {
    color: var(--text-muted);
    opacity: 0.5;
    cursor: not-allowed;
}

/* What this panel is about, when nothing is switchable: one org on
   the control plane, the bot's name on a bot server. Every bot server
   looks identical, so this is what tells four open tabs apart. */
.rail-context {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    margin: 0;
    padding: 0 0.65rem;
    min-width: 0;
}

.rail-eyebrow {
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.rail-context-name {
    font-weight: 600;
    color: var(--text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Sign-out with no account menu to live in — a bot server holds no
   accounts, so it gets a row of its own. */
.rail-signout {
    flex: 1 1 auto;
    background: none;
    border: 1px solid var(--border);
    color: var(--text-secondary);
    font: inherit;
    font-weight: 500;
    padding: 0.45rem 0.75rem;
    border-radius: 0.5rem;
    cursor: pointer;
    text-align: left;
}

.rail-signout:hover {
    background-color: var(--bg-tertiary);
    color: var(--text-primary);
}

/* The avatar control on /account. Bigger than the rail's, because here it
   is the thing being edited rather than a label. */
.avatar-lg {
    width: 4rem;
    height: 4rem;
    font-size: 1.4rem;
}

.avatar-control {
    display: flex;
    align-items: center;
    gap: 1rem;
}

.avatar-actions {
    display: flex;
    gap: 0.5rem;
}

/* ---- disclosures (switcher, account menu) ----
   Both are <details>. The browser owns open, close, Escape and focus, and
   they keep working with no script on the page at all. */

.switcher,
.account-menu {
    position: relative;
}

.switcher > summary,
.account-menu > summary {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.5rem 0.65rem;
    border-radius: 0.5rem;
    cursor: pointer;
    list-style: none;
    color: var(--text-primary);
}

/* Safari still draws its own triangle without this. */
.switcher > summary::-webkit-details-marker,
.account-menu > summary::-webkit-details-marker {
    display: none;
}

.switcher > summary:hover,
.account-menu > summary:hover {
    background-color: var(--bg-tertiary);
}

.switcher-label {
    flex: 1 1 auto;
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.rail-caret {
    width: 1rem;
    height: 1rem;
    flex: 0 0 auto;
    color: var(--text-muted);
}

.switcher-menu,
.account-list {
    list-style: none;
    margin: 0.25rem 0 0 0;
    padding: 0.35rem;
    background-color: var(--bg-primary);
    border: 1px solid var(--border);
    border-radius: 0.6rem;
    box-shadow: 0 8px 24px var(--shadow-color);
}

.switcher-menu li,
.account-list li {
    margin: 0;
}

.switcher-menu a,
.account-list a,
.account-signout {
    display: block;
    width: 100%;
    padding: 0.45rem 0.6rem;
    border-radius: 0.4rem;
    color: var(--text-secondary);
    text-decoration: none;
    text-align: left;
}

.switcher-menu a:hover,
.account-list a:hover,
.account-signout:hover {
    background-color: var(--bg-tertiary);
    color: var(--text-primary);
    text-decoration: none;
}

.switcher-menu a[aria-current="true"] {
    color: var(--text-primary);
    font-weight: 600;
}

/* A form control that has to read as a menu row, so it gives up every
   button default rather than inheriting the pill treatment. */
.account-signout {
    background: none;
    border: none;
    font: inherit;
    font-weight: 400;
    cursor: pointer;
    border-radius: 0.4rem;
}

.account-menu > summary {
    flex: 1 1 auto;
    min-width: 0;
}

.account-name {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    line-height: 1.2;
}

.account-name strong,
.account-detail {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.account-detail {
    font-size: 0.75rem;
    color: var(--text-muted);
}

/* The account menu is the last thing in the rail, so it opens upward —
   downward would render it off the bottom of the viewport. */
.account-menu > .account-list {
    position: absolute;
    bottom: calc(100% + 0.25rem);
    left: 0;
    right: 0;
    z-index: 120;
}

.avatar {
    width: 2rem;
    height: 2rem;
    flex: 0 0 auto;
    border-radius: 50%;
    object-fit: cover;
    background-color: var(--bg-tertiary);
}

/* Drawn rather than fetched, so a provider URL that has rotted shows a
   face instead of a broken image in the corner of every page. */
.avatar-initials {
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.8rem;
    font-weight: 700;
    color: white;
    background-color: var(--primary);
}

/* Reachable by keyboard, out of the way otherwise. It is the first thing
   in the document, so it is also what the scrim targets to close. */
.skip-link {
    position: absolute;
    left: -9999px;
    z-index: 400;
}

.skip-link:focus {
    left: 0.5rem;
    top: 0.5rem;
    padding: 0.5rem 0.9rem;
    background-color: var(--bg-primary);
    border: 1px solid var(--border);
    border-radius: 0.4rem;
}

.nav-brand {
    display: inline-flex;
    align-items: center;
    gap: 0.75rem;
    font-size: 1.5rem;
    font-weight: bold;
    color: var(--primary);
    cursor: pointer;
    text-decoration: none;
    transition: opacity 0.2s;
}

.nav-brand:hover {
    opacity: 0.8;
}

.nav-brand:hover,
.nav-brand:hover h1 {
    text-decoration: none !important;
}

.nav-brand.logo {
    width: 120px;
    height: 40px;
    background-size: contain;
    background-repeat: no-repeat;
    background-position: left center;
}

.nav-brand.logo h1 {
    color: transparent;
    margin: 0;
    font-size: inherit;
}

[data-theme="light"] .nav-brand.logo {
    background-image: url("/img/logo-black.png");
}

[data-theme="dark"] .nav-brand.logo {
    background-image: url("/img/logo-white.png");
}

[data-theme="auto"] .nav-brand.logo {
    background-image: url("/img/logo-white.png");
}

/* The mobile header. Carries the hamburger and the brand and nothing
   else — everything else is a row in the drawer, where it has room for a
   label. Hidden entirely on desktop, where the rail is always open. */
.topbar {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.75rem var(--spacer);
    background-color: var(--bg-secondary);
    border-bottom: 1px solid var(--border);
    position: sticky;
    top: 0;
    z-index: 100;
}

.topbar .nav-brand {
    font-size: 1.25rem;
}

.drawer-toggle {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0.35rem;
    border-radius: 0.4rem;
    color: var(--text-primary);
}

.drawer-toggle:hover {
    background-color: var(--bg-tertiary);
}

.drawer-icon {
    width: 1.6rem;
    height: 1.6rem;
}

/* Covers the page while the drawer is open, and closes it when clicked.
   An anchor rather than a div because closing is "go to another target",
   which is the whole of the drawer's state. */
.rail-scrim {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 290;
    background-color: rgba(0, 0, 0, 0.5);
}

.theme-toggle {
    background: none;
    border: none;
    cursor: pointer;
    padding: 0.5rem;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* theme-toggle.js shows the one matching the current theme. */
.theme-icon {
    display: none;
    width: 1.5rem;
    height: 1.5rem;
    color: var(--complement);
    transition:
        color 0.3s,
        transform 0.1s cubic-bezier(0.175, 0.885, 0.32, 1.275);
    position: absolute;
}

.theme-toggle:hover .theme-icon {
    color: var(--text-primary);
    transform: scale(1.1);
}


.tagline {
    font-size: 110%;
    color: var(--text-secondary);
    margin-bottom: var(--spacer);
    line-height: 1.5;
}

.btn {
    padding: 0.875rem var(--spacer);
    font-size: 1rem;
    font-weight: 600;
    border-radius: var(--bubble-radius);
    border: none;
    cursor: pointer;
    transition:
        filter 0.1s,
        transform 0.1s;
    text-decoration: none;
    display: inline-block;
}

.btn-primary {
    background-color: var(--primary);
    color: white;
}

.btn-primary:hover {
    filter: brightness(var(--hover-brightness));
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
    transform: scale(1.05);
}


/* RESPONSIVE

   60rem is where the rail stops being a drawer and becomes a sidebar. It
   is expressed in rem deliberately: someone running a large system font
   wants the drawer for longer, because their content column is narrower
   at the same pixel width. */

/* ---- below 60rem: the rail is a drawer ---- */
@media (max-width: 59.999rem) {
    .rail {
        position: fixed;
        top: 0;
        bottom: 0;
        left: 0;
        z-index: 300;
        width: min(19rem, 84vw);
        transform: translateX(-100%);
        transition: transform 0.2s ease;
        border-right: 1px solid var(--border);
        box-shadow: 0 0 32px var(--shadow-color);
    }

    .rail:target {
        transform: none;
    }

    .rail:target ~ .rail-scrim {
        display: block;
    }

    /* Sliding a drawer is decoration; arriving is the point. */
    @media (prefers-reduced-motion: reduce) {
        .rail {
            transition: none;
        }
    }
}

/* ---- 60rem and up: the rail is a sidebar ---- */
@media (min-width: 60rem) {
    .app-shell {
        flex-direction: row;
    }

    .topbar {
        display: none;
    }

    .rail {
        /* Its own scroll region, so a long org list never pushes the
           account block off the bottom and the page scrolls independently. */
        position: sticky;
        top: 0;
        height: 100vh;
        flex: 0 0 16rem;
    }

    .app-main {
        flex: 1 1 auto;
        min-width: 0;
    }
}

@media (max-width: 768px) {
    :root {
        --spacer: 1rem;
        /* 2rem corners on a card that's nearly full-width reads as a
           blob and eats usable content width — scale it with the gutter. */
        --bubble-radius: 1rem;
    }

    pre {
        font-size: 0.8rem;
    }

    pre code {
        font-size: inherit;
    }

}

/* FORMS & SECTIONS */

section {
    margin-bottom: var(--spacer);
}

section h2 {
    font-size: 1.5rem;
    margin-bottom: 1rem;
    color: var(--text-primary);
}

.card {
    background-color: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: var(--bubble-radius);
    padding: var(--spacer);
    margin-bottom: var(--spacer);
}

.card h3 {
    margin-top: 0;
    margin-bottom: 1rem;
    color: var(--text-primary);
}

/* ---- admin card structure ---- */

/* Section header: optional avatar/graphic on the left, title + one line
   of explanation on the right. Replaces the old ad-hoc flex-start with
   inline gap/margin overrides. */
.card-head {
    display: flex;
    align-items: center;
    gap: 1.25rem;
    margin-bottom: 1.75rem;
}

.card-head h2 {
    margin: 0 0 0.2rem;
    font-size: 1.25rem;
    letter-spacing: -0.01em;
}

.card-head p {
    margin: 0;
    max-width: 62ch;
}

/* Image and its Upload button sit side by side, under the field label —
   the button reads as an action on the image next to it. */
.avatar-preview {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 1rem;
    flex-shrink: 0;
}

/* Square, sized to a text field so the avatar row lines up with the
   fields beside it. */
.avatar-img {
    width: var(--field-height);
    height: var(--field-height);
    object-fit: cover;
    border-radius: var(--field-radius);
    border: var(--field-border) solid var(--border);
    display: block;
}

.avatar-placeholder {
    background: var(--bg-tertiary);
    color: var(--text-muted);
    font-size: 2rem;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* Full-width text inputs look wrong for short values like a domain. */
.form-group-narrow {
    max-width: 26rem;
}

/* An input with an adjacent icon action (e.g. clear the stored key). */
.field-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.field-row input {
    flex: 1;
    min-width: 0;
}

/* A checkbox row is one control, not a stacked label-over-input. */
.check-group {
    margin-top: 0.5rem;
    margin-bottom: 0;
}

.check-label {
    display: inline-flex;
    align-items: center;
    gap: 0.55rem;
    margin: 0;
    font-weight: 400;
    cursor: pointer;
}

/* ---- notices (replaces the dead daub --db-* alert markup) ---- */

.notice {
    padding: 0.75rem 1rem;
    margin: 1rem 0;
    border-radius: 0.5rem;
    border-left: 3px solid var(--border);
    font-size: 0.92rem;
}

.notice-warning {
    background: color-mix(in srgb, var(--warning) 10%, transparent);
    border-left-color: var(--warning);
    color: var(--text-primary);
}

.notice-error {
    background: color-mix(in srgb, var(--error) 10%, transparent);
    border-left-color: var(--error);
    color: var(--text-primary);
}

/* ---- source panels (pages, documents, training) ---- */

/* Sub-headings inside a card, for the Pages and Documents blocks that
   share the "Connect Your Website" card. */
/* Qualified with h3 deliberately. These live inside .card, and
   `.card h3 { margin-top: 0 }` above outranks a bare class no matter how
   far down the file it sits — which silently ate the space above every
   source heading. Matching that specificity lets source order decide. */
h3.source-heading {
    margin: 1.75rem 0 0.35rem;
    font-size: 1rem;
}

/* The first one already has the card's own heading block above it. */
h3.source-heading:first-of-type {
    margin-top: 1rem;
}

.source-note {
    font-size: 0.9rem;
    margin: 0 0 0.85rem;
}

/* Button and status line share a row when there's room and stack when
   there isn't — the generic .flex-start doesn't wrap, so on a phone the
   status text ran off the side of the card. */
.source-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.75rem;
    margin-bottom: 0.5rem;
}

.source-status {
    font-size: 0.9rem;
    min-width: 0;
    overflow-wrap: anywhere;
}

.crawl-depth {
    flex-shrink: 0;
    color: var(--text-muted);
    font-size: 0.8rem;
    font-variant-numeric: tabular-nums;
}

/* Sits at the end of a URL row. Kept quiet — it's an inspection tool,
   not something you reach for on every page. */
.url-view {
    flex-shrink: 0;
    font-size: 0.85rem;
    color: var(--text-secondary);
    margin-left: auto;
    white-space: nowrap;
}

.url-view:hover {
    color: var(--complement);
}

/* Autosave confirmation.

   One fixed slot for the whole page, not a holder beside every field.
   Fields autosave one at a time, so a single slot serves all of them —
   which is what lets the templates drop nine duplicate target divs and
   nine identical hx-targets. Being fixed, it also can't move the form
   as it comes and goes, which the old in-flow badge did.

   Sits above the sticky navbar's z-index, and offset below it so it
   doesn't cover the nav on short pages. */
.toast {
    position: fixed;
    top: 5rem;
    right: 1.5rem;
    z-index: 200;
    pointer-events: none;
}

.toast-msg {
    display: inline-block;
    padding: 0.4rem 0.9rem;
    border-radius: 999px;
    background-color: var(--bg-primary);
    border: 1px solid color-mix(in srgb, var(--success) 45%, var(--border));
    color: var(--success);
    font-size: 0.875rem;
    font-weight: 600;
    white-space: nowrap;
    box-shadow: 0 4px 14px var(--shadow-color);
    /* Every save swaps in a brand-new node, so this replays on insertion
       with no JS to reset it. `forwards` holds the final frame — fully
       transparent — until the next save replaces the node. */
    animation: toastIn 2.6s ease forwards;
}

.toast-msg.badge-error {
    border-color: color-mix(in srgb, var(--error) 45%, var(--border));
    color: var(--error);
}

@keyframes toastIn {
    0%   { opacity: 0; transform: translateY(-0.5rem); }
    8%   { opacity: 1; transform: none; }
    72%  { opacity: 1; transform: none; }
    100% { opacity: 0; transform: translateY(-0.25rem); }
}

@media (prefers-reduced-motion: reduce) {
    .toast-msg {
        animation: toastHold 2.6s step-end forwards;
    }

    @keyframes toastHold {
        0%, 72% { opacity: 1; }
        100%    { opacity: 0; }
    }
}

/* The training result reuses .save-badge, which is green; a failed run
   has to read as failed. */
.save-badge.badge-error {
    background-color: color-mix(in srgb, var(--error) 15%, transparent);
    color: var(--error);
}

fieldset {
    border: none;
    padding: 0;
    margin: 0 0 1.5rem 0;
}

legend {
    font-weight: 600;
    font-size: 1.1rem;
    margin-bottom: 1rem;
    color: var(--text-primary);
}

label {
    display: block;
    font-weight: 500;
    margin-bottom: 0.25rem;
    color: var(--text-primary);
}

input[type="text"],
input[type="email"],
input[type="password"],
input[type="number"],
input[type="file"],
textarea,
select {
    width: 100%;
    padding: var(--field-pad-y) 0.75rem;
    border: var(--field-border) solid var(--border);
    border-radius: var(--field-radius);
    background-color: var(--bg-primary);
    color: var(--text-primary);
    font-family: inherit;
    font-size: 1rem;
    /* Fixed in rem so every field is exactly --field-height, instead of
       varying with the font's own line box. */
    line-height: var(--field-line);
    margin-bottom: 1rem;
    transition: border-color 0.2s, box-shadow 0.2s;
}

/* A native select doesn't take its height from line-height the way an
   input does, so pin every single-line field to the token explicitly.
   textarea is excluded — it's meant to grow. */
input[type="text"],
input[type="email"],
input[type="password"],
input[type="number"],
select {
    height: var(--field-height);
}

input[type="text"]:focus,
input[type="email"]:focus,
input[type="password"]:focus,
input[type="number"]:focus,
input[type="file"]:focus,
textarea:focus,
select:focus {
    outline: none;
    border-color: var(--primary);
    box-shadow: 0 0 0 3px var(--primary-lighter);
}

/* The native chevron is a tiny unstyled glyph pinned to the edge, and it
   ignores every token on the field around it. Replacing it means turning
   the whole control's appearance off, so the arrow is drawn here as a
   background image and the right padding is opened up to clear it.
   A data URI can't read a CSS variable, so the stroke color is baked in
   and re-declared for dark mode below. */
select {
    -webkit-appearance: none;
    appearance: none;
    padding-right: 2.25rem;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5' fill='none' stroke='%23404040' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 0.85rem center;
    background-size: 0.7rem auto;
}

[data-theme="dark"] select {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5' fill='none' stroke='%23b3b3b3' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) select {
        background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5' fill='none' stroke='%23b3b3b3' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
    }
}

textarea {
    min-height: 150px;
    resize: vertical;
}

/* Pill buttons, matching Arland — fully rounded ends, and the same
   brightness-based hover, so the two products read as a family.
   (Arland also scales 1.05 on hover; skipped here because these sit in
   table rows and dense forms where it reads as twitchy rather than
   inviting.) */
button,
input[type="submit"],
input[type="button"] {
    background-color: var(--primary);
    color: white;
    border: none;
    padding: 0.75rem 1.5rem;
    border-radius: var(--pill-radius);
    cursor: pointer;
    font-weight: 600;
    transition: filter 0.15s, background-color 0.2s, box-shadow 0.15s;
}

button:hover,
input[type="submit"]:hover,
input[type="button"]:hover {
    filter: brightness(var(--hover-brightness));
    box-shadow: 0 4px 12px var(--shadow-color);
}

button:active,
input[type="submit"]:active,
input[type="button"]:active {
    filter: none;
    box-shadow: none;
}

/* Secondary was a filled --complement, which is lighter (55%) than the
   --primary fill (50%) — so "Upload" and "Delete" were the loudest things
   on the page while real actions receded. Now it's the same primary,
   hollow: reads as the same family as a filled button, one step down in
   weight. Fills in on hover. */
button.secondary {
    background-color: transparent;
    border: 1px solid var(--primary);
    color: var(--primary);
}

button.secondary:hover {
    background-color: color-mix(in srgb, var(--primary) 14%, transparent);
    color: var(--primary);
}

/* Destructive. Stays neutral — a step quieter than secondary — and only
   commits to red once you're actually reaching for it. */
button.danger {
    background-color: transparent;
    border: 1px solid var(--border);
    color: var(--text-secondary);
    font-weight: 500;
}

button.danger:hover {
    background-color: color-mix(in srgb, var(--error) 12%, transparent);
    border-color: var(--error);
    color: var(--error);
}

/* The base hover lifts filled buttons with brightness + a drop shadow.
   Under a hollow pill the shadow floats with nothing casting it, so
   outline variants opt out and rely on their fill-in instead. */
button.secondary:hover,
button.danger:hover {
    filter: none;
    box-shadow: none;
}

/* Compact variant for buttons that sit inside rows and cards. */
button.btn-sm {
    padding: 0.45rem 0.9rem;
    font-size: 0.875rem;
}

.form-group {
    margin-bottom: 1.5rem;
}

/* Inputs carry their own margin-bottom for standalone use; inside a
   form-group that stacked with the group's margin for ~45px gaps. */
.form-group input,
.form-group textarea,
.form-group select {
    margin-bottom: 0;
}

.form-group label {
    margin-bottom: 0.25rem;
}

/* Autosave target. Empty most of the time, so it must not reserve a line
   of height — that was padding out every field in the grid. */
.form-helper {
    font-size: 0.875rem;
    color: var(--text-muted);
    margin-top: 0.25rem;
    min-height: 0;
    line-height: 1.2;
}

.form-helper:empty {
    display: none;
}

/* Checkboxes were raw browser blue, the one control ignoring the theme. */
input[type="checkbox"],
input[type="radio"] {
    accent-color: var(--primary);
    width: auto;
    margin: 0;
    vertical-align: middle;
}

.form-error {
    color: var(--error);
    font-size: 0.875rem;
    margin-top: 0.25rem;
}

/* Two-column field layout, column-major: the left .col holds fields
   1-2-3 and the right holds 4-5-6, rather than snaking across rows.
   That needs real column elements — CSS alone can only reorder within a
   single flow — so .grid takes two .col children and each stacks its own
   fields.
   Collapsing is then just display:block: the columns stack, and because
   each already reads top-to-bottom the result is 1-2-3-4-5-6 in one
   column with no reordering. */
.grid {
    display: flex;
    gap: 1.5rem;
}

.grid > .col {
    flex: 1 1 0;
    min-width: 0;
}

/* Fields inside a column stack on their own margins. */
.grid > .col > .form-group:last-child {
    margin-bottom: 0;
}

@media (max-width: 768px) {
    .grid {
        display: block;
    }

    /* Block layout ignores gap, so the last field of a stacked column
       needs its margin back or the columns run together. */
    .grid > .col > .form-group:last-child {
        margin-bottom: 1.5rem;
    }
}

/* UTILITY CLASSES */

.stack {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
}

/* The page title used to supply the gap under the sticky navbar; without
   one, the first card would sit flush against it. */
main.container {
    padding-top: var(--spacer);
    padding-bottom: var(--spacer);
}

.center {
    display: flex;
    flex-direction: column;
    align-items: center;
}

.flex-between {
    display: flex;
    justify-content: space-between;
    align-items: center;
    flex-wrap: wrap;
    gap: 1rem;
}

.flex-start {
    display: flex;
    gap: 0.5rem;
    align-items: center;
}

.gap-small {
    gap: 0.5rem;
}

.text-muted {
    color: var(--text-muted);
}

.text-secondary {
    color: var(--text-secondary);
}

/* CHAT PAGE */

.chat-container {
    flex: 1;
    overflow: hidden;
    display: flex;
    flex-direction: column;
}

/* ADMIN COMPONENTS */

/* Rows are their own surfaces on --bg-primary, which reads as raised
   against the card's --bg-secondary. No outer container border — the
   rows themselves are the structure. */
.document-list {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.document-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    min-height: 3.75rem;
    padding: 0.5rem 0.75rem 0.5rem 1.25rem;
    background-color: var(--bg-primary);
    border: 1px solid var(--border);
    border-radius: var(--field-radius);
    transition: border-color 0.15s;
}

.document-item:hover {
    border-color: var(--text-muted);
}

.document-title {
    color: var(--text-primary);
    overflow-wrap: anywhere;
}

.document-empty {
    justify-content: center;
    color: var(--text-muted);
    border-style: dashed;
}

.document-empty:hover {
    border-color: var(--border);
}

/* The upload affordance is the first row, not a button above the list,
   so the whole line is the target. */
.document-upload {
    padding: 0;
    border-style: dashed;
}

.document-upload-btn {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    width: 100%;
    min-height: 3.6rem;
    padding: 0.5rem 1.25rem;
    background: none;
    border: none;
    border-radius: var(--field-radius);
    color: var(--primary);
    font-weight: 600;
    text-align: left;
    cursor: pointer;
}

.document-upload-btn:hover {
    background-color: color-mix(in srgb, var(--primary) 10%, transparent);
    filter: none;
    box-shadow: none;
}

/* ---- icon buttons ---- */

.doc-icon {
    width: 2rem;
    height: 2rem;
    flex-shrink: 0;
    display: block;
}

/* Fixed hit area, independent of glyph size — shrinking the icon must
   not shrink what you have to aim at. */
.icon-btn {
    display: grid;
    place-items: center;
    flex-shrink: 0;
    width: 2.7rem;
    height: 2.7rem;
    padding: 0;
    background: none;
    border: none;
    border-radius: 50%;
    color: var(--text-muted);
    cursor: pointer;
    transition: color 0.15s, background-color 0.15s;
}

.icon-btn .doc-icon {
    width: 1.25rem;
    height: 1.25rem;
}

.icon-btn:hover {
    background: none;
    filter: none;
    box-shadow: none;
    color: var(--text-primary);
}

.icon-btn-danger:hover {
    background-color: color-mix(in srgb, var(--error) 12%, transparent);
    color: var(--error);
}

.crawl-status {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

/* ---- url list ---- */

.url-list {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.url-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    min-height: 3.75rem;
    padding: 0.5rem 0.75rem 0.5rem 1.25rem;
    background-color: var(--bg-primary);
    border: 1px solid var(--border);
    border-radius: var(--field-radius);
    transition: border-color 0.15s;
}

.url-item:hover {
    border-color: var(--text-muted);
}

.url-add {
    padding: 0.75rem;
}

.url-input-group {
    display: flex;
    gap: 0.5rem;
    flex: 1;
}

.url-input {
    flex: 1;
    padding: 0.5rem 0.75rem;
    border: 1px solid var(--border);
    border-radius: var(--field-radius);
    background-color: var(--bg-secondary);
    color: var(--text-primary);
    font-size: 0.95rem;
}

.url-input:focus {
    outline: none;
    border-color: var(--primary);
    background-color: var(--bg-primary);
}

.url-content {
    flex: 1;
    display: flex;
    align-items: center;
    gap: 0.75rem;
    min-width: 0;
}

.url-text {
    color: var(--text-primary);
    text-decoration: none;
    word-break: break-all;
    font-size: 0.9rem;
    overflow-wrap: anywhere;
}

.url-text:hover {
    text-decoration: underline;
    color: var(--link);
}

.url-empty {
    justify-content: center;
    color: var(--text-muted);
    border-style: dashed;
}

.url-empty:hover {
    border-color: var(--border);
}

.url-icon {
    width: 1.5rem;
    height: 1.5rem;
    flex-shrink: 0;
    display: block;
}

.url-icon-add {
    color: var(--text-muted);
}

.source-badge {
    display: inline-block;
    padding: 0.25rem 0.5rem;
    border-radius: 0.25rem;
    font-size: 0.75rem;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    white-space: nowrap;
}

.source-crawled {
    background-color: color-mix(in srgb, var(--primary) 15%, transparent);
    color: var(--primary);
}

/* A URL the last summary run couldn't read (404, unreachable, no text).
   It stays in the list — it's the admin's call whether to fix or drop
   it — so it needs to be visibly not-fine rather than silently skipped. */
.source-failed {
    background-color: color-mix(in srgb, var(--error) 15%, transparent);
    color: var(--error);
    cursor: help;
}

/* A source that was readable but too big for the summary's size budget,
   so it went in truncated or not at all. Deliberately warning-colored
   rather than error-colored: the URL or document is perfectly fine, the
   budget wasn't, and the fix is to split the content or move to a bigger
   model — not to go hunting for a broken link. */
.source-oversize {
    background-color: color-mix(in srgb, var(--warning) 18%, transparent);
    color: color-mix(in srgb, var(--warning) 75%, var(--text));
    cursor: help;
}

.url-actions {
    display: flex;
    gap: 0.5rem;
    padding: 1rem 0 0 0;
}

/* accent-color gives a filled track for free but leaves the thumb at the
   platform's default size, which is too small to grab. Taking over with
   appearance:none allows a proper handle; the fill it gave up is rebuilt
   as a gradient driven by --range-pct, which the input's own oninput
   keeps current (and the template seeds server-side so it's right before
   any interaction). */
input[type="range"] {
    -webkit-appearance: none;
    appearance: none;
    width: 100%;
    /* Same box as every other field, so a slider lines up with the
       selects and inputs beside it instead of riding high in its row.
       The track and thumb centre themselves inside it, and the whole
       height becomes hit target. */
    height: var(--field-height);
    /* colors.css puts a border, background and focus ring on every input.
       On a range those draw a box around the entire control — the track
       and thumb below are the only surface it should have. */
    border: none;
    background: transparent;
    padding: 0;
    margin: 0;
    cursor: pointer;
}

/* Focus moves to the thumb instead (see below), so the field-wide ring
   from colors.css has to be cancelled here. */
input[type="range"]:focus {
    outline: none;
    box-shadow: none;
    border: none;
}

input[type="range"]::-webkit-slider-runnable-track {
    height: 0.375rem;
    border-radius: 999px;
    background: linear-gradient(
        to right,
        var(--primary) 0 var(--range-pct, 50%),
        var(--bg-tertiary) var(--range-pct, 50%) 100%
    );
}

input[type="range"]::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    width: 1.25rem;
    height: 1.25rem;
    /* (track height - thumb height) / 2, to sit centred on the track. */
    margin-top: -0.4375rem;
    border-radius: 50%;
    background: var(--primary);
    border: 2px solid var(--bg-primary);
    box-shadow: 0 1px 3px var(--shadow-color);
}

input[type="range"]::-moz-range-track {
    height: 0.375rem;
    border-radius: 999px;
    background: linear-gradient(
        to right,
        var(--primary) 0 var(--range-pct, 50%),
        var(--bg-tertiary) var(--range-pct, 50%) 100%
    );
}

input[type="range"]::-moz-range-thumb {
    width: 1.25rem;
    height: 1.25rem;
    border-radius: 50%;
    background: var(--primary);
    border: 2px solid var(--bg-primary);
    box-shadow: 0 1px 3px var(--shadow-color);
}

input[type="range"]:focus-visible::-webkit-slider-thumb {
    box-shadow: 0 0 0 3px var(--primary-lighter);
}

input[type="range"]:focus-visible::-moz-range-thumb {
    box-shadow: 0 0 0 3px var(--primary-lighter);
}

.range-value {
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
    font-weight: 400;
}

input[type="color"] {
    width: 4rem;
    height: var(--field-height);
    padding: 0.25rem;
    border: var(--field-border) solid var(--border);
    border-radius: var(--field-radius);
    background: var(--bg-primary);
    cursor: pointer;
}

/* Sign-out in the navbar.

   A form rather than a link, because sign-out is a state change and a
   link prefetcher must not be able to trigger it. The form itself is
   layout-invisible; only its button should be seen. Shared with the
   control plane, which puts the same control in the same place. */
.nav-form {
    display: inline;
    margin: 0;
}

.nav-form button {
    padding: 0.4rem 1rem;
    font-size: 0.9rem;
}

/* ---- busy buttons (static/busy-button.js) ----
   Opt in with data-busy on any button; the script does the rest. */

/* Phosphor spinner-gap (bold), inlined so it costs no request, and drawn
   as a mask rather than an image so it takes currentColor — one glyph
   that is right on a primary button, a dark theme and a light one. */
.btn-spinner {
    display: inline-block;
    width: 1em;
    height: 1em;
    margin-right: 0.5em;
    vertical-align: -0.125em;
    background-color: currentColor;
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'%3E%3Cpath d='M140,32V64a12,12,0,0,1-24,0V32a12,12,0,0,1,24,0Zm84,84H192a12,12,0,0,0,0,24h32a12,12,0,0,0,0-24Zm-42.26,48.77a12,12,0,1,0-17,17l22.63,22.63a12,12,0,0,0,17-17ZM128,180a12,12,0,0,0-12,12v32a12,12,0,0,0,24,0V192A12,12,0,0,0,128,180ZM74.26,164.77,51.63,187.4a12,12,0,0,0,17,17l22.63-22.63a12,12,0,1,0-17-17ZM76,128a12,12,0,0,0-12-12H32a12,12,0,0,0,0,24H64A12,12,0,0,0,76,128ZM68.6,51.63a12,12,0,1,0-17,17L74.26,91.23a12,12,0,0,0,17-17Z'/%3E%3C/svg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'%3E%3Cpath d='M140,32V64a12,12,0,0,1-24,0V32a12,12,0,0,1,24,0Zm84,84H192a12,12,0,0,0,0,24h32a12,12,0,0,0,0-24Zm-42.26,48.77a12,12,0,1,0-17,17l22.63,22.63a12,12,0,0,0,17-17ZM128,180a12,12,0,0,0-12,12v32a12,12,0,0,0,24,0V192A12,12,0,0,0,128,180ZM74.26,164.77,51.63,187.4a12,12,0,0,0,17,17l22.63-22.63a12,12,0,1,0-17-17ZM76,128a12,12,0,0,0-12-12H32a12,12,0,0,0,0,24H64A12,12,0,0,0,76,128ZM68.6,51.63a12,12,0,1,0-17,17L74.26,91.23a12,12,0,0,0,17-17Z'/%3E%3C/svg%3E") center / contain no-repeat;
    /* steps(8), because the glyph has eight spokes: it ticks from one to
       the next instead of sliding, which is what a spinner of this shape
       is drawn to do. */
    animation: btnSpin 0.8s steps(8) infinite;
}

@keyframes btnSpin {
    to { transform: rotate(360deg); }
}

/* Not button-scoped: a provider link is an <a>, where disabled does
   nothing and pointer-events is what stops a second click. */
[aria-busy="true"] {
    cursor: progress;
    pointer-events: none;
    opacity: 0.9;
}

@media (prefers-reduced-motion: reduce) {
    /* Slowed rather than stopped. A still spinner on a disabled button is
       indistinguishable from a hung page. */
    .btn-spinner {
        animation-duration: 2.4s;
    }
}

/* "New org…" — an action, not another org to switch to, so it is
   separated from the list it sits under. */
.switcher-menu .switcher-action {
    border-top: 1px solid var(--border);
    margin-top: 0.35rem;
    padding-top: 0.35rem;
}

.switcher-menu .switcher-action a {
    color: var(--primary);
    font-weight: 600;
}

/* Sibling inputs sharing one label (a bot's opening questions). Tighter
   than the gap between form-groups, since they read as one control with
   several slots rather than several fields. */
.field-stack {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

/* The bot's own address, under its name in the rail. Monospace and small:
   it is a hostname to read, not a label to skim. */
.rail-context-detail {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.7rem;
    color: var(--text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* --- choice cards -----------------------------------------------------
   A labelled radio card, used where the thing being picked has terms worth
   reading: plans on the control plane, and which AI answers on a bot. One
   option renders the same as three; nothing here assumes a count. */

.bot-new-form {
    display: flex;
    flex-direction: column;
    gap: 1.25rem;
}

.field {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
}

.field-label {
    font-weight: 600;
    font-size: 0.95rem;
}

.field-hint {
    color: var(--text-muted);
    font-size: 0.85rem;
}

.plan-choice {
    border: 0;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
}

.plan-choice legend {
    padding: 0 0 0.35rem 0;
}

/* The whole card is the label, so the click target is the card and not a
   6px radio nobody aims at. */
.plan-card {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 0.15rem 0.75rem;
    align-items: baseline;
    padding: 0.9rem 1rem;
    border: 1px solid var(--border);
    border-radius: var(--field-radius);
    cursor: pointer;
}

.plan-card:hover {
    border-color: var(--primary-light);
}

/* :has, so selecting the radio lights the card it belongs to without a
   line of script. */
.plan-card:has(input:checked) {
    border-color: var(--primary);
    background: var(--bg-secondary);
}

/* Spans every row and sits at the top, so it stays beside the option's
   name however tall the card gets — centering it drifted to the middle
   once a card carried its own fields. */
.plan-card input {
    grid-row: 1 / -1;
    align-self: start;
    margin: 0.3rem 0 0 0;
    accent-color: var(--primary);
}

.plan-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
}

.plan-name {
    font-weight: 600;
}

.plan-price {
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

.plan-per {
    color: var(--text-muted);
    font-weight: 400;
    font-size: 0.85rem;
}

.plan-messages {
    grid-column: 2;
    font-size: 0.9rem;
}

.plan-blurb {
    grid-column: 2;
    color: var(--text-muted);
    font-size: 0.85rem;
}

.form-actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 1rem;
}

/* Cancel is a way out, not a second thing to choose — so it reads as a
   link even though it sits beside a button. */
.btn-quiet {
    background: none;
    border: 0;
    color: var(--text-secondary);
    text-decoration: none;
}

.btn-quiet:hover {
    color: var(--text-primary);
    text-decoration: underline;
}

/* The dashboard row's usage line, under the hostname. */
.bot-usage {
    display: block;
    font-size: 0.85rem;
    color: var(--text-muted);
}

/* Configuration belonging to a choice card, revealed only for the option
   that is selected. Full width under the blurb rather than beside it: the
   controls are the point once you've chosen, not a footnote to the terms. */
.plan-fields {
    grid-column: 2;
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    margin-top: 0.85rem;
    padding-top: 0.85rem;
    border-top: 1px solid var(--border);
    cursor: default;
}

.plan-fields .form-group {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    margin: 0;
}

/* Where the choice is made in the browser rather than saved, both cards
   carry their fields and the unselected one hides them. Cards whose
   fields are rendered server-side never hit this. */
.plan-card:not(:has(input:checked)) .plan-fields {
    display: none;
}

/* ---- inbox ---- */

.feedback-list {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.feedback-item {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 1rem;
    padding: 0.75rem 0.75rem 0.75rem 1.25rem;
    background-color: var(--bg-primary);
    border: 1px solid var(--border);
    border-radius: var(--field-radius);
    transition: border-color 0.15s;
}

.feedback-item:hover {
    border-color: var(--text-muted);
}

/* Dealt with, but still readable: the row stays, the emphasis goes. */
.feedback-item.is-done {
    background-color: transparent;
}

.feedback-item.is-done .feedback-message,
.feedback-item.is-done .feedback-name {
    color: var(--text-muted);
}

.feedback-main {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    flex: 1;
    min-width: min-content;
}

.feedback-who {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0 0.6rem;
}

.feedback-name {
    font-weight: 600;
    color: var(--text-primary);
}

.feedback-contact {
    font-family: "SF Mono", Menlo, Monaco, Consolas, ui-monospace, monospace;
    font-size: 0.8rem;
    color: var(--text-muted);
    overflow-wrap: anywhere;
}

.feedback-message {
    margin: 0;
    color: var(--text-primary);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.feedback-when {
    font-size: 0.8rem;
    color: var(--text-muted);
}

.feedback-badge {
    flex-shrink: 0;
    font-size: 0.75rem;
    font-weight: 600;
    padding: 0.2rem 0.7rem;
    border-radius: var(--pill-radius);
    background-color: color-mix(in srgb, var(--primary) 14%, transparent);
    color: var(--primary);
}

.feedback-badge-reply {
    background-color: color-mix(in srgb, var(--warning) 14%, transparent);
    color: var(--text-primary);
}

.feedback-badge-done {
    background-color: var(--bg-tertiary);
    color: var(--text-muted);
}

/* Narrows to one button and lets the icons stack rather than reserving
   every width at every size. */
.feedback-actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    align-items: center;
    min-width: 2.7rem;
}

.feedback-empty {
    justify-content: center;
    color: var(--text-muted);
    border-style: dashed;
}

.feedback-empty:hover {
    border-color: var(--border);
}

/* Count of things nobody has dealt with, on a rail link. */
.rail-badge {
    margin-left: auto;
    min-width: 1.35rem;
    padding: 0.1rem 0.4rem;
    border-radius: var(--pill-radius);
    background-color: var(--primary);
    color: var(--bg-primary);
    font-size: 0.7rem;
    font-weight: 700;
    text-align: center;
}
