/* ClipSpark AI — foundation styles.
   Deliberately restrained; the full design system lands in Phase 9. */

:root {
  --bg: #0c0d12;
  --panel: #15171f;
  --panel-2: #1b1e28;
  --border: #262a36;
  --text: #eef0f6;
  --muted: #9aa0b0;
  --accent: #6a7dff;
  --ok: #4ade80;
  --warn: #fbbf24;
  --danger: #f87171;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
  background: var(--bg);
  color: var(--text);
  line-height: 1.6;
}

/* ---- Chrome ------------------------------------------------------------- */

.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 14px 20px;
  border-bottom: 1px solid var(--border);
  background: var(--panel);
}

.brand {
  font-weight: 700;
  font-size: 17px;
  color: var(--text);
  text-decoration: none;
}

.brand span { color: var(--accent); }

.topnav {
  display: flex;
  align-items: center;
  gap: 16px;
  font-size: 14px;
}

.topnav a { color: var(--muted); text-decoration: none; }
.topnav a:hover { color: var(--text); }

.inline-form { margin: 0; }

.linkbutton {
  padding: 0;
  border: none;
  background: none;
  color: var(--muted);
  font: inherit;
  cursor: pointer;
}

.linkbutton:hover { color: var(--text); }

.shell {
  flex: 1;
  width: 100%;
  max-width: 760px;
  margin: 0 auto;
  padding: 32px 20px 64px;
}

.footer {
  display: flex;
  justify-content: space-between;
  max-width: 760px;
  width: 100%;
  margin: 0 auto;
  padding: 20px;
  border-top: 1px solid var(--border);
  font-size: 13px;
  color: var(--muted);
}

/* ---- Panels ------------------------------------------------------------- */

.panel {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: 28px;
  margin-bottom: 20px;
}

.panel--form { max-width: 440px; margin: 24px auto; }
.panel--narrow { text-align: center; }
.panel--danger { border-color: #4a2630; }

.eyebrow {
  margin: 0 0 8px;
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent);
}

h1 { margin: 0 0 12px; font-size: 28px; line-height: 1.2; }
h2 { margin: 0 0 16px; font-size: 19px; }

.lead { margin: 0 0 24px; color: var(--muted); }
.muted { color: var(--muted); }

.note {
  margin: 0;
  padding-top: 20px;
  border-top: 1px solid var(--border);
  font-size: 14px;
  color: var(--muted);
}

.checklist { margin: 0 0 24px; padding-left: 20px; }
.checklist li { margin-bottom: 6px; }

code {
  background: #0f1118;
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 1px 6px;
  font-size: 13px;
}

a { color: var(--accent); }

/* ---- Forms -------------------------------------------------------------- */

label {
  display: block;
  margin-bottom: 6px;
  font-size: 14px;
  color: var(--text);
}

input[type="text"],
input[type="email"],
input[type="password"] {
  width: 100%;
  margin-bottom: 16px;
  padding: 11px 13px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 10px;
  color: var(--text);
  font-size: 15px;
}

input:focus {
  outline: none;
  border-color: var(--accent);
}

.checkbox-row {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  margin: 4px 0 20px;
}

.checkbox-row input[type="checkbox"] {
  width: 18px;
  height: 18px;
  margin-top: 2px;
  accent-color: var(--accent);
  flex-shrink: 0;
}

.checkbox-label {
  margin: 0;
  font-size: 13px;
  color: var(--muted);
}

.field-hint {
  margin: -10px 0 16px;
  font-size: 12px;
  color: var(--muted);
}

.field-error {
  margin: -10px 0 14px;
  font-size: 13px;
  color: var(--danger);
}

.formlinks {
  margin: 20px 0 0;
  padding-top: 16px;
  border-top: 1px solid var(--border);
  font-size: 14px;
  color: var(--muted);
  text-align: center;
}

.btn {
  display: inline-block;
  padding: 11px 22px;
  background: var(--accent);
  border: none;
  border-radius: 10px;
  color: #fff;
  font-size: 15px;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
}

