/*
 * Stetworth /app — the server-backed gallery states (loading / error
 * / empty, the warm refreshing note and the refresh-failure line),
 * cut from style.css's "Server-backed gallery states" section
 * unchanged and in the original order.  The task-gallery grid itself
 * is shared page vocabulary and stays in style.css.
 */
/*
 * Load order is load-bearing: the /app shell links every split sheet
 * BEFORE style.css.  That keeps both source-order contracts intact —
 * a rule kept behind in style.css still beats its shared group there
 * by file order, and the responsive tail at the end of style.css
 * still overrides this sheet's base rules at equal specificity.
 * This sheet declares no design-token block of its own and carries
 * no media block of any kind — every width, motion and paged
 * override for these rules lives in style.css's responsive tail
 * (docs/APP.md#the-split-stylesheets).
 */

/* ============================================================
 * Server-backed gallery states (loading / error / empty, plus the
 * warm refreshing note and refresh-failure line)
 *
 * The /app gallery is fetched from `GET /api/app/tasks` on route
 * entry (web/app/js/app.js `_fetchTasks`), so the task grid needs
 * interim treatments the static mockup never did: a loading
 * placeholder while a cold list request is in flight, an
 * inline-retry error state, and a zero-task empty state pointing
 * back at the composer — all composing the existing `.panel`
 * surface and palette variables, no new colors.  A warm re-entry
 * skips the panel treatments entirely: the cached rows paint at
 * once under the quiet `.gallery-refreshing-note`, and a failed
 * re-read swaps that slot for the `.gallery-refresh-error` line
 * (one sentence plus a Try again control) while the rows stay up.
 * (This section is /app-only by design: it is where this
 * stylesheet diverges from its web/mockup/ origin.)
 *
 * The boot-error page (`_renderBootError`) needs no rules of its
 * own — it composes `.login`, `.card`, `.login-lede`, and
 * `.composer-actions`; `.boot-error` / `.boot-error-title` are
 * JS/test hooks like `.login-awaiting` / `.login-awaiting-title`.
 * ============================================================ */

.gallery-state {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--s-3);
    padding: var(--s-7) var(--s-5);
    text-align: center;
}

.gallery-state-text {
    margin: 0;
    color: var(--c-ink-muted);
    font-size: var(--fs-body);
}

.gallery-state-empty .gallery-state-text {
    color: var(--c-ink-muted);
    font-style: italic;
}

.gallery-spinner {
    width: 18px;
    height: 18px;
    flex: none;
    border-radius: 50%;
    border: 2px solid var(--c-rule-strong);
    border-top-color: var(--c-burnished);
    animation: gallery-spin 0.9s linear infinite;
}

@keyframes gallery-spin {
    to { transform: rotate(360deg); }
}

/* The cold load's ledger placeholder: the announced copy over four
   unfilled hairline rows — rules and negative space standing where the
   task rows will land.  No gray blocks, no shimmer, and deliberately no
   animation or transition properties, so the state is byte-identical
   under prefers-reduced-motion by construction rather than by a
   media-query patch.  (The spinner above no longer renders here — its
   surviving sites are named at the reduced-motion block.)
   `.gallery-state-loading` is also the class of those five surviving
   spinner panels, so its block may hold nothing beyond the wrap
   permission — a no-op for a spinner-beside-copy row that never fills
   a line.  The ledger reaches full width through the placeholder's
   own 100% basis, never through a direction or alignment override the
   five panels would inherit. */
.gallery-state-loading {
    flex-wrap: wrap;
}

.gallery-placeholder {
    flex: 1 1 100%;
    border-top: 1px solid var(--c-rule);
}

.gallery-placeholder-row {
    padding: var(--s-4) 0;
    border-bottom: 1px solid var(--c-rule);
}

/* The stale-while-revalidate slot above the rows: the quiet note a
   warm re-entry paints while its re-read is in flight, and the
   matching inline line a failed re-read replaces it with.  Both are
   painted on demand and repainted away — never shipped hidden. */
.gallery-refreshing-note {
    font-size: var(--fs-ui);
    font-style: italic;
    color: var(--c-ink-muted);
    margin: 0 0 0.5rem;
}

.gallery-refresh-error {
    font-size: var(--fs-ui);
    font-style: italic;
    color: var(--c-ink-muted);
    margin: 0 0 0.5rem;
}

