/*
 * Remote reading app — list-view chrome only. Reuses report-base.css's :root tokens (loaded before this
 * file in index.html) for the detail view's cards/dashboard/modals; this file only styles the app shell
 * that report-base.css has no equivalent for (the report list, header, error state).
 */
body {
  margin: 0;
  font-family: var(--font);
  background: var(--bg);
  color: var(--text);
}

/*
 * Page container for the list view (2026-09-07).
 *
 * Header, toolbar, error banner and list each carried their own `max-width: 900px` and no horizontal
 * margin at all — there was not a single `margin-inline: auto` in this file. A max-width without one
 * constrains the width but never moves the box, so on any screen wider than 900px the whole app sat
 * flush against the left edge with a growing empty gap on the right. The detail view never showed it
 * because it is styled by report-base.css, whose `.layout` does centre itself (`max-width: 1440px;
 * margin: 0 auto`) — which is why the bug only ever appeared on the list.
 *
 * One grid column instead of four separate max-widths: every band is bounded and centred by the
 * container, so they share one axis by construction and cannot drift apart when one of them is
 * edited later. `minmax(0, …)` keeps long unbreakable strings (report titles, file names) from
 * pushing the column past its bound.
 */
:root {
  --list-content-max: 900px;
}

#listView {
  display: grid;
  grid-template-columns: minmax(0, var(--list-content-max));
  justify-content: center;
  align-content: start;
}

/* F-XX/2026-09-06: the browser's UA stylesheet only sets `[hidden] { display: none }` — any AUTHOR
 * rule on the same element that also declares `display` (e.g. `.push-settings { display: flex }`,
 * `.update-banner { display: flex }`, `.remote-app-error { display: flex }`) wins over that UA default
 * regardless of selector specificity, because author styles always outrank user-agent styles in the
 * cascade. Every one of those three components toggles visibility purely via `el.hidden = true/false`
 * in remote-app.js — with no `[hidden]` override, the `hidden` attribute was cosmetically inert on all
 * three: the push-settings panel could never actually be dismissed (always `display:flex`, "close"
 * click did nothing visible), and the update banner rendered visible on every single load regardless
 * of whether a real update existed. One global, specificity-proof rule closes this for these three and
 * any future `hidden`-toggled component in this file. */
[hidden] {
  display: none !important;
}

.remote-app-header {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 20px 16px 8px;
}

.remote-app-header h1 {
  margin: 0;
  font-size: 1.3rem;
  margin-right: auto;
}

.detail-backbar {
  position: sticky;
  top: 0;
  z-index: 6;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  /* Same bound and padding as report-base.css's .layout below it, so the back button lines up with
     the report content instead of hugging the left edge on a wide screen (2026-09-07). */
  max-width: var(--layout-max);
  margin-inline: auto;
  padding: 10px clamp(16px, 3vw, 28px);
  background: var(--bg);
  border-bottom: 1px solid var(--border);
}

/* Loading state between tapping a report and its spec arriving (2026-09-07) — same max-width and
   padding as .detail-backbar/.layout so the placeholder occupies the position the report will. */
.detail-loading {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  max-width: var(--layout-max);
  margin-inline: auto;
  padding: 28px clamp(16px, 3vw, 28px);
  color: var(--muted);
}

.detail-loading-spinner {
  width: 18px;
  height: 18px;
  flex: none;
  border-radius: 50%;
  border: 2px solid var(--border);
  border-top-color: var(--accent);
  animation: detail-loading-spin .7s linear infinite;
}

.detail-loading-title {
  font-weight: 600;
  color: var(--text);
}

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

/* A spinner that cannot spin still has to say "busy" — the border stays, only the rotation stops. */
@media (prefers-reduced-motion: reduce) {
  .detail-loading-spinner { animation: none; }
}

/* report-base.css's shared .floating-actions (Theme/Hilfe) is also used, unmodified, by every
   standalone locally-rendered report — only neutralize its own padding/border/background when it is
   nested inside this remote-app-only backbar, so "Liste"/"Theme"/"Hilfe" read as one line here without
   touching the shared class's default look everywhere else. */
.detail-backbar .floating-actions {
  padding: 0;
  border-bottom: none;
  background: transparent;
}

.detail-back {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  width: auto;
  padding: 8px 16px;
  border-radius: 999px;
  background: var(--panel);
  font-weight: 600;
  text-decoration: none;
  transition: border-color .15s ease, background-color .15s ease;
}

.detail-back:hover,
.detail-back:focus-visible {
  border-color: var(--accent);
  background: var(--accent-soft);
}