.btn:hover { filter: brightness(1.08); }
.btn--block { width: 100%; }
.btn--sm { padding: 7px 14px; font-size: 13px; }
.btn--danger { background: #b91c3c; }

/* ---- Flash messages and banners ----------------------------------------- */

.flashes { margin-bottom: 20px; }

.flash {
  padding: 12px 16px;
  border: 1px solid var(--border);
  border-radius: 10px;
  margin-bottom: 10px;
  font-size: 14px;
}

.flash--info { background: #16203a; border-color: #27406e; color: #a8c4ff; }
.flash--success { background: #14291d; border-color: #245c39; color: var(--ok); }
.flash--warning { background: #2a2413; border-color: #5c4a1c; color: var(--warn); }
.flash--error { background: #2a1519; border-color: #5c2430; color: var(--danger); }

.banner {
  padding: 12px 16px;
  border-radius: 10px;
  margin-bottom: 20px;
  font-size: 14px;
}

.banner--warning { background: #2a2413; border: 1px solid #5c4a1c; color: var(--warn); }

/* ---- Data display ------------------------------------------------------- */

.statgrid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 12px;
}

.stat {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 16px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 12px;
}

.stat-label { font-size: 12px; color: var(--muted); }
.stat-value { font-size: 24px; font-weight: 700; }

.emptystate {
  padding: 28px;
  border: 1px dashed var(--border);
  border-radius: 12px;
  text-align: center;
  color: var(--muted);
}

/* Ledger tables. `.tablewrap` scrolls horizontally rather than letting a wide
   row stretch the page — a phone should scroll the table, not the layout. */
.tablewrap {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

.datatable {
  width: 100%;
  border-collapse: collapse;
  font-size: 14px;
}

.datatable th,
.datatable td {
  padding: 10px 12px;
  text-align: left;
  border-bottom: 1px solid var(--border);
  vertical-align: top;
}

.datatable th {
  font-size: 12px;
  font-weight: 600;
  color: var(--muted);
  white-space: nowrap;
}

.datatable tbody tr:last-child td { border-bottom: none; }

.datatable .num {
  text-align: right;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.datatable .field-hint { display: block; margin: 2px 0 0; }

/* Direction is carried by the sign as well as the colour, so the table still
   reads correctly in monochrome or to anyone who cannot distinguish the two. */
.amount--in { color: var(--ok); }
.amount--out { color: var(--muted); }

.emptystate p { margin: 0 0 6px; }

.emptystate-title {
  font-size: 16px;
  font-weight: 600;
  color: var(--text);
}

.table { width: 100%; border-collapse: collapse; font-size: 14px; }
.table th, .table td { padding: 9px 8px; text-align: left; border-bottom: 1px solid var(--border); }
.table th { font-size: 12px; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); }

.pill {
  display: inline-block;
  padding: 2px 10px;
  border-radius: 999px;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  vertical-align: middle;
}

.pill--ok { background: #14291d; color: var(--ok); }
.pill--warn { background: #2a2413; color: var(--warn); }

@media (max-width: 520px) {
  .panel { padding: 20px; }
  h1 { font-size: 24px; }
  .topnav { gap: 12px; font-size: 13px; }
}

/* ---- Phase 3: projects, uploads, history ---------------------------------
   Wider layout for the project pages; the auth pages keep the 760px shell. */

.shell--wide {
  max-width: 1060px;
}

.pagehead {
  margin-bottom: 24px;
}

.pagehead--split {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
}

.pagehead h1 {
  margin-bottom: 4px;
}

/* Filenames are user-supplied and can be 500 characters long. Clip them to the
   container rather than letting one blow out the layout. */
.truncate {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.layout {
  display: grid;
  grid-template-columns: 1fr 320px;
  gap: 20px;
  align-items: start;
}

@media (max-width: 820px) {
  .layout { grid-template-columns: 1fr; }
}

/* ---- Badges -------------------------------------------------------------- */

.badge {
  display: inline-block;
  padding: 3px 10px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  white-space: nowrap;
}

.badge--completed  { background: #14291d; color: var(--ok); }
.badge--draft      { background: #16203a; color: #8fb0ff; }
.badge--queued     { background: #2a2413; color: var(--warn); }
.badge--uploading  { background: #16203a; color: #8fb0ff; }
.badge--analyzing  { background: #16203a; color: #8fb0ff; }
.badge--rendering  { background: #16203a; color: #8fb0ff; }
.badge--failed     { background: #2a1519; color: var(--danger); }
.badge--cancelled  { background: #201d1d; color: var(--muted); }
.badge--deleted    { background: #201d1d; color: var(--muted); }

/* ---- Metalist ------------------------------------------------------------ */

.metalist {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 2px 18px;
  margin: 0;
  font-size: 14px;
}

.metalist div {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 0;
  border-bottom: 1px solid var(--border);
}

.metalist dt { color: var(--muted); }
.metalist dd { margin: 0; text-align: right; }

.metalist--stacked {
  grid-template-columns: 1fr;
}

.metalist--stacked div { border-bottom: none; padding: 2px 0; }

/* ---- Progress ------------------------------------------------------------ */

.progress {
  margin-bottom: 20px;
}

.progress-track {
  height: 12px;
  border-radius: 999px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  overflow: hidden;
}

.progress-fill {
  height: 100%;
  width: 0;
  border-radius: 999px;
  background: var(--accent);
  transition: width 0.4s ease;
}

.progress #job-label,
.progress .field-hint {
  margin-top: 8px;
  margin-bottom: 0;
}

/* The project card's version: same bar, thinner, no animation — it is a
   server-rendered snapshot, and a transition on first paint would imply it is
   moving when it is not. */
.progress-track--slim { height: 6px; }
.progress-track--slim .progress-fill { transition: none; }

.cardprogress { margin-top: 4px; }
.cardprogress .field-hint { margin: 6px 0 0; }

/* ---- Upload form --------------------------------------------------------- */

.fieldgroup {
  margin: 0 0 22px;
  padding: 0;
  border: none;
}

.fieldgroup legend {
  margin-bottom: 10px;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--muted);
}

.select {
  width: 100%;
  padding: 11px 13px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 10px;
  color: var(--text);
  font-size: 15px;
}

.input {
  width: 100%;
  /* Matches the text inputs above: .field-hint pulls itself up by 10px and
     expects the field it describes to have left that room. */
  margin-bottom: 16px;
  padding: 11px 13px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 10px;
  color: var(--text);
  font-size: 15px;
}

.input.number {
  max-width: 140px;
}

.checkrow {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0;
}

.checkrow input[type="checkbox"] {
  width: 18px;
  height: 18px;
  accent-color: var(--accent);
}

/* The row is dimmed but the "Coming soon" pill inside it is not, so the reason
   the control is unavailable stays legible. */
.checkrow--disabled { cursor: not-allowed; }
.checkrow--disabled > span { color: var(--muted); }
.checkrow--disabled .pill { color: var(--text); }

.ratio-options {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
}

@media (max-width: 520px) {
  .ratio-options { grid-template-columns: 1fr; }
}

.ratio-card {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  margin: 0;
  padding: 16px 10px 14px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--panel-2);
  cursor: pointer;
  text-align: center;
}

.ratio-card:hover { border-color: var(--accent); }

/* The radio stays visible rather than being hidden behind a styled card.
   The card border below is a `:has()` enhancement, and a browser without
   `:has()` would otherwise show no selected state at all. */
.ratio-input {
  margin: 0;
  accent-color: var(--accent);
  cursor: pointer;
}

.ratio-card:focus-within {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.ratio-card:has(.ratio-input:checked) {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent) inset;
}

.ratio-shape {
  display: block;
  border: 2px solid var(--muted);
  border-radius: 4px;
  background: transparent;
}

.ratio-shape--vertical   { width: 22px; height: 38px; }
.ratio-shape--square     { width: 30px; height: 30px; }
.ratio-shape--landscape  { width: 38px; height: 22px; }

.ratio-card:has(.ratio-input:checked) .ratio-shape { border-color: var(--accent); }

.ratio-name {
  font-size: 14px;
  font-weight: 600;
}

.ratio-desc {
  font-size: 12px;
  color: var(--muted);
}

/* ---- Dropzone ------------------------------------------------------------ */

.dropzone {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  margin-bottom: 18px;
  padding: 34px 20px;
  border: 2px dashed var(--border);
  border-radius: 14px;
  background: var(--panel-2);
  text-align: center;
  cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease;
}

.dropzone:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.dropzone:hover,
.dropzone.dz-active {
  border-color: var(--accent);
  background: #1a2030;
}

.dropzone.dz-error {
  border-color: var(--danger);
  background: #241418;
}

.dropzone-title {
  margin: 0;
  font-size: 16px;
  font-weight: 600;
}

.dropzone .field-hint {
  margin: 0;
}

.dropzone p + p { margin-top: 4px; }

.preview {
  max-width: 100%;
  max-height: 260px;
  margin-top: 12px;
  border-radius: 10px;
}

.formerrors {
  margin: 0 0 16px;
  padding: 12px 16px;
  border: 1px solid #5c2430;
  border-radius: 10px;
  background: #2a1519;
  color: var(--danger);
  font-size: 14px;
}

.formerrors p { margin: 0; }
.formerrors p + p { margin-top: 6px; }

.form-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
}

.form-actions .field-hint { flex-basis: 100%; }

/* ---- Project grid -------------------------------------------------------- */

.projectgrid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 16px;
}

.projectcard {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 18px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 14px;
}

.projectcard-link {
  text-decoration: none;
  color: var(--text);
}

.projectcard-link:hover .projectcard-title { color: var(--accent); }

.projectcard-title {
  margin: 8px 0 0;
  font-size: 16px;
  line-height: 1.35;
}

.projectcard .metalist {
  grid-template-columns: 1fr 1fr;
  font-size: 13px;
}

.inline-error {
  margin: 0;
  font-size: 13px;
  color: var(--danger);
}

.pager {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  margin-top: 24px;
}

/* ---- Storage meter ------------------------------------------------------- */

.meter {
  height: 8px;
  border-radius: 999px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  overflow: hidden;
}

.meter-fill {
  height: 100%;
  border-radius: 999px;
  background: var(--accent);
}

.panel--tight { padding: 16px 20px; }

.meterrow {
  display: flex;
  align-items: center;
  gap: 12px;
}

.meter-label { font-size: 13px; color: var(--muted); flex-shrink: 0; }
.meter-value { font-size: 13px; color: var(--muted); flex-shrink: 0; }
.meterrow .meter { flex: 1; }

.limitlist {
  margin: 0 0 18px;
  padding: 0;
  list-style: none;
  font-size: 14px;
}

.limitlist li {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding: 7px 0;
  border-bottom: 1px solid var(--border);
}

.limitlist li:last-child { border-bottom: none; }
.limitlist span { color: var(--muted); }
.limitlist strong { font-weight: 600; }

/* ---- Clip grid ----------------------------------------------------------- */

.clipgrid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: 16px;
}

.clipcard {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 16px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 12px;
}

.clipcard .metalist--stacked {
  font-size: 13px;
}

/* The clip is portrait more often than not, so the element is capped by height
   rather than width — an unconstrained 9:16 video makes a card twice as tall as
   the grid row it sits in. object-fit keeps the frame intact inside that cap. */
.clipcard-video {
  width: 100%;
  max-height: 340px;
  border-radius: 8px;
  background: #000;
  object-fit: contain;
}

.clipcard-title {
  margin: 0;
  font-size: 15px;
  font-weight: 600;
  line-height: 1.3;
}

.clipcard-hook {
  margin: 0;
  font-size: 13px;
  color: var(--muted);
  line-height: 1.45;
}

/* ---- Candidate reasoning ------------------------------------------------- */

.candidatelist {
  display: grid;
  gap: 12px;
}

.candidate {
  padding: 14px 16px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 10px;
}

/* Dimmed, not hidden: a moment the AI liked but ffmpeg could not cut is the
   most useful row on the page when someone asks why they got two clips. */
.candidate--dropped { opacity: 0.62; }

.candidate-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}

.candidate-head h3 {
  margin: 0;
  font-size: 15px;
  font-weight: 600;
}

.candidate-time {
  margin: 4px 0 0;
  font-size: 12px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.candidate-hook {
  margin: 8px 0 0;
  font-size: 14px;
  line-height: 1.5;
}

.candidate-reason {
  margin: 6px 0 0;
  font-size: 13px;
  color: var(--muted);
  line-height: 1.5;
}

.banner--info { background: #16203a; border: 1px solid #27406e; color: #a8c4ff; }
.banner--error { background: #2a1519; border: 1px solid #5c2430; color: var(--danger); }

/* ---- Ghost button -------------------------------------------------------
   Referenced since Phase 3 by the pager and the secondary actions on the
   project pages, and never defined — so those controls have been rendering as
   solid accent-coloured buttons competing with the primary action next to
   them. Defined here rather than in the Phase 6 block because it is not a
   billing style; it is the missing half of the button set. */

.btn--ghost {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text);
}

.btn--ghost:hover {
  background: var(--panel-2);
  filter: none;
}

.btn:disabled,
.btn[aria-disabled="true"] {
  opacity: 0.45;
  cursor: not-allowed;
  filter: none;
}

/* ---- Plans and billing (Phase 6) ---------------------------------------- */

.plangrid {
  display: grid;
  /* auto-fit rather than a fixed count: four plans on a desktop, two on a
     tablet, one on a phone, with no breakpoint to keep in step with the
     number of plans an admin has decided to sell. */
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 16px;
  margin-top: 4px;
}

.plancard {
  display: flex;
  flex-direction: column;
  padding: 20px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 12px;
}

.plancard--current { border-color: var(--accent); }
.plancard--pending { border-color: var(--warn); }

.plancard-name {
  margin: 0;
  font-size: 16px;
  font-weight: 600;
}

.plancard-price {
  margin: 10px 0 2px;
  font-size: 28px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.plancard-period {
  font-size: 13px;
  font-weight: 500;
  color: var(--muted);
}

.plancard-features {
  margin: 14px 0 18px;
  padding: 0;
  list-style: none;
  font-size: 13px;
  line-height: 1.9;
  color: var(--muted);
}

/* Pushes the button to the bottom edge whatever the feature list length, so a
   row of cards has its actions on one line instead of a ragged staircase. */
.plancard-action { margin-top: auto; }

.plancard-tag {
  display: inline-block;
  margin-bottom: 10px;
  padding: 3px 9px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  background: #1d2440;
  color: #a8c4ff;
}

.plancard-tag--pending { background: #2a2413; color: var(--warn); }

.pricerow {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 14px 0;
  border-bottom: 1px solid var(--border);
}

.pricerow:last-child { border-bottom: none; }

.actionrow {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 16px;
}

/* Payment statuses reuse `.badge`, but the project-status modifiers above do
   not cover them: a payment is succeeded/pending/failed/refunded, not
   queued/rendering/completed. `badge--failed` is already defined and means the
   same thing here, so it is not repeated. Without these four a payment row
   renders an unstyled pill, which reads as "no status" rather than as a
   status. */
.badge--succeeded { background: #14291d; color: var(--ok); }
.badge--pending   { background: #2a2413; color: var(--warn); }
.badge--refunded  { background: #201d1d; color: var(--muted); }
.badge--partially_refunded { background: #201d1d; color: var(--muted); }

/* The two money columns in the payments table. Refund and failure notes sit
   under the amount as hints, and a right-aligned `.num` cell needs them to
   stack rather than run on. */
.datatable .num .field-hint { text-align: right; }

/* ---- Phase 7: admin dashboard --------------------------------------------
   Deliberately short. The admin pages were built out of the vocabulary that
   already exists — .panel, .datatable, .statgrid, .badge, .pill, .emptystate —
   so what follows is only the handful of classes with no equivalent anywhere
   else in the app. */

/* Section nav under the top bar. Scrolls sideways rather than wrapping to two
   rows on a phone: nine links stacked would push the page content below the
   fold on every admin screen. */
.adminnav {
  display: flex;
  gap: 4px;
  margin-bottom: 24px;
  padding-bottom: 2px;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  border-bottom: 1px solid var(--border);
}

.adminnav a {
  padding: 8px 14px;
  border-radius: 8px 8px 0 0;
  font-size: 14px;
  color: var(--muted);
  text-decoration: none;
  white-space: nowrap;
}

.adminnav a:hover { color: var(--text); background: var(--panel-2); }

/* The underline sits inside the padding box so it lines up with the nav's own
   bottom border rather than floating above it. */
.adminnav a.is-active {
  color: var(--text);
  background: var(--panel);
  box-shadow: inset 0 -2px 0 var(--accent);
}

/* Filter row above a table: a text input and one or two selects, on one line
   where there is room and stacked where there is not. */
.filterbar {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
  margin-bottom: 16px;
}

/* `.input` carries a 16px bottom margin so `.field-hint` has room beneath it.
   Nothing in a filter row has a hint, and with `align-items: center` that
   margin would sit the text box half a line above the selects next to it. */
.filterbar .input,
.filterbar .select { width: auto; min-width: 150px; flex: 1 1 180px; margin-bottom: 0; }
.filterbar .btn { flex: 0 0 auto; }

/* Signup sparkline. Fourteen bars, scaled in the template against the busiest
   day; the container is a fixed height so an empty stretch does not collapse
   the panel to nothing. */
.sparkbars {
  display: flex;
  align-items: flex-end;
  gap: 6px;
  height: 120px;
  padding-top: 8px;
}

.sparkbar {
  position: relative;
  display: flex;
  flex: 1;
  flex-direction: column;
  justify-content: flex-end;
  align-items: center;
  height: 100%;
  gap: 4px;
}

.sparkbar-fill {
  width: 100%;
  min-height: 2px;
  border-radius: 4px 4px 0 0;
  background: var(--accent);
}

.sparkbar-label { font-size: 11px; color: var(--muted); }

/* The stack of destructive buttons on a user's page — suspend, force sign-out,
   role change. Each is its own form with its own reason field, so they are
   separated rather than crowded into a button row. */
.adminactions {
  display: grid;
  gap: 16px;
}

.adminactions form {
  padding: 16px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 12px;
}

/* One outstanding reservation: what is held, and the form that returns it. */
.stuckrow {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  padding: 14px 0;
  border-bottom: 1px solid var(--border);
}

.stuckrow:last-child { border-bottom: none; }
.stuckrow-title { margin: 0 0 4px; font-weight: 600; }
.stuckrow form { flex: 1 1 260px; }

/* Raw JSON: settings values, webhook payloads, job error detail. Scrolls in
   both directions inside its own box — a minified Stripe payload is one very
   long line, and letting it size the page would break every layout it sits in.
   Capped in height because a payload can run to hundreds of lines. */
.codeblock {
  max-height: 420px;
  margin: 0;
  padding: 14px;
  overflow: auto;
  background: #0a0b10;
  border: 1px solid var(--border);
  border-radius: 10px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 12px;
  line-height: 1.6;
  color: #c9d1e4;
  white-space: pre;
}

/* The editable counterpart: a textarea holding the same JSON. Monospace so the
   indentation the route pretty-printed still reads as structure.

   No height and no `white-space` here on purpose. The template sizes the box
   with `rows="{{ [line_count + 1, 24] | min }}"`, so a min-height would fight a
   number it worked out from the content; and a textarea's default `pre-wrap`
   wraps a long string value instead of hiding it off the right edge, which is
   what you want in a box someone has to edit. */
.codearea {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 12px;
  line-height: 1.6;
}

@media (max-width: 820px) {
  /* Below this the two halves of a stuck-reservation row have no room to sit
     side by side, and the release form is the half that needs the width. */
  .stuckrow { flex-direction: column; }
  .stuckrow form { width: 100%; }
}


/* ---------------------------------------------------------------------------
   Phase 8 — notifications, storage meter, sharing
   --------------------------------------------------------------------------- */

/* The nav bell. `position: relative` on the wrapper is what the dropdown
   anchors to, so the panel follows the button on every viewport instead of
   being positioned against the page. */
.bell { position: relative; display: inline-flex; }

.bell-button {
  position: relative;
  padding: 4px 8px;
  background: none;
  border: none;
  color: var(--muted);
  font: inherit;
  font-size: 15px;
  cursor: pointer;
  line-height: 1;
}

.bell-button:hover { color: var(--text); }

/* The count. Absolutely positioned so a two-character badge ("9+") does not
   widen the nav and shift everything beside it. */
.bell-badge {
  position: absolute;
  top: -2px;
  right: -2px;
  min-width: 16px;
  padding: 1px 4px;
  border-radius: 999px;
  background: var(--accent);
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  line-height: 14px;
  text-align: center;
}

.is-hidden { display: none !important; }

.bell-panel {
  position: absolute;
  top: calc(100% + 10px);
  right: 0;
  z-index: 40;
  width: 320px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: 0 18px 40px rgba(0, 0, 0, 0.45);
  overflow: hidden;
}

.bell-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 14px;
  border-bottom: 1px solid var(--border);
  font-size: 13px;
}

/* Capped and scrollable: the feed returns at most eight rows, but a long title
   plus body on each of them still overruns a short window. */
.bell-list { max-height: 320px; overflow-y: auto; }

.bell-items { margin: 0; padding: 0; list-style: none; }
.bell-item { border-bottom: 1px solid var(--border); }
.bell-item:last-child { border-bottom: none; }

.bell-link {
  display: block;
  padding: 11px 14px;
  color: var(--text);
  text-decoration: none;
}

.bell-link:hover { background: var(--panel-2); }

/* Unread earns the accent bar; read rows stay quiet. The distinction has to
   survive a glance, which a font-weight change alone does not. */
.bell-link.is-unread { border-left: 2px solid var(--accent); }

.bell-title { font-size: 13px; font-weight: 600; }
.bell-body { margin-top: 2px; font-size: 12px; color: var(--muted); }
.bell-empty { margin: 0; padding: 18px 14px; color: var(--muted); font-size: 13px; }

.bell-foot {
  display: block;
  padding: 11px 14px;
  border-top: 1px solid var(--border);
  color: var(--accent);
  font-size: 13px;
  text-decoration: none;
  text-align: center;
}

.bell-foot:hover { background: var(--panel-2); }

/* The full notification list. */
.notelist { margin: 0; padding: 0; list-style: none; }

.note {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  padding: 14px 0;
  border-bottom: 1px solid var(--border);
}

.note:last-child { border-bottom: none; }
.note-main { flex: 1 1 auto; min-width: 0; }
.note-title { color: var(--text); font-weight: 600; text-decoration: none; }
.note-title:hover { color: var(--accent); }
.note-body { margin: 4px 0 0; color: var(--muted); font-size: 13px; }
.note-meta {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 6px 0 0;
  color: var(--muted);
  font-size: 12px;
}

/* Unread rows get a left rule that sits outside the text column, so it reads
   as a marker on the row rather than an indent of the content. */
.note.is-unread {
  margin-left: -12px;
  padding-left: 10px;
  border-left: 2px solid var(--accent);
}

/* Storage quota meter. A native <progress> styles inconsistently across
   browsers, so this is two divs whose inner width is set from the server's
   percentage. */
.meter {
  height: 8px;
  margin: 8px 0 6px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 999px;
  overflow: hidden;
}

.meter-fill { height: 100%; background: var(--accent); border-radius: 999px; }

/* Modifiers named for `storage_summary.state`, not for colours, so the
   thresholds live in one place — the service — and the stylesheet only decides
   what each state looks like. `ok` needs no rule; it is the base. */
.meter-fill--warning { background: var(--warn); }
.meter-fill--critical { background: var(--warn); }
.meter-fill--full { background: var(--danger); }

.meter-note { margin: 4px 0 0; font-size: 12px; color: var(--warn); }

.meter-label {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  font-size: 12px;
  color: var(--muted);
}

/* Share links on the project page. */
.sharerow {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 0;
  border-bottom: 1px solid var(--border);
}

.sharerow:last-child { border-bottom: none; }

/* The one time the raw token is ever visible. Selectable, wrapping, and
   monospace, because it exists to be copied. */
.sharelink {
  width: 100%;
  padding: 10px 12px;
  background: #0a0b10;
  border: 1px solid var(--border);
  border-radius: 8px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 12px;
  color: #c9d1e4;
  word-break: break-all;
}

/* The public share page: no nav to align to, so it centres on its own. */
.center-panel { max-width: 720px; margin: 40px auto; text-align: center; }
.share-video {
  width: 100%;
  max-height: 70vh;
  margin: 18px 0;
  background: #000;
  border-radius: 10px;
}
.share-actions { margin: 0 0 14px; }

@media (max-width: 560px) {
  /* At this width a 320px dropdown anchored right would hang off the edge on
     the narrowest phones; pinning both edges keeps it on screen. */
  .bell-panel { position: fixed; left: 12px; right: 12px; width: auto; }
}
