/* ==========================================================================
   AstroChris — admin.css
   Admin-panel-only styles, loaded AFTER main.css on /admin and nowhere else.

   Rules of engagement:
     * main.css owns the design system. This file adds the handful of patterns
       the public site has no use for (tab bar, data tables, dense form grid)
       and reuses every token from :root. No literal colours, no new fonts.
     * Public classes (.btn, .input, .panel, .chip, .badge, .notice, .empty,
       .field, .label, .help) are used as-is; only admin-specific classes are
       defined here, all prefixed .admin-* or clearly panel-local.
     * The admin panel is not indexed and never server-rendered — it is a
       static page plus /js/admin.js.

   Contents
     1.  Page frame and the admin bar
     2.  Tab bar
     3.  Panels and toolbars
     4.  Tables
     5.  Forms (dense grid) and uploads
     5b. Side-by-side markdown editor and preview pane
     5c. Collection membership picker
     6.  Comment moderation list
     7.  Row actions, two-step confirm, toasts, session banner
     8.  Responsive and reduced motion
   ========================================================================== */

/* ------------------------------------------- 1. Page frame and the admin bar */

.page-admin {
  /* No starfield here: the admin panel is a work surface, not a showcase. */
  background:
    radial-gradient(1000px 600px at 85% -10%, rgba(58, 78, 130, 0.18), transparent 60%),
    linear-gradient(180deg, #070b16 0%, var(--bg) 45%, var(--bg-deep) 100%);
  background-attachment: fixed;
}

.admin-bar {
  position: sticky;
  top: 0;
  z-index: 40;
  background: rgba(5, 7, 14, 0.86);
  backdrop-filter: saturate(140%) blur(12px);
  -webkit-backdrop-filter: saturate(140%) blur(12px);
  border-bottom: 1px solid var(--border);
}

.admin-bar__inner {
  min-height: 52px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2xs);
}

/* A smaller brand than the public header — this is a tool, not the site. */
.admin-bar .brand {
  font-size: 0.95rem;
  gap: 0.45rem;
}

.admin-bar__tag {
  padding: 0.1rem 0.55rem;
  border: 1px solid var(--accent-line);
  border-radius: var(--radius-pill);
  background: var(--accent-soft);
  color: var(--accent);
  font-family: var(--font-display);
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.admin-bar__spacer { flex: 1 1 auto; }

.admin-bar__who {
  max-width: 22rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text-dim);
  font-size: var(--step--1);
}

/* -------------------------------------------------------------- 2. Tab bar */
/* One button per section. A later phase appends Objects / Posts / Events /
   Collections; nothing here is per-tab, so no CSS change is needed for that. */

.tabbar {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3xs);
  margin: var(--space-md) 0 var(--space-md);
  padding-bottom: var(--space-3xs);
  border-bottom: 1px solid var(--border);
}

.tabbar__btn {
  appearance: none;
  padding: 0.5rem 0.95rem;
  border: 1px solid transparent;
  border-bottom: 0;
  border-radius: var(--radius-sm) var(--radius-sm) 0 0;
  background: transparent;
  color: var(--text-muted);
  font-family: var(--font-display);
  font-size: 0.9375rem;
  font-weight: 500;
  letter-spacing: 0.01em;
  cursor: pointer;
  transition: color var(--transition), background-color var(--transition);
}

.tabbar__btn:hover {
  color: var(--text);
  background: rgba(146, 170, 214, 0.07);
}

.tabbar__btn[aria-selected='true'] {
  color: var(--accent);
  background: var(--accent-soft);
  border-color: var(--accent-line);
  border-bottom: 0;
  box-shadow: inset 0 -2px 0 0 var(--accent);
}

.tabbar__count {
  margin-left: 0.4rem;
  color: var(--text-dim);
  font-size: 0.75rem;
  font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------- 3. Panels and toolbars */

.admin-panel[hidden] { display: none; }

.admin-panel {
  padding-bottom: var(--space-2xl);
}

.admin-section + .admin-section { margin-top: var(--space-lg); }

.admin-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2xs);
  margin-bottom: var(--space-sm);
}

