/*
 * Our own custom CSS, loaded after the vendored ui/css/app.css so it can
 * extend/override without touching that generated file (see decisions.md's
 * 2026-09-18 Nexus entry).
 */

/*
 * AI Auto-fill's loading indicator (see autofill/index.html): htmx's default
 * .htmx-indicator behavior only toggles opacity, which leaves the card's
 * full height reserved as an empty gap both before the first request and
 * again after the response replaces #autofill-outlet below it. Collapse it
 * to zero height when idle instead, so it only takes up space while a
 * proposal is actually being generated.
 */
#autofill-loading {
    max-height: 0;
    margin-top: 0;
    opacity: 0;
    overflow: hidden;
    transition: max-height 150ms ease-in, opacity 150ms ease-in, margin-top 150ms ease-in;
}

#autofill-loading.htmx-request {
    max-height: 200px;
    margin-top: 1.5rem;
    opacity: 1;
}

/*
 * While a new proposal is generating (#autofill-loading carries
 * .htmx-request), the outlet still shows the previous response until the
 * new one replaces it. Without these, an old error sat next to the spinner
 * for the whole AI call, reading as though the new attempt had already
 * failed, and an old proposal stayed clickable, so it could be accepted by
 * accident mid-generation.
 */
body:has(#autofill-loading.htmx-request) #autofill-outlet .autofill-error {
    display: none;
}

body:has(#autofill-loading.htmx-request) #autofill-outlet .autofill-proposal {
    opacity: 0.4;
    pointer-events: none;
    transition: opacity 150ms ease-in;
}

/*
 * AI buttons (topic/description Generate, Refine's Apply): swap the icon for
 * a spinner while that button's own request runs. htmx puts .htmx-request
 * on the triggering button; keying on button.htmx-request rather than any
 * ancestor keeps a task save (which marks the whole form) from spinning
 * every AI button in it.
 */
.ai-spinner {
    display: none;
}

button.htmx-request .ai-spinner {
    display: inline-block;
}

button.htmx-request .ai-icon {
    display: none;
}

/*
 * While an AI button's request runs, fade the field it's about to replace
 * and ignore clicks on it: anything typed there meanwhile would be silently
 * overwritten when the response swaps the field in. CSS rather than the
 * disabled attribute, which would also drop the value from the request.
 * .ai-field marks the swapped field fragments (task modal topic and
 * description, Auto-fill row description).
 */
.ai-field:has(button.htmx-request) :is(textarea, input[type="text"]) {
    opacity: 0.5;
    pointer-events: none;
    transition: opacity 150ms ease-in;
}

/*
 * A tooltip that wraps at a fixed width (e.g. the locked Refine button's
 * "not included in your plan"). daisyUI sizes .tooltip-content to
 * max-content, a single line that ran past the task modal's right edge.
 * Its rule outranks a Tailwind w-* utility (both in the utilities layer,
 * higher specificity), so the width is set here, unlayered.
 */
.tooltip-wrap {
    width: 10rem;
}

/*
 * The admin user page's raw webhook JSON (admin/user.html): wrapped and
 * height-capped, since the precompiled Nexus CSS has no max-h-* or
 * whitespace-pre-wrap utilities.
 */
.admin-json {
    max-height: 24rem;
    overflow: auto;
    white-space: pre-wrap;
    word-break: break-all;
}

/*
 * The auth pages' left panel (fragments/auth :: art): a soft wash of the
 * theme's primary and secondary colours, from its CSS variables so it
 * follows light/dark. Gradient opacities Nexus never compiled as classes.
 */
.auth-art {
    background:
        radial-gradient(circle at 20% 15%, color-mix(in oklab, var(--color-primary) 22%, transparent), transparent 55%),
        radial-gradient(circle at 85% 85%, color-mix(in oklab, var(--color-secondary) 22%, transparent), transparent 55%),
        var(--color-base-200);
}

/*
 * The legal pages' long-form text (legal/*.html). The vendored stylesheet
 * has no typography plugin and no list bullets, so headings, paragraphs,
 * lists and links inside .legal get their spacing here.
 */
.legal h2 {
    margin-top: 2.5rem;
    font-size: 1.25rem;
    font-weight: 600;
    scroll-margin-top: 5rem;
}

.legal h3 {
    margin-top: 1.5rem;
    font-weight: 600;
    scroll-margin-top: 5rem;
}

.legal p,
.legal ul,
.legal ol,
.legal .table-wrap {
    margin-top: 0.75rem;
    line-height: 1.7;
}

.legal ul {
    list-style: disc;
    padding-inline-start: 1.5rem;
}

.legal ol {
    list-style: decimal;
    padding-inline-start: 1.5rem;
}

.legal li + li {
    margin-top: 0.375rem;
}

.legal a:not(.btn) {
    color: var(--color-primary);
    text-decoration: underline;
}

.legal td,
.legal th {
    vertical-align: top;
}

/*
 * Safari: DaisyUI's .fieldset-legend (display: flex, margin-inline-end:
 * auto) inside the grid .fieldset shrinks to its narrowest width there,
 * one word per line ("What should we call you?" in five lines). Size it
 * to its text instead, as Chrome does, still wrapping when the field is
 * narrower than the text.
 */
.fieldset > .fieldset-legend {
    width: max-content;
    max-width: 100%;
}