.offline-badge {
  font-size: .8rem;
  padding: 3px 8px;
  border-radius: 999px;
  background: var(--warn-bg, #4a3a12);
  color: var(--warn-text, #ffcf6b);
}

.push-settings {
  position: absolute;
  top: 100%;
  right: 16px;
  z-index: 10;
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 10px 12px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: 0 4px 12px rgba(0, 0, 0, .3);
  font-size: .85rem;
}

.push-settings label {
  display: flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
}

.push-settings-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  font-weight: 600;
  padding-bottom: 4px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 2px;
}

#listToolbar {
  position: sticky;
  top: 0;
  z-index: 5;
  background: var(--bg);
  flex-wrap: wrap;
  row-gap: 10px;
  padding: 10px 16px 12px;
  margin-bottom: 4px;
  border-bottom: 1px solid var(--border);
  transition: transform .25s ease, opacity .2s ease;
}

/* Hides the whole filter section on scroll-down, reveals it again on scroll-up (wireScrollHide() in
   remote-app.js toggles this class) — a `transform`/`opacity` transition (not display/height) keeps it
   smooth ("langsam ausblenden") and cheap, since it never triggers layout/reflow. */
#listToolbar.toolbar-hidden {
  transform: translateY(-115%);
  opacity: 0;
}

#globalSearch {
  flex: 1 1 100%;
  padding: 9px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--panel);
  color: var(--text);
  font: inherit;
}

.chip-row {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}

/* Pill (matches .chip's pill footprint) around the bare native date widget — the two used to sit at
   different heights and read as stray, ungrouped controls next to the range chips. No visible "Von"/
   "Bis" label text (2026-09-07 user request: a single dash between the two inputs already says which
   side is which — kept as an aria-label on each input instead, so the fields stay accessible). */
.date-field {
  display: inline-flex;
  align-items: center;
  padding: 4px 6px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--panel);
  font-size: .85rem;
  color: var(--muted);
}

.date-field input[type="date"] {
  padding: 4px 8px;
  border: none;
  border-radius: var(--radius-sm);
  background: var(--panel-soft);
  color: var(--text);
  font: inherit;
}

.date-range-row {
  display: flex;
  align-items: center;
  flex: 1 1 100%;
  gap: 8px;
}

.date-range-dash {
  color: var(--muted);
  font-size: .85rem;
  flex: 0 0 auto;
}

.date-range-row .date-field {
  flex: 1 1 0;
}

.date-range-row .date-field input[type="date"] {
  width: 100%;
  box-sizing: border-box;
}

.btn-block {
  display: block;
  flex: 1 1 100%;
  width: 100%;
  box-sizing: border-box;
  text-align: center;
}

.remote-app-error {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin: 0 16px 8px;
  padding: 12px 14px;
  border: 1px solid var(--danger);
  border-radius: var(--radius-sm);
  background: var(--danger-soft);
  color: var(--danger);
}

/* F-XX/2026-09-07: a flex item's default `min-width: auto` locks its shrunk width to its own
 * min-content size — for this span, that means the longest unbreakable token in the error text (a
 * report filename with no spaces, e.g. "20260904-0011-CODE_REVIEW_...json", or a validateSpec message
 * quoting one). With the dismiss button pinned at `flex-shrink: 0` right below, that min-content floor
 * pushed the whole row past the viewport — the button ended up off-screen and undismissable, and the
 * page gained horizontal scroll (measured: 471px document width in a 390px viewport). Same bug class
 * as the `minmax(0, …)` fix on #listView's grid column above — `min-width: 0` lets this span shrink
 * below its min-content size so wrapping (`overflow-wrap`) can actually take effect instead of being
 * pre-empted by the flex algorithm. */
.remote-app-error span {
  min-width: 0;
  overflow-wrap: break-word;
}

.remote-app-error .btn { flex-shrink: 0; }

.remote-list-divider {
  padding: 12px 4px 2px;
  font-size: .78rem;
  font-weight: 700;
  letter-spacing: .02em;
  text-transform: uppercase;
  color: var(--muted);
}

.remote-list-divider:first-child { padding-top: 0; }

.remote-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 8px 16px 32px;
}

.remote-list-row {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 14px 16px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--panel);
  text-decoration: none;
  color: var(--text);
  box-shadow: var(--shadow);
}

.remote-list-row:hover,
.remote-list-row:focus-visible {
  border-color: var(--accent);
}

.remote-list-title {
  font-weight: 600;
}

/* The ✅/⏳ marker sits in front of the title (user request 2026-09-07). Shape and colours come from
   report-base.css, which the app already loads for the detail view — only the inline spacing is
   list-specific, and the fixed width keeps every title in the column starting at the same x. */
.remote-list-title .completion-badge.is-marker {
  display: inline-block;
  width: 1.3em;
  margin-right: 2px;
  color: inherit;
}

.remote-list-meta {
  color: var(--muted);
  font-size: .9rem;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
}

/* "total klar links": the code count is the one number that always matters, so it gets its own
   emphasized span on the left of the meta line instead of blending into the muted time text. */