.admin-toolbar__title {
  margin: 0;
  font-size: var(--step-2);
}

.admin-toolbar__spacer { flex: 1 1 auto; }

.admin-toolbar .input { max-width: 18rem; }
.admin-toolbar .select { max-width: 12rem; }

/* --------------------------------------------------------------- 4. Tables */

.table-wrap {
  overflow-x: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--panel);
}

.admin-table {
  width: 100%;
  margin: 0;
  border-collapse: collapse;
  font-size: 0.9375rem;
}

.admin-table th,
.admin-table td {
  padding: 0.6rem 0.75rem;
  text-align: left;
  vertical-align: middle;
  border-bottom: 1px solid var(--border);
}

.admin-table thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--panel-solid);
  color: var(--text-dim);
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
}

.admin-table tbody tr:last-child td { border-bottom: 0; }
.admin-table tbody tr:hover { background: rgba(146, 170, 214, 0.05); }

.admin-table__title {
  font-weight: 600;
  color: var(--text);
}

.admin-table__sub {
  display: block;
  color: var(--text-dim);
  font-size: var(--step--1);
}

.admin-table__num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.admin-table__actions {
  white-space: nowrap;
  text-align: right;
}

/* Fixed-size thumbnail cell so a missing image does not reflow the row. */
.thumb {
  width: 68px;
  height: 48px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: linear-gradient(160deg, #0d1424, #070b14);
  object-fit: cover;
  overflow: hidden;
}

.thumb--empty {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--text-dim);
  font-size: 0.65rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.badge--live {
  background: color-mix(in srgb, var(--success) 18%, transparent);
  color: var(--success);
}

.badge--draft {
  background: rgba(146, 170, 214, 0.12);
  color: var(--text-muted);
}

.badge--flag {
  background: var(--accent-soft);
  color: var(--accent);
}

/* -------------------------------------------------- 5. Forms and uploads */

.admin-form {
  margin-top: var(--space-md);
  padding: var(--space-md);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  background: var(--panel);
}

.admin-form[hidden] { display: none; }

.admin-form__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2xs);
  margin-bottom: var(--space-sm);
}

.admin-form__title {
  margin: 0;
  font-size: var(--step-1);
}

.admin-form__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2xs);
  margin-top: var(--space-md);
  padding-top: var(--space-sm);
  border-top: 1px solid var(--border);
}

/* Dense two/three column grid. .field already supplies the label spacing. */
.form-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
  gap: 0 var(--space-sm);
}

.form-grid--wide {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 22rem), 1fr));
}

.field--full { grid-column: 1 / -1; }

/* Checkbox / radio row: the label sits beside the control, not above it. */
.check {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: var(--space-sm);
  color: var(--text-muted);
  font-size: 0.9375rem;
}

.check input[type='checkbox'] {
  width: 1.05rem;
  height: 1.05rem;
  accent-color: var(--accent);
  cursor: pointer;
  flex: none;
}

.check label { cursor: pointer; }

.fieldset {
  margin: 0 0 var(--space-sm);
  padding: var(--space-sm);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: rgba(3, 5, 12, 0.35);
}

.fieldset > legend {
  padding: 0 0.4rem;
  color: var(--text-dim);
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* Upload block: file input, preview, progress bar. */
.upload {
  display: grid;
  grid-template-columns: 96px 1fr;
  gap: var(--space-sm);
  align-items: start;
}

.upload__preview {
  width: 96px;
  height: 72px;
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-sm);
  background: linear-gradient(160deg, #0d1424, #070b14);
  object-fit: cover;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-dim);
  font-size: 0.65rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  overflow: hidden;
}

/* The preview is a box with an optional <img> injected into it, never a
   blob: URL — the CSP img-src is 'self' data: and does not allow blob:. */
.upload__preview img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.upload__body { min-width: 0; }

.upload input[type='file'] {
  width: 100%;
  font-size: var(--step--1);
  color: var(--text-muted);
}

.upload input[type='file']::file-selector-button {
  margin-right: 0.6rem;
  padding: 0.35rem 0.8rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--text);
  font-size: var(--step--1);
  cursor: pointer;
}

.progress {
  height: 6px;
  margin-top: var(--space-2xs);
  border-radius: var(--radius-pill);
  background: rgba(146, 170, 214, 0.14);
  overflow: hidden;
}

.progress[hidden] { display: none; }

.progress__bar {
  height: 100%;
  width: 0;
  border-radius: inherit;
  background: var(--accent);
  transition: width 120ms linear;
}

.upload__status {
  margin: var(--space-3xs) 0 0;
  font-size: var(--step--1);
  color: var(--text-dim);
}

/* ------------------- 5b. Side-by-side markdown editor and preview pane */
/* Used by the Posts body editor and the Collections intro editor. Both panes
   are the same width and scroll independently, so the source and the rendered
   result stay on screen together. Below 900px they stack: a 40-character
   textarea beside a 40-character preview helps nobody. */

.editor-split {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-sm);
  margin-bottom: var(--space-sm);
}

.editor-split__pane { min-width: 0; }

.editor-split__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2xs);
  margin-bottom: var(--space-3xs);
}

.editor-split__head .label { margin: 0; }

/* A monospaced source pane that does not wrap markdown tables into soup. */
.editor-split__source {
  min-height: 22rem;
  resize: vertical;
  line-height: 1.55;
  tab-size: 2;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* The rendered pane. Height-matched to the textarea and scrolled, never
   growing the page: an 8,000-word post must not push the Save button below
   three screenfuls of preview. */
.preview-pane {
  min-height: 22rem;
  max-height: 60vh;
  padding: var(--space-sm);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: rgba(3, 5, 12, 0.35);
  overflow-y: auto;
  overflow-wrap: anywhere;
}

.preview-pane > :first-child { margin-top: 0; }
.preview-pane > :last-child { margin-bottom: 0; }

/* Wide markdown output (tables, code fences) scrolls inside the pane rather
   than widening the whole panel. */
.preview-pane pre,
.preview-pane table { max-width: 100%; }
.preview-pane img { max-width: 100%; height: auto; }

/* The local-autosave restore offer. Informational, not an error: it is a
   choice being presented, and it is never applied without a click. */
.draft-restore {
  margin-bottom: var(--space-sm);
  border-left: 3px solid var(--accent);
}

.draft-restore[hidden] { display: none; }

.draft-restore__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3xs);
  margin: var(--space-2xs) 0 0;
}

/* --------------------------------------- 5c. Collection membership picker */
/* Two panes: everything available on the left, the ordered membership on the
   right. Reordering is Up/Down buttons rather than drag-and-drop on purpose —
   buttons are keyboard-operable, need no pointer precision, and cannot drop a
   photo into the wrong collection. */

.picker {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-sm);
}

.picker__pane { min-width: 0; }

.picker__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2xs);
  margin-bottom: var(--space-3xs);
}

.picker__head .label { margin: 0; }
.picker__head .input { max-width: 12rem; }

.picker__list {
  display: grid;
  gap: var(--space-3xs);
  max-height: 26rem;
  margin: 0;
  padding: var(--space-2xs);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: rgba(3, 5, 12, 0.35);
  list-style: none;
  overflow-y: auto;
}

/* The members pane is an <ol>: the number IS the sort_index the save writes. */
.picker__list--members {
  padding-left: var(--space-md);
  list-style: decimal;
}

.picker__item {
  display: grid;
  gap: var(--space-3xs);
  padding: var(--space-2xs);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--panel);
  font-size: 0.9375rem;
}

.picker__item--member { border-left: 3px solid var(--accent-line); }

.picker__row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2xs);
}

.picker__label {
  flex: 1 1 12rem;
  min-width: 0;
  color: var(--text-muted);
  overflow-wrap: anywhere;
}

.picker__note { font-size: var(--step--1); }

/* A past event is still editable, just visually demoted. */
.admin-table tbody tr.is-past { opacity: 0.6; }
.admin-table tbody tr.is-past:hover { opacity: 1; }