.remote-list-total {
  font-weight: 600;
  color: var(--text);
}

/* Left-aligned, below a thin divider rule (2026-09-06 user feedback: was bottom-right, now left with
   an hr above it, matching the rest of the card's left-aligned text). */
.remote-list-divider-rule {
  width: 100%;
  border: none;
  border-top: 1px solid var(--border);
  margin: 6px 0 2px;
}

.remote-list-badges {
  display: flex;
  align-items: center;
  gap: 4px;
}

.sev-badge {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: 1px 7px;
  border-radius: 999px;
  font-size: .8rem;
  font-variant-numeric: tabular-nums;
}

.sev-badge.sev-krit { background: var(--danger-soft); color: var(--danger); }
.sev-badge.sev-warn { background: var(--warn-soft); color: var(--warn); }
.sev-badge.sev-info { background: var(--info-soft); color: var(--info); }
.sev-badge.sev-ok { background: var(--ok-soft); color: var(--ok); }

/* Positive gets the same badge shape as the Ampel pills (just its own green tint, no fraction — a
   Positive has no "open" state to contrast against, so "nur total pos" per user feedback). */
.sev-badge.pos-count { background: var(--ok-soft); color: var(--ok); }

.refine-marker {
  font-size: .95rem;
  line-height: 1;
}

.remote-app-state {
  padding: 16px;
  color: var(--muted);
}

#detailView .layout {
  min-height: 100vh;
}

/* Persistent (no auto-hide) — distinct from the transient #toast, since a stale-version notice must
   stay until the user acts on it, not disappear after 2.6s like a save-confirmation would. Full-width
   + stacked block button (not a small centered pill) so it reads as unmissable on mobile — the whole
   point of this banner is a hard-reload the user must not be able to overlook or accidentally dismiss
   by tapping past a slim strip. */
.update-banner {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 40;
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 14px 16px calc(14px + env(safe-area-inset-bottom, 0px));
  background: var(--panel);
  border-top: 2px solid var(--accent);
  box-shadow: 0 -4px 16px rgba(0, 0, 0, .35);
  font-size: .95rem;
}

.update-banner > span {
  text-align: center;
  font-weight: 600;
}

/* Shared by .update-banner and .install-banner (2026-09-07: install banner now has two peer buttons —
   "Installieren"/"Schließen" — styled identically to the update banner's own single-button row, not a
   separate icon-only close). Mobile: full-width blocks stacked one below the other; from the existing
   md breakpoint used elsewhere in this codebase (report-base.css .toolbar-row), lay them out as a row. */
.banner-actions {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

@media (min-width: 768px) {
  .banner-actions { flex-direction: row; }
}

.banner-actions .btn {
  display: block;
  width: 100%;
  box-sizing: border-box;
  padding: 13px;
  font-size: 1rem;
  text-align: center;
}

.lifecycle-spinner {
  position: fixed;
  top: 10px;
  right: 10px;
  z-index: 40;
  padding: 4px 10px;
  border-radius: 999px;
  background: var(--panel);
  border: 1px solid var(--border);
  color: var(--muted);
  font-size: .8rem;
  box-shadow: var(--shadow);
}

#backToList {
  text-decoration: none;
}

/* ---------------------------------------------------------------- Login (F-14/2026-09-07)
   Session login replaced HTTP Basic Auth, so the app now needs a page of its own instead of the
   browser's credential dialog. Uses the same tokens as the rest of the app — no separate palette. */

.login-body {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100dvh;
  margin: 0;
  padding: 1.5rem;
  background: var(--bg);
}

.login-card {
  width: 100%;
  max-width: 22rem;
  padding: 1.75rem 1.5rem 2rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg, 14px);
  background: var(--surface);
  box-shadow: var(--shadow);
}

.login-card h1 {
  margin: 0 0 0.25rem;
  font-size: 1.4rem;
}

.login-sub {
  margin: 0 0 1.25rem;
  color: var(--muted);
  font-size: 0.9rem;
}

.login-field {
  display: block;
  margin-bottom: 0.9rem;
}

.login-field span {
  display: block;
  margin-bottom: 0.3rem;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--muted);
}

.login-field input {
  width: 100%;
  box-sizing: border-box;
  padding: 0.6rem 0.7rem;
  font: inherit;
  color: var(--fg);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius, 10px);
}

.login-field input:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.login-error {
  margin-bottom: 1rem;
  padding: 0.6rem 0.75rem;
  border-radius: var(--radius, 10px);
  border: 1px solid var(--sev-krit, #b3261e);
  background: color-mix(in srgb, var(--sev-krit, #b3261e) 12%, transparent);
  font-size: 0.88rem;
}

/* The logout control sits in the header next to the push button. */
#logoutForm {
  display: inline;
}