/* ------------------------------------------- 6. Comment moderation list */

.comment-list {
  display: grid;
  gap: var(--space-2xs);
  margin: 0;
  padding: 0;
  list-style: none;
}

.comment-card {
  display: grid;
  gap: var(--space-2xs);
  padding: var(--space-sm);
  border: 1px solid var(--border);
  border-left-width: 3px;
  border-radius: var(--radius);
  background: var(--panel);
}

.comment-card--hidden {
  border-left-color: var(--text-dim);
  opacity: 0.72;
}

.comment-card--visible { border-left-color: var(--success); }
.comment-card--pending { border-left-color: var(--accent); }

.comment-card__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2xs);
  font-size: var(--step--1);
  color: var(--text-dim);
}

.comment-card__author {
  color: var(--text);
  font-weight: 600;
  font-size: 0.9375rem;
}

.comment-card__body {
  margin: 0;
  color: var(--text-muted);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.comment-card__foot {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3xs);
  align-items: center;
}

/* ------------------ 7. Row actions, two-step confirm, toasts, session banner */

.row-actions {
  display: inline-flex;
  flex-wrap: wrap;
  gap: var(--space-3xs);
  justify-content: flex-end;
}

.btn--danger {
  border-color: color-mix(in srgb, var(--danger) 45%, transparent);
  color: var(--danger);
}

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

/* Second stage of the inline confirm. No browser confirm() dialogs anywhere:
   they are modal, unstyled, and block the whole panel. */
.btn--danger.is-armed {
  background: var(--danger);
  border-color: var(--danger);
  color: #1a0606;
  font-weight: 600;
}

.toasts {
  position: fixed;
  right: var(--space-sm);
  bottom: var(--space-sm);
  z-index: 80;
  display: grid;
  gap: var(--space-2xs);
  width: min(24rem, calc(100vw - 2 * var(--space-sm)));
  pointer-events: none;
}

.toast {
  padding: var(--space-2xs) var(--space-xs);
  border: 1px solid var(--border-strong);
  border-left-width: 3px;
  border-radius: var(--radius-sm);
  background: var(--panel-solid);
  box-shadow: var(--shadow);
  color: var(--text);
  font-size: 0.9375rem;
  overflow-wrap: anywhere;
  animation: toast-in 160ms ease-out;
}

.toast--error { border-left-color: var(--danger); }
.toast--success { border-left-color: var(--success); }
.toast--info { border-left-color: var(--accent); }

@keyframes toast-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}

/* The Access-session banner. Sticky, never auto-dismissed, and it never
   touches form state — losing a half-written record to an expired session is
   risk R8 in the plan. */
.session-banner {
  position: sticky;
  top: 52px;
  z-index: 30;
  margin: var(--space-sm) 0 0;
}

.session-banner[hidden] { display: none; }

.session-banner__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3xs);
  margin-top: var(--space-2xs);
}

/* Host for the inline sign-in form on a 401 (js/auth-form.js mounts into it).
   The .auth-form rules in main.css do the rest. */
.session-banner__signin {
  margin-top: var(--space-2xs);
}

.session-banner__signin[hidden] { display: none; }

/* ------------------------------------- 8. Responsive and reduced motion */

/* The two split layouts stack before the rest of the panel does: two 40-column
   panes are worse than one full-width one well before 720px. */
@media (max-width: 900px) {
  .editor-split,
  .picker { grid-template-columns: 1fr; }

  .preview-pane { max-height: 40vh; }
}

@media (max-width: 720px) {
  .admin-bar__who { max-width: 100%; flex-basis: 100%; }
  .admin-bar__spacer { flex-basis: 0; }

  .upload { grid-template-columns: 1fr; }

  .admin-table th,
  .admin-table td { padding: 0.5rem; }

  .admin-table__actions { text-align: left; }
  .row-actions { justify-content: flex-start; }

  .toasts {
    left: var(--space-sm);
    right: var(--space-sm);
    width: auto;
  }
}

@media (prefers-reduced-motion: reduce) {
  .toast { animation: none; }
  .progress__bar { transition: none; }
}
