/* See the Tailwind configuration guide for advanced usage
   https://tailwindcss.com/docs/configuration */

@import "tailwindcss" source(none);
@source "../css";
@source "../js";
@source "../../lib/masthead_web";

/* A Tailwind plugin that makes "hero-#{ICON}" classes available.
   The heroicons installation itself is managed by your mix.exs */
@plugin "../vendor/heroicons";

/* daisyUI — loaded from the npm package (see assets/package.json), not a
   vendored file, so the build never downloads it from GitHub. */
@plugin "daisyui" {
  themes: false;
}

/* daisyUI theme plugin (npm: daisyui/theme). Two custom themes — a dark one
   inspired by Elixir and a light one inspired by Phoenix. Build your own at:
   https://daisyui.com/theme-generator/ */
@plugin "daisyui/theme" {
  name: "dark";
  default: false;
  prefersdark: true;
  color-scheme: "dark";
  --color-base-100: oklch(30.33% 0.016 252.42);
  --color-base-200: oklch(25.26% 0.014 253.1);
  --color-base-300: oklch(20.15% 0.012 254.09);
  --color-base-content: oklch(97.807% 0.029 256.847);
  --color-primary: oklch(58% 0.233 277.117);
  --color-primary-content: oklch(96% 0.018 272.314);
  --color-secondary: oklch(58% 0.233 277.117);
  --color-secondary-content: oklch(96% 0.018 272.314);
  --color-accent: oklch(60% 0.25 292.717);
  --color-accent-content: oklch(96% 0.016 293.756);
  --color-neutral: oklch(37% 0.044 257.287);
  --color-neutral-content: oklch(98% 0.003 247.858);
  --color-info: oklch(58% 0.158 241.966);
  --color-info-content: oklch(97% 0.013 236.62);
  --color-success: oklch(60% 0.118 184.704);
  --color-success-content: oklch(98% 0.014 180.72);
  --color-warning: oklch(66% 0.179 58.318);
  --color-warning-content: oklch(98% 0.022 95.277);
  --color-error: oklch(58% 0.253 17.585);
  --color-error-content: oklch(96% 0.015 12.422);
  --radius-selector: 0.25rem;
  --radius-field: 0.25rem;
  --radius-box: 0.5rem;
  --size-selector: 0.21875rem;
  --size-field: 0.21875rem;
  --border: 1.5px;
  --depth: 1;
  --noise: 0;
}

@plugin "daisyui/theme" {
  name: "light";
  default: true;
  prefersdark: false;
  color-scheme: "light";
  --color-base-100: oklch(98% 0 0);
  --color-base-200: oklch(96% 0.001 286.375);
  --color-base-300: oklch(92% 0.004 286.32);
  --color-base-content: oklch(21% 0.006 285.885);
  --color-primary: oklch(70% 0.213 47.604);
  --color-primary-content: oklch(98% 0.016 73.684);
  --color-secondary: oklch(55% 0.027 264.364);
  --color-secondary-content: oklch(98% 0.002 247.839);
  --color-accent: oklch(0% 0 0);
  --color-accent-content: oklch(100% 0 0);
  --color-neutral: oklch(44% 0.017 285.786);
  --color-neutral-content: oklch(98% 0 0);
  --color-info: oklch(62% 0.214 259.815);
  --color-info-content: oklch(97% 0.014 254.604);
  --color-success: oklch(70% 0.14 182.503);
  --color-success-content: oklch(98% 0.014 180.72);
  --color-warning: oklch(66% 0.179 58.318);
  --color-warning-content: oklch(98% 0.022 95.277);
  --color-error: oklch(58% 0.253 17.585);
  --color-error-content: oklch(96% 0.015 12.422);
  --radius-selector: 0.25rem;
  --radius-field: 0.25rem;
  --radius-box: 0.5rem;
  --size-selector: 0.21875rem;
  --size-field: 0.21875rem;
  --border: 1.5px;
  --depth: 1;
  --noise: 0;
}

/* Add variants based on LiveView classes */
@custom-variant phx-click-loading (.phx-click-loading&, .phx-click-loading &);
@custom-variant phx-submit-loading (.phx-submit-loading&, .phx-submit-loading &);
@custom-variant phx-change-loading (.phx-change-loading&, .phx-change-loading &);

/* Use the data attribute for dark mode  */
@custom-variant dark (&:where([data-theme=dark], [data-theme=dark] *));

/* Make LiveView wrapper divs transparent for layout */
[data-phx-session], [data-phx-teleported-src] { display: contents }

/* ---- Masthead: admin + auth + marketing ---- */

:root {
  /* The landing palette (slate) — kept apart from the admin palette (zinc)
     below. Lives here rather than on `.landing` so the signed-out
     marketplace header can wear the same colours as the homepage nav. */
  --landing-fg: #0f172a;
  --landing-fg-soft: #334155;
  --landing-muted: #64748b;
  --landing-rule: #e2e8f0;
  --landing-bg: #f8fafc;
  --landing-card: #ffffff;
  --landing-accent: #2563eb;
  --landing-accent-hover: #1d4ed8;
  --landing-accent-soft: #eff6ff;

  --fg: #18181b;
  --fg-soft: #3f3f46;
  --muted: #71717a;
  --rule: #e4e4e7;
  --rule-strong: #d4d4d8;
  --bg: #f4f4f5;
  --bg-soft: #fafafa;
  --card: #ffffff;
  --accent: #2563eb;
  --accent-hover: #1d4ed8;
  --accent-soft: #eff6ff;
  --accent-strong: #1e40af;
  --danger: #dc2626;
  --danger-soft: #fef2f2;
  --good: #16a34a;
  --good-soft: #ecfdf5;
  --amber: #d97706;
  --amber-soft: #fef3c7;
  --violet: #7c3aed;
  --violet-soft: #f3e8ff;
  --shadow-sm: 0 1px 2px rgba(15, 23, 42, 0.05);
  --shadow-md: 0 4px 14px -2px rgba(15, 23, 42, 0.07), 0 2px 6px -2px rgba(15, 23, 42, 0.04);
  --shadow-lg: 0 14px 34px -10px rgba(15, 23, 42, 0.12), 0 4px 12px -4px rgba(15, 23, 42, 0.06);
}

body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Inter", "Helvetica Neue", Arial, sans-serif;
  background: var(--bg);
  color: var(--fg);
  line-height: 1.5;
}
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
code { font-family: ui-monospace, Menlo, monospace; font-size: 0.9em; background: #f4f4f5; padding: 0.1em 0.35em; border-radius: 3px; }
.muted { color: var(--muted); }
.empty { color: var(--muted); padding: 1.5rem 0; }
.error { color: var(--danger); margin-top: 0.4rem; }

.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 3rem 2rem;
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: 14px;
  box-shadow: var(--shadow-sm);
}
.empty-state h2 {
  margin: 0 0 0.4rem;
  font-size: 1.2rem;
  font-weight: 600;
  letter-spacing: -0.015em;
  color: var(--fg);
}
.empty-state p {
  margin: 0 0 1.5rem;
  color: var(--muted);
  max-width: 40ch;
}
/* Top-anchor the stack and pin a min-height so every illustrated empty
   state is the same height and its button lands in the same place — even
   the checklist's "all caught up" state, which has no button. */
.empty-state-illustrated {
  padding: 4rem 2rem;
  justify-content: flex-start;
  min-height: 33rem;
}
/* Fixed box + object-fit so drawings of differing aspect ratios all
   occupy the same vertical space. */
.empty-illustration {
  width: 100%;
  max-width: 320px;
  height: 220px;
  object-fit: contain;
  margin-bottom: 1.75rem;
  user-select: none;
  pointer-events: none;
}
/* Reserve ~2 lines so a one- vs two-line message doesn't shift the button. */
.empty-state-illustrated p { min-height: 2.6em; }

.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.5rem 0.9rem;
  border-radius: 8px;
  border: 1px solid var(--rule);
  background: var(--card);
  cursor: pointer;
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--fg);
  box-shadow: none;
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
.btn:hover { text-decoration: none; background: var(--bg-soft); }
.btn-primary {
  background: var(--accent);
  color: white;
  border-color: var(--accent);
}
.btn-primary:hover {
  background: var(--accent-hover);
  border-color: var(--accent-hover);
  color: white;
}
.btn-danger {
  background: var(--danger-soft);
  color: var(--danger);
  border: 0;
  border-radius: 999px;
  padding: 0.4rem 1rem;
  box-shadow: none;
}
.btn-danger:hover {
  background: #fee2e2;
  color: #b91c1c;
}
.btn .icon { width: 1em; height: 1em; flex: 0 0 auto; }
.btn-sm { padding: 0.35rem 0.85rem; font-size: 0.8rem; }
.btn-danger.btn-sm { padding: 0.3rem 0.8rem; }

/* Header "create" buttons (`+ New …`). On phones they collapse to a compact
   icon-only "+" so the action stays top-right without crowding the title. */
.btn-add-icon { font-weight: 600; }
@media (max-width: 640px) {
  .btn-add { padding-left: 0.65rem; padding-right: 0.65rem; }
  .btn-add .btn-add-label { display: none; }
  .btn-add .btn-add-icon { font-size: 1.1rem; line-height: 1; }
}
.btn:disabled { opacity: 0.5; cursor: not-allowed; }

/* Right-align an actions column in tables */
.table td.actions-cell, .table th.actions-cell { text-align: right; }

/* Auth pages */
.auth-page { min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 2rem; }
.auth-card { background: var(--card); border: 1px solid var(--rule); border-radius: 10px; padding: 2rem; width: 100%; max-width: 380px; box-shadow: 0 1px 2px rgba(0,0,0,0.04); }
.auth-card h1 { margin-top: 0; font-size: 1.4rem; }
.auth-card form { display: flex; flex-direction: column; gap: 0.9rem; }
.auth-card label { display: flex; flex-direction: column; gap: 0.35rem; font-size: 0.875rem; }
.auth-card input { padding: 0.55rem 0.75rem; border: 1px solid var(--rule); border-radius: 6px; font-size: 0.95rem; }
.auth-card input:focus { outline: 2px solid var(--accent); outline-offset: -1px; border-color: var(--accent); }
.auth-card button { margin-top: 0.5rem; padding: 0.6rem; border: 0; border-radius: 6px; background: var(--accent); color: white; font-weight: 500; cursor: pointer; }
.auth-card button:hover { background: var(--accent-hover); }
.auth-card .meta { font-size: 0.875rem; color: var(--muted); margin-top: 1rem; margin-bottom: 0; text-align: center; }
.auth-card .error { background: #fef2f2; color: var(--danger); padding: 0.5rem 0.75rem; border-radius: 6px; font-size: 0.875rem; margin: 0; }
.auth-card .errors { list-style: none; padding: 0.5rem 0.75rem; background: #fef2f2; border-radius: 6px; color: var(--danger); font-size: 0.85rem; margin: 0; }

/* Admin shell — sidebar layout */
:root {
  --sidebar-width: 220px;
  --sidebar-bg: #0a0a0b;
  --sidebar-bg-hover: #18181b;
  --sidebar-border: #1f1f23;
  --sidebar-fg: #d4d4d8;
  --sidebar-fg-muted: #71717a;
  --sidebar-fg-active: #ffffff;
}

.admin-shell { min-height: 100vh; display: flex; }

.admin-sidebar {
  width: var(--sidebar-width);
  background: var(--sidebar-bg);
  color: var(--sidebar-fg);
  display: flex;
  flex-direction: column;
  position: sticky;
  top: 0;
  height: 100vh;
  flex-shrink: 0;
  border-right: 1px solid var(--sidebar-border);
}

.sidebar-brand {
  position: relative;
  padding: 1.4rem 1.25rem 1.25rem;
  border-bottom: 1px solid var(--sidebar-border);
}
.sidebar-brand .brand {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  color: var(--sidebar-fg-active);
  font-weight: 600;
  font-size: 1.05rem;
  letter-spacing: -0.01em;
}
.sidebar-brand .brand:hover { text-decoration: none; color: var(--sidebar-fg-active); }
.sidebar-brand .brand-mark { color: var(--accent); font-size: 0.9rem; }
.sidebar-brand .brand-logo {
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 30%;
  object-fit: cover;
}
.sidebar-site {
  margin: 0.5rem 0 0;
  font-size: 0.78rem;
  color: var(--sidebar-fg-muted);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-weight: 500;
}
.sidebar-version {
  margin: 0.25rem 0 0;
  font-size: 0.72rem;
  font-family: ui-monospace, Menlo, monospace;
  color: var(--sidebar-fg-muted);
  letter-spacing: 0.02em;
}

.sidebar-nav {
  flex: 1;
  padding: 1rem 0.6rem;
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  overflow-y: auto;
}
.sidebar-nav .nav-item {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 0.75rem;
  padding: 0.55rem 0.85rem;
  color: var(--sidebar-fg);
  font-size: 0.9rem;
  font-weight: 500;
  border-radius: 8px;
  transition: background 0.15s ease, color 0.15s ease;
}
.sidebar-nav .nav-item:hover {
  background: var(--sidebar-bg-hover);
  color: var(--sidebar-fg-active);
  text-decoration: none;
}
.sidebar-nav .nav-item.active {
  background: var(--accent);
  color: white;
}
.sidebar-nav .nav-item .icon {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  stroke-width: 1.6;
}
.sidebar-nav .nav-item .nav-badge {
  margin-left: auto;
  min-width: 1.3rem;
  padding: 0.05rem 0.4rem;
  border-radius: 999px;
  background: var(--danger);
  color: #fff;
  font-size: 0.7rem;
  font-weight: 700;
  line-height: 1.45;
  text-align: center;
}

/* Pulse applied by the BadgePulse hook when the count changes. */
.nav-badge.badge-pulse {
  animation: badge-pulse 0.45s ease-out;
}
@keyframes badge-pulse {
  0% {
    transform: scale(1);
  }
  35% {
    transform: scale(1.4);
    box-shadow: 0 0 0 4px color-mix(in srgb, var(--danger) 30%, transparent);
  }
  100% {
    transform: scale(1);
    box-shadow: 0 0 0 0 transparent;
  }
}
@media (prefers-reduced-motion: reduce) {
  .nav-badge.badge-pulse {
    animation: none;
  }
}
.sidebar-divider {
  height: 1px;
  background: var(--sidebar-border);
  margin: 0.6rem 0.4rem;
}

.sidebar-user {
  padding: 0.85rem 0.9rem;
  border-top: 1px solid var(--sidebar-border);
  display: flex;
  align-items: center;
  gap: 0.6rem;
}
.user-avatar {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--accent);
  color: white;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.8rem;
  font-weight: 600;
  flex-shrink: 0;
}
.user-email {
  flex: 1;
  font-size: 0.78rem;
  color: var(--sidebar-fg-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.logout-link {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 6px;
  color: var(--sidebar-fg-muted);
  flex-shrink: 0;
}
.logout-link:hover {
  background: var(--sidebar-bg-hover);
  color: var(--sidebar-fg-active);
  text-decoration: none;
}
.logout-link .icon { width: 16px; height: 16px; }

.admin-content {
  flex: 1;
  padding: 2.25rem 2.75rem 4rem;
  width: 100%;
  min-width: 0;
  background: var(--bg);
}

/* Mobile chrome — the top bar (with hamburger), the drawer backdrop and the
   in-drawer close button exist in the markup at every width but only show
   below the breakpoint, where the sidebar turns into an off-canvas drawer. */
.admin-topbar { display: none; }
.sidebar-overlay { display: none; }
.sidebar-close { display: none; }

@media (max-width: 800px) {
  /* The sidebar leaves the flow and becomes an off-canvas drawer, so the
     content fills the full width with a sticky top bar above it. */
  .admin-shell { display: block; }

  .admin-topbar {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    position: sticky;
    top: 0;
    z-index: 30;
    padding: 0.6rem 1rem;
    background: var(--sidebar-bg);
    color: var(--sidebar-fg-active);
    border-bottom: 1px solid var(--sidebar-border);
  }
  .hamburger {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    margin: -0.25rem 0;
    border-radius: 9px;
    color: var(--sidebar-fg);
    flex-shrink: 0;
    cursor: pointer;
  }
  .hamburger:hover {
    background: var(--sidebar-bg-hover);
    color: var(--sidebar-fg-active);
  }
  .hamburger .icon {
    width: 24px;
    height: 24px;
  }
  .topbar-brand {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    color: var(--sidebar-fg-active);
    font-weight: 600;
    font-size: 1rem;
  }
  .topbar-brand:hover {
    text-decoration: none;
    color: var(--sidebar-fg-active);
  }
  .topbar-brand .brand-logo {
    width: 1.5rem;
    height: 1.5rem;
    border-radius: 30%;
    object-fit: cover;
  }
  .topbar-site {
    margin-left: auto;
    max-width: 38%;
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: var(--sidebar-fg-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  /* The drawer: a fixed full-height panel that slides in from the left and
     keeps its desktop column layout (vertical nav, visible labels). */
  .admin-sidebar {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    height: 100dvh;
    width: min(82vw, 300px);
    transform: translateX(-100%);
    transition: transform 0.28s cubic-bezier(0.4, 0, 0.2, 1);
    z-index: 50;
    will-change: transform;
  }
  .admin-shell.nav-open .admin-sidebar {
    transform: translateX(0);
    box-shadow: 0 0 50px rgba(0, 0, 0, 0.45);
  }

  .sidebar-close {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    position: absolute;
    top: 1rem;
    right: 1rem;
    width: 34px;
    height: 34px;
    border-radius: 8px;
    color: var(--sidebar-fg-muted);
    cursor: pointer;
  }
  .sidebar-close:hover {
    background: var(--sidebar-bg-hover);
    color: var(--sidebar-fg-active);
  }
  .sidebar-close .icon {
    width: 20px;
    height: 20px;
  }

  /* Backdrop — fades in only while the drawer is open. */
  .sidebar-overlay {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 40;
    background: rgba(0, 0, 0, 0.5);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.28s ease;
  }
  .admin-shell.nav-open .sidebar-overlay {
    opacity: 1;
    pointer-events: auto;
  }

  .admin-content { padding: 1.5rem; }
}

@media (prefers-reduced-motion: reduce) {
  .admin-sidebar,
  .sidebar-overlay { transition: none; }
}
/* Flash toasts — floating, auto-dismissing messages.
   Namespaced as `flash-toast*` to avoid colliding with daisyUI's `.toast`. */
.flash-toasts {
  position: fixed;
  bottom: 2rem;
  right: 2rem;
  z-index: 1000;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  align-items: stretch;
  width: min(92vw, 400px);
  pointer-events: none;
}
.flash-toast {
  pointer-events: auto;
  width: 100%;
  padding: 1.2rem;
  border-radius: 10px;
  font-size: 1.2rem;
  font-weight: 500;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
  cursor: pointer;
  /* Visible by default — entrance is a CSS animation so the toast shows
     even if the JS hook hasn't loaded; the hook only auto-dismisses it. */
  animation: flash-toast-in 0.22s ease both;
}
@keyframes flash-toast-in {
  from { opacity: 0; transform: translateY(12px); }
  to { opacity: 1; transform: translateY(0); }
}
/* Leave: a dedicated keyframe animation reliably overrides the entrance
   one (a plain transition was masked by the entrance animation's fill). */
.flash-toast.is-leaving {
  animation: flash-toast-out 0.2s ease forwards;
}
@keyframes flash-toast-out {
  from { opacity: 1; transform: translateY(0); }
  to { opacity: 0; transform: translateY(12px); }
}
.flash-toast-info { background: #ecfdf5; color: var(--good); border: 1px solid #a7f3d0; }
.flash-toast-error { background: #fef2f2; color: var(--danger); border: 1px solid #fecaca; }

.account-banner {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: wrap;
  padding: 0.7rem 0.95rem;
  margin-bottom: 1rem;
  border-radius: 6px;
  font-size: 0.9rem;
  background: #fffbeb;
  color: #92400e;
  border: 1px solid #fde68a;
}
.account-banner p { margin: 0; flex: 1; min-width: 14rem; }
.account-banner form { margin: 0; display: inline; }
.account-banner-btn {
  display: inline-block;
  border: 1px solid currentColor;
  color: inherit;
  text-decoration: none;
  padding: 0.3rem 0.7rem;
  border-radius: 5px;
  font-size: 0.85rem;
  cursor: pointer;
  white-space: nowrap;
}
.account-banner-btn:hover { background: rgba(146, 64, 14, 0.08); }
.account-banner-link { color: inherit; font-weight: 600; text-decoration: underline; }

.auth-card section { margin-top: 1.75rem; }
.auth-card section h2 { font-size: 1rem; margin-bottom: 0.5rem; }
.danger-zone { border-top: 1px solid #fecaca; padding-top: 1.25rem; }
.danger-zone h2 { color: var(--danger); }
.danger-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1.5rem;
}
.danger-row p { margin: 0.3rem 0 0; max-width: 52ch; font-size: 0.85rem; line-height: 1.55; }
.danger-row .btn-danger { flex: 0 0 auto; }
button.danger {
  background: var(--danger);
  color: #fff;
  border: none;
}
button.danger:hover { filter: brightness(0.92); }

/* Account page (mirrors the settings-section layout) */
.account-fields { gap: 1.4rem; }
.account-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1.5rem;
}
.account-row-label { font-weight: 600; font-size: 0.9rem; margin-bottom: 0.2rem; }
.account-row-value { font-size: 0.95rem; }
.account-hint { font-size: 0.85rem; line-height: 1.55; margin: 0.3rem 0 0; max-width: 48ch; }
.account-divider { border: 0; border-top: 1px solid var(--rule); margin: 0.4rem 0; }
.account-form {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.9rem;
}
.account-form label {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  font-size: 0.9rem;
  font-weight: 500;
  width: 100%;
  max-width: 360px;
}
.account-form input {
  padding: 0.55rem 0.75rem;
  border: 1px solid var(--rule);
  border-radius: 6px;
  font-size: 0.95rem;
  font-family: inherit;
  background: var(--card);
}
.account-form input:focus {
  outline: 2px solid var(--accent);
  outline-offset: -1px;
  border-color: var(--accent);
}
/* Buttons sit in a flex column — keep them their natural size, not stretched */
.account-fields .btn { align-self: flex-start; }

.sso-divider {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin: 1.25rem 0;
  color: #9ca3af;
  font-size: 0.8rem;
}
.sso-divider::before,
.sso-divider::after {
  content: "";
  flex: 1;
  border-top: 1px solid #e5e7eb;
}
.sso-buttons { display: flex; flex-direction: column; gap: 0.5rem; }
.sso-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.55rem;
  padding: 0.55rem 0.9rem;
  border: 1px solid #d1d5db;
  border-radius: 6px;
  text-decoration: none;
  color: inherit;
  font-size: 0.9rem;
}
.sso-btn svg { width: 18px; height: 18px; flex: none; }
.sso-btn:hover { background: #f9fafb; }

.page-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 2rem;
  gap: 1rem;
  padding: 1.5rem 1.75rem;
  background:
    linear-gradient(180deg, var(--accent), var(--violet)) left / 0.4rem 100% no-repeat,
    var(--card);
  border: 1px solid var(--rule);
  border-radius: 14px;
  box-shadow: var(--shadow-sm);
  position: relative;
  z-index: 15;
}
/* "Who's viewing" overlapping avatars, shown right after the page title.
   Each avatar reveals the member's email in a popover on hover/focus. */
.presence-cluster {
  display: inline-flex;
  align-items: center;
}
.presence-cluster .presence-avatar {
  position: relative;
  /* Nudge down: flex centers on the line box, which sits above the title's
     optical (cap-height) center. */
  top: 2px;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--accent);
  color: #fff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 0.72rem;
  font-weight: 600;
  border: 2px solid var(--card);
  margin-left: -8px;
  box-shadow: var(--shadow-sm);
  cursor: default;
  transition: transform 0.12s ease;
}
.presence-cluster .presence-avatar:first-child {
  margin-left: 0;
}
.presence-cluster .presence-avatar:hover,
.presence-cluster .presence-avatar:focus-visible {
  transform: translateY(-2px);
  z-index: 3;
  outline: none;
}
.presence-cluster .presence-popover {
  position: absolute;
  top: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%) translateY(4px);
  background: var(--ink, #18181b);
  color: #fff;
  font-size: 0.75rem;
  font-weight: 500;
  line-height: 1;
  white-space: nowrap;
  padding: 0.4rem 0.6rem;
  border-radius: 6px;
  box-shadow: var(--shadow-sm);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.12s ease, transform 0.12s ease;
  z-index: 4;
}
.presence-cluster .presence-popover::before {
  content: "";
  position: absolute;
  bottom: 100%;
  left: 50%;
  transform: translateX(-50%);
  border: 5px solid transparent;
  border-bottom-color: var(--ink, #18181b);
}
.presence-cluster .presence-avatar:hover .presence-popover,
.presence-cluster .presence-avatar:focus-visible .presence-popover {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

.page-head h1 {
  margin: 0;
  padding-left: 0.4rem;
  font-size: 1.55rem;
  line-height: 1.1;
  letter-spacing: -0.025em;
  font-weight: 600;
  color: var(--fg);
}
.page-head-title {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.55rem;
  min-width: 0;
}
.page-head .actions { display: flex; gap: 0.5rem; }

@media (max-width: 640px) {
  .page-head {
    gap: 0.75rem;
    padding: 1.15rem 1.25rem;
    margin-bottom: 1.5rem;
  }
  /* Keep the title left and actions on the right (as on desktop); let the
     title shrink/wrap rather than push the buttons off-screen. */
  .page-head h1 { font-size: 1.3rem; min-width: 0; }
  .page-head .actions { flex-shrink: 0; }
  /* The "Theme template" link is a nice-to-have; it crowds out the title. */
  .page-head .actions .github-btn { display: none; }
}

/* Stats / cards */
.action-card {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  background: #fffbeb;
  border: 1px solid #fde68a;
  border-radius: 12px;
  padding: 1rem 1.25rem;
  margin-bottom: 1.5rem;
}
.action-card-body { flex: 1; min-width: 0; }
.action-card-title {
  margin: 0 0 0.05rem;
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.2;
  color: #92400e;
}
.action-card-message {
  margin: 0;
  font-size: 0.9rem;
  color: #78350f;
}
.action-card-dismiss {
  flex-shrink: 0;
  background: transparent;
  border: 0;
  color: #92400e;
  opacity: 0.55;
  font-size: 1.3rem;
  line-height: 1;
  cursor: pointer;
  padding: 0 0.1rem;
  border-radius: 6px;
}
.action-card-dismiss:hover {
  opacity: 1;
}
.action-list {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}
.action-list .action-card { margin-bottom: 0; }

/* Dashboard metrics. Named `metric*` rather than `stat*` on purpose:
   daisyUI ships a `.stats`/`.stat`/`.stat-value` component whose
   `grid-auto-flow: column` would otherwise win the cascade and force the
   cards into a single overflowing row instead of this responsive grid. */
.metrics {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 1rem;
  margin-bottom: 2.5rem;
}
.metric {
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: 14px;
  padding: 1.25rem 1.4rem;
  box-shadow: var(--shadow-sm);
  display: flex;
  align-items: center;
  gap: 1rem;
  position: relative;
  overflow: hidden;
}
.metric .metric-icon {
  width: 44px;
  height: 44px;
  border-radius: 12px;
  background: var(--accent-soft);
  color: var(--accent);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.metric .metric-icon svg { width: 22px; height: 22px; }
.metric.metric-good .metric-icon { background: var(--good-soft); color: var(--good); }
.metric.metric-amber .metric-icon { background: var(--amber-soft); color: var(--amber); }
.metric.metric-violet .metric-icon { background: var(--violet-soft); color: var(--violet); }
.metric .metric-body { display: flex; flex-direction: column; min-width: 0; }
.metric .num {
  font-size: 1.9rem;
  font-weight: 700;
  letter-spacing: -0.03em;
  color: var(--fg);
  line-height: 1.1;
}
.metric .metric-label {
  font-size: 0.78rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
  margin-top: 0.2rem;
}

/* On phones, stack the metric cards into a single column so each reads
   clearly on its own line instead of squeezing two or three across. */
@media (max-width: 640px) {
  .metrics { grid-template-columns: 1fr; gap: 0.75rem; margin-bottom: 1.75rem; }
}

.card-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 1rem;
}
.card-list li {
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: 14px;
  box-shadow: var(--shadow-sm);
  transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
  position: relative;
  overflow: hidden;
}
.card-list li::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 3px;
  background: linear-gradient(90deg, var(--accent), var(--violet));
  opacity: 0;
  transition: opacity 0.18s ease;
}
.card-list li:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow-lg);
  border-color: var(--rule-strong);
}
.card-list li:hover::before { opacity: 1; }
.card-list li a {
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
  padding: 1.4rem 1.5rem;
  color: inherit;
}
.card-list li a:hover { text-decoration: none; }
.card-list li strong { font-size: 1.05rem; font-weight: 600; letter-spacing: -0.015em; color: var(--fg); }
.card-list li .muted {
  font-size: 0.8rem;
  font-family: ui-monospace, Menlo, monospace;
  color: var(--muted);
}
.card-list li .pill { align-self: flex-start; margin-top: 0.25rem; }

/* Tables */
.table {
  width: 100%;
  border-collapse: collapse;
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: 14px;
  overflow: hidden;
  box-shadow: var(--shadow-sm);
}
.table th, .table td {
  padding: 1rem 1.5rem;
  text-align: left;
  border-bottom: 1px solid var(--rule);
  font-size: 0.92rem;
}
.table th {
  background: var(--bg-soft);
  font-weight: 600;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--muted);
}
.table tr:last-child td { border-bottom: 0; }
.table tbody tr { transition: background 0.12s ease; }
.table tbody tr:hover td { background: var(--accent-soft); }
.table .muted {
  font-size: 0.78rem;
  font-family: ui-monospace, Menlo, monospace;
}

/* Right-aligned cluster of row action buttons (e.g. Edit / Delete). */
.row-actions { display: inline-flex; align-items: center; gap: 0.4rem; }

/* Whole-row link: clicking anywhere on the row navigates to its edit page
   (wired with phx-click on the <tr>). The title still reads as a link, and
   the action buttons keep their own behaviour via closest-match handling. */
.row-link { cursor: pointer; }
.row-title { color: var(--accent); font-weight: 500; }
.row-link:hover .row-title { text-decoration: underline; }

/* Relative timestamp ("a day ago"); the exact date is in a custom tooltip
   (from `data-tooltip`), hinted by the dotted underline + help cursor. */
.rel-time {
  position: relative;
  color: var(--muted);
  cursor: help;
  white-space: nowrap;
  text-decoration: underline dotted;
  text-decoration-color: var(--rule-strong);
  text-underline-offset: 2px;
}

/* Black tooltip bubble + arrow above the label. Custom (not the native
   `title`) so it appears near-instantly instead of after the ~1s UA delay.
   Positioned above so it stays inside the table's overflow box (it overlays
   the row above / the header rather than escaping the table). */
.rel-time::after {
  content: attr(data-tooltip);
  position: absolute;
  bottom: calc(100% + 7px);
  left: 50%;
  transform: translateX(-50%);
  background: #000;
  color: #fff;
  font-size: 0.75rem;
  line-height: 1;
  padding: 0.4rem 0.55rem;
  border-radius: 6px;
  white-space: nowrap;
  z-index: 10;
}

.rel-time::before {
  content: "";
  position: absolute;
  bottom: calc(100% + 2px);
  left: 50%;
  transform: translateX(-50%);
  border: 5px solid transparent;
  border-top-color: #000;
  border-bottom: none;
  z-index: 10;
}

.rel-time::before,
.rel-time::after {
  opacity: 0;
  pointer-events: none;
  transition: opacity 80ms ease-out 100ms;
}

.rel-time:hover::before,
.rel-time:hover::after {
  opacity: 1;
}

/* On phones, a multi-column table is unreadable. Tables opting in with
   `.table-cards` collapse into a stack of cards: each row becomes a card,
   each cell a labelled line (label from `data-label`). The first cell is the
   card title and the `.actions-cell` is pinned to the bottom-right. */
@media (max-width: 640px) {
  .table-cards {
    display: block;
    border: 0;
    border-radius: 0;
    box-shadow: none;
    background: transparent;
    overflow: visible;
  }
  .table-cards thead { display: none; }
  .table-cards tbody { display: block; }
  .table-cards tr {
    display: block;
    background: var(--card);
    border: 1px solid var(--rule);
    border-radius: 12px;
    box-shadow: var(--shadow-sm);
    padding: 0.85rem 1rem;
    margin-bottom: 0.75rem;
  }
  .table-cards tbody tr:hover td { background: transparent; }
  .table-cards td {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.32rem 0;
    border: 0;
    font-size: 0.9rem;
  }
  .table-cards td[data-label]::before {
    content: attr(data-label);
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--muted);
  }
  /* Title cell — full-width heading with its slug beneath, no label. */
  .table-cards td:first-child {
    display: block;
    padding: 0 0 0.55rem;
    margin-bottom: 0.5rem;
    border-bottom: 1px solid var(--rule);
    font-size: 1rem;
    font-weight: 600;
  }
  .table-cards td:first-child .muted { font-size: 0.75rem; margin-top: 0.15rem; }
  /* Actions — right-aligned, separated from the meta rows. */
  .table-cards td.actions-cell {
    justify-content: flex-end;
    padding-top: 0.6rem;
    margin-top: 0.4rem;
    border-top: 1px solid var(--rule);
  }
}

/* Section heading inside a page */
.section-heading {
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 2.5rem 0 1rem;
}

/* Recent posts list (dashboard) */
.recent-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: 12px;
  overflow: hidden;
}
.recent-list li { border-bottom: 1px solid var(--rule); }
.recent-list li:last-child { border-bottom: 0; }
.recent-list li a {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0.9rem 1.4rem;
  color: inherit;
}
.recent-list li a:hover { background: #fafafa; text-decoration: none; }

.pill {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.2rem 0.65rem;
  border-radius: 999px;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.02em;
}
.pill::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
}
.pill-live { background: var(--good-soft); color: #166534; }
.pill-draft { background: var(--amber-soft); color: #92400e; }
.pill-ok { background: var(--good-soft); color: #166534; }
.pill-warn { background: var(--amber-soft); color: #92400e; }
.pill-danger { background: #fef2f2; color: #991b1b; }

/* Admin overview (users / sites / themes tables) */
.admin-tabs {
  display: flex;
  gap: 0.25rem;
  margin-bottom: 1.5rem;
  border-bottom: 1px solid var(--rule);
}
.admin-tab {
  appearance: none;
  background: transparent;
  border: 0;
  border-bottom: 2px solid transparent;
  padding: 0.6rem 1rem;
  margin-bottom: -1px;
  font-size: 0.92rem;
  font-weight: 500;
  color: var(--muted);
  cursor: pointer;
}
.admin-tab:hover { color: var(--fg); }
.admin-tab.is-active { color: var(--accent); border-bottom-color: var(--accent); }
/* Admin tables reuse the platform `.table` style; this just allows the
   wider tables to scroll on narrow viewports and lays out the row's
   action buttons in a right-aligned cluster. */
.admin-table-wrap { overflow-x: auto; }
.admin-row-actions {
  display: flex;
  gap: 0.4rem;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
}
/* Toolbar above each admin table: filter buttons on the left, search on
   the right, with a cap hint underneath when the list is truncated. */
.admin-toolbar {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-bottom: 1rem;
}
.admin-toolbar-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
}
.admin-toolbar-hint { margin: 0; font-size: 0.8rem; color: var(--muted); }
.admin-filters { display: flex; gap: 0.4rem; flex-wrap: wrap; }
.admin-search { margin: 0; flex: 0 1 18rem; }
.admin-search input[type="search"] {
  width: 100%;
  box-sizing: border-box;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--rule);
  border-radius: 6px;
  font-size: 0.9rem;
  font-family: inherit;
  background: var(--card);
  color: var(--fg);
}
.admin-search input[type="search"]::placeholder { color: var(--muted); }
.admin-search input[type="search"]:focus {
  outline: none;
  border-color: var(--accent);
}

/* Search sits beside any extra filter control the page adds. */
.admin-toolbar-controls {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex: 0 1 auto;
}
/* On a phone the search box reads as an afterthought squeezed beside the
   filters; give it the full row. */
@media (max-width: 640px) {
  .admin-toolbar-controls { flex: 1 1 100%; }
  .admin-search { flex: 1 1 auto; }
}
.visibility-filter { margin: 0; }
.visibility-filter select {
  padding: 0.5rem 2.2rem 0.5rem 0.75rem;
  border: 1px solid var(--rule);
  border-radius: 6px;
  font-size: 0.9rem;
  font-family: inherit;
  background: var(--card);
  color: var(--fg);
  appearance: none;
  -webkit-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2371717a' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.6rem center;
}
.visibility-filter select:focus { outline: none; border-color: var(--accent); }

/* Format tags (Markdown / HTML / Blog) */
.format-tag {
  display: inline-block;
  padding: 0.18rem 0.55rem;
  border-radius: 6px;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  font-family: ui-monospace, Menlo, monospace;
}
.format-tag-markdown { background: var(--accent-soft); color: var(--accent-strong); }
.format-tag-html { background: var(--violet-soft); color: var(--violet); }
.format-tag-theme { background: var(--good-soft); color: #166534; }

/* Tags — management list in settings */
.tag-manage-list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
}
.tag-chip-add {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.2rem 0.7rem;
  border-radius: 999px;
  font-size: 0.75rem;
  font-weight: 600;
  background: none;
  color: var(--accent);
  border: 1px dashed var(--rule-strong, var(--rule));
  cursor: pointer;
  white-space: nowrap;
  text-decoration: none;
}
.tag-chip-add:hover {
  border-color: var(--accent);
  background: var(--accent-soft);
}
.tag-chip {
  display: inline-flex;
  align-items: center;
  border-radius: 999px;
  font-size: 0.75rem;
  font-weight: 600;
  background: var(--rule);
  color: var(--fg);
  overflow: hidden;
}
.tag-chip-label {
  padding: 0.2rem 0.5rem 0.2rem 0.7rem;
  background: none;
  border: 0;
  color: inherit;
  font: inherit;
  cursor: pointer;
}
.tag-chip-remove {
  padding: 0.2rem 0.55rem;
  background: none;
  border: 0;
  color: var(--muted);
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
}
.tag-chip-remove:hover { color: var(--danger, #991b1b); }

.tag-cell {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
}

/* Tag picker (toggle pills) on the post form */
/* Tag picker field on the post form — mirror the .form label column layout
   so the "Tags" title sits above the chips with the same spacing. */
.field {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
}
.field-label {
  font-size: 0.9rem;
  font-weight: 500;
}
.tag-picker {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-bottom: 0.4rem;
}
.tag-toggle {
  padding: 0.25rem 0.7rem;
  border-radius: 999px;
  font-size: 0.8rem;
  font-weight: 600;
  background: var(--bg);
  color: var(--fg);
  border: 1px solid var(--rule);
  cursor: pointer;
}
.tag-toggle-on {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}

/* Tag filter pills on the posts list */
.tag-filter {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.1rem 0.5rem;
  border-radius: 999px;
  font-size: 0.7rem;
  font-weight: 600;
  background: var(--rule);
  color: var(--fg);
  border: 0;
  cursor: pointer;
}

/* Forms */
.form {
  display: flex;
  flex-direction: column;
  gap: 1.1rem;
  max-width: 720px;
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: 12px;
  padding: 1.75rem 2rem;
}
.form.post-form {
  max-width: none;
  background: transparent;
  border: 0;
  padding: 0;
}
.form label { display: flex; flex-direction: column; gap: 0.3rem; font-size: 0.9rem; font-weight: 500; }
.form input[type="text"], .form input[type="email"], .form input[type="password"],
.form input[type="number"], .form input[type="url"], .form input[type="color"],
.form textarea, .form select {
  width: 100%; box-sizing: border-box;
  padding: 0.55rem 0.75rem; border: 1px solid var(--rule); border-radius: 6px; font-size: 0.95rem; font-family: inherit; background: var(--card);
}
.form textarea { font-family: ui-monospace, Menlo, monospace; resize: vertical; }
/* Replace the native select chevron (cramped, browser-dependent) with a
   custom one and reserve right padding so text never runs under it. */
.form select {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  padding-right: 2.4rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2371717a' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.75rem center;
}
/* Native color input: render as a full-width swatch matching text-input
   height, with the inner swatch filling the control (no default chrome). */
.form input[type="color"] { height: 42px; padding: 0.25rem; cursor: pointer; }
.form input[type="color"]::-webkit-color-swatch-wrapper { padding: 0; }
.form input[type="color"]::-webkit-color-swatch { border: none; border-radius: 4px; }
.form input[type="color"]::-moz-color-swatch { border: none; border-radius: 4px; }
.form input:focus, .form textarea:focus, .form select:focus { outline: 2px solid var(--accent); outline-offset: -1px; border-color: var(--accent); }
.form small { color: var(--muted); font-weight: 400; }
.form .checkbox { flex-direction: row; align-items: center; gap: 0.5rem; }
/* Boolean metadata field: checkbox beside a stacked label + hint.
   The wrapper is a <div> (not a <label>) so the generic
   `.form label { flex-direction: column }` rule can't stretch the
   checkbox full-width. */
.settings-checkbox { display: flex; align-items: center; gap: 1rem; justify-content: space-between; }
.settings-checkbox input[type="checkbox"] {
  width: 1.2rem;
  height: 1.2rem;
  flex: none;
  margin: 0;
  accent-color: var(--accent);
  cursor: pointer;
}
.settings-checkbox .settings-checkbox-text { flex: 1; min-width: 0; gap: 0.15rem; cursor: pointer; user-select: none; }
.form-actions { display: flex; gap: 1rem; align-items: center; margin-top: 0.5rem; }
.errors { background: #fef2f2; color: var(--danger); list-style: none; padding: 0.6rem 0.9rem; border-radius: 6px; font-size: 0.85rem; margin: 0; }

/* Wizard / stepper */
.wizard {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 0;
}
.wizard .form { max-width: none; }
.wizard .form.post-form { max-width: none; }

.stepper {
  list-style: none;
  padding: 0;
  margin: 0 0 2.5rem;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: 14px;
  padding: 1rem 1.5rem;
  box-shadow: var(--shadow-sm);
}
.stepper .step {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex: 1;
  font-size: 0.88rem;
  position: relative;
  cursor: pointer;
}
/* Hover affordance: only nudge the border + label. Don't recolor the
   number text — the current/done steps have a filled background, so
   blue-on-blue would make the digit vanish. */
.stepper .step:hover .step-num {
  border-color: var(--accent);
}
.stepper .step:hover .step-label {
  color: var(--fg);
}
.stepper .step:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 4px;
}
.stepper .step::after {
  content: "";
  flex: 1;
  height: 2px;
  background: var(--rule);
  margin-left: 0.5rem;
  border-radius: 2px;
}
.stepper .step:last-child { flex: 0 0 auto; }
.stepper .step:last-child::after { display: none; }
.step-num {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-weight: 600;
  font-size: 0.85rem;
  background: var(--bg);
  color: var(--muted);
  border: 1.5px solid var(--rule);
  flex-shrink: 0;
}
.step-label { font-weight: 500; color: var(--muted); }
.step-current .step-num { background: var(--accent); color: white; border-color: var(--accent); }
.step-current .step-label { color: var(--fg); }
.step-done .step-num { background: var(--accent-soft); color: var(--accent); border-color: var(--accent); }
.step-done .step-label { color: var(--fg-soft); }
.step-done::after { background: var(--accent); }
/* Forward steps are unreachable until the format selection is complete
   (e.g. a theme page still needs a template). */
.stepper .step-disabled { cursor: not-allowed; opacity: 0.45; }
.stepper .step-disabled:hover .step-num { border-color: var(--rule); }
.stepper .step-disabled:hover .step-label { color: var(--muted); }

/* On narrow screens the row of labelled steps overflows; drop the labels and
   keep numbers + connectors so progress is still readable at a glance. */
@media (max-width: 640px) {
  .stepper { padding: 0.85rem 1rem; gap: 0.4rem; margin-bottom: 1.5rem; }
  .stepper .step .step-label { display: none; }
  .stepper .step::after { margin-left: 0.4rem; }
}

.wizard-heading {
  font-size: 1.4rem;
  letter-spacing: -0.02em;
  margin: 0 0 1.5rem;
  font-weight: 600;
}

.format-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 1.25rem;
}
.format-card {
  background: var(--card);
  border: 2px solid var(--rule);
  border-radius: 16px;
  padding: 1.75rem;
  text-align: left;
  cursor: pointer;
  transition: transform 0.18s ease, border-color 0.18s ease, box-shadow 0.18s ease;
  font: inherit;
  color: inherit;
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  min-height: 248px;
}
.format-card:hover:not([disabled]):not(.format-card-selected) {
  transform: translateY(-3px);
  border-color: var(--accent);
  box-shadow: var(--shadow-lg);
}
.format-card-selected {
  border-color: var(--accent);
  background: var(--accent-soft);
  cursor: default;
  position: relative;
}
.format-card-selected::after {
  content: "Selected";
  position: absolute;
  top: 0.85rem;
  right: 0.85rem;
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--accent);
  background: white;
  border: 1px solid var(--accent);
  padding: 0.15rem 0.55rem;
  border-radius: 999px;
}
.format-card[disabled], .format-card-disabled {
  opacity: 0.4;
  cursor: not-allowed;
  filter: grayscale(40%);
}
.format-card[disabled]:hover, .format-card-disabled:hover {
  transform: none;
  border-color: var(--rule);
  box-shadow: none;
}
.format-card h3 { margin: 0; font-size: 1.15rem; letter-spacing: -0.015em; }
.format-card p { margin: 0; color: var(--fg-soft); line-height: 1.55; font-size: 0.93rem; }
.format-icon {
  width: 48px;
  height: 48px;
  border-radius: 12px;
  background: var(--accent-soft);
  color: var(--accent);
  display: flex;
  align-items: center;
  justify-content: center;
}
.format-icon svg { width: 26px; height: 26px; }
.format-pill {
  align-self: flex-start;
  margin-top: auto;
  background: var(--accent-soft);
  color: var(--accent);
  padding: 0.2rem 0.65rem;
  border-radius: 999px;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.format-pill-muted { background: var(--bg); color: var(--muted); }
/* On a selected card the body turns accent-soft, so the accent-soft pill would
   read as blue-on-blue — give it a solid white chip to keep it legible. */
.format-card-selected .format-pill {
  background: var(--card);
  border: 1px solid var(--accent);
}

/* The Theme page card holds a template dropdown instead of being a single
   click target, so pin it to the bottom and style it like a form control. */
.format-card-select { margin: 0; margin-top: auto; }
.format-card-select select {
  width: 100%;
  padding: 0.55rem 0.7rem;
  border: 1px solid var(--rule);
  border-radius: 10px;
  background: var(--card);
  font: inherit;
  color: inherit;
  cursor: pointer;
}
.format-card-select select:focus { outline: none; border-color: var(--accent); }
.format-card-select select:disabled { cursor: not-allowed; opacity: 0.7; }

.wizard-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-top: 1.5rem;
  padding: 0;
}
.wizard-footer .muted { font-size: 0.88rem; flex: 1; text-align: center; }
.wizard-actions { display: flex; gap: 0.6rem; align-items: center; }

/* Publish-toggle button (page header) */
.btn-publish-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  border-radius: 999px;
  padding: 0.5rem 1.1rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  box-shadow: none;
}
.btn-publish-toggle::before {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: currentColor;
}
.btn-publish-toggle.btn-draft {
  background: var(--accent);
  color: white;
  border-color: var(--accent);
}
.btn-publish-toggle.btn-draft:hover {
  background: var(--accent-hover);
  border-color: var(--accent-hover);
  color: white;
}
.btn-publish-toggle.btn-published {
  background: var(--good-soft);
  color: #166534;
  border: 1px solid #86efac;
}
.btn-publish-toggle.btn-published:hover {
  background: #dcfce7;
  color: #14532d;
}

.format-note {
  margin: -0.25rem 0 0.5rem;
  font-size: 0.82rem;
  text-align: center;
  color: var(--muted);
}

/* Short editor variant (used by blog page description) */
.editor.editor-short .markdown-editor { min-height: 180px; flex: 1; }

.form-row { display: flex; gap: 1rem; }
.form-row > label { flex: 1; }

/* Settings page — card-style sections grouping related fields */
.settings-form {
  background: transparent;
  border: 0;
  padding: 0;
  max-width: none;
  gap: 1.5rem;
}
.settings-section {
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: 14px;
  box-shadow: var(--shadow-sm);
  display: grid;
  grid-template-columns: 280px 1fr;
  gap: 2rem;
  padding: 1.75rem 2rem;
}
.settings-section-head h2 {
  margin: 0 0 0.4rem;
  font-size: 1.05rem;
  letter-spacing: -0.015em;
  font-weight: 600;
}
.settings-section-head p {
  margin: 0;
  color: var(--muted);
  font-size: 0.88rem;
  line-height: 1.55;
}
.settings-fields {
  display: flex;
  flex-direction: column;
  gap: 1.1rem;
  min-width: 0;
}
.settings-fields .muted code {
  font-family: ui-monospace, Menlo, monospace;
  background: var(--bg);
  padding: 0.15rem 0.45rem;
  border-radius: 4px;
  margin: 0 0.15rem;
}

/* Token category accordions (themes that group tokens by category). */
.token-groups {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  min-width: 0;
}
.token-group {
  border: 1px solid var(--rule);
  border-radius: 8px;
  background: var(--card);
}
.token-group-summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.8rem 1rem;
  font-weight: 600;
  font-size: 0.95rem;
  cursor: pointer;
  list-style: none;
  user-select: none;
}
.token-group-summary::-webkit-details-marker { display: none; }
.token-group-summary::after {
  content: "▸";
  color: var(--muted);
  font-size: 0.8rem;
  transition: transform 0.15s ease;
}
.token-group[open] > .token-group-summary { border-bottom: 1px solid var(--rule); }
.token-group[open] > .token-group-summary::after { transform: rotate(90deg); }
.token-group > .settings-fields { padding: 1rem; }
/* Quick fade/slide when a section opens, just to smooth the reveal. */
.token-group[open] > .settings-fields { animation: token-group-reveal 0.15s ease-out; }
@keyframes token-group-reveal {
  from { opacity: 0; transform: translateY(-4px); }
  to { opacity: 1; transform: translateY(0); }
}

/* Theme picker — card grid for the public-site theme selection. */
.theme-picker {
  border: 0;
  padding: 0;
  margin: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: 0.75rem;
}
.theme-picker legend {
  grid-column: 1 / -1;
  padding: 0;
  margin-bottom: 0.25rem;
  font-size: 0.95rem;
  font-weight: 500;
  color: var(--fg);
}
.theme-picker-hint {
  grid-column: 1 / -1;
  color: var(--muted);
  font-size: 0.85rem;
}
.theme-picker-card {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  min-height: 84px;
  padding: 1rem 0.75rem;
  background: var(--bg);
  border: 2px solid var(--rule);
  border-radius: 8px;
  cursor: pointer;
  text-align: center;
  text-decoration: none;
  color: var(--fg);
  transition: border-color 120ms ease, background 120ms ease, color 120ms ease;
}
.theme-picker-card input[type="radio"] {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}
.theme-picker-card:hover { border-color: var(--rule-strong); background: var(--bg-soft); }
.theme-picker-card-selected {
  border-color: var(--accent);
  background: var(--bg-soft);
}
.theme-picker-card-name { font-weight: 600; font-size: 0.95rem; }
.theme-picker-card-tag {
  display: inline-block;
  margin-left: 0.4rem;
  padding: 0.05rem 0.4rem;
  font-size: 0.7rem;
  font-weight: 500;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--muted);
  background: var(--bg-soft);
  border: 1px solid var(--rule);
  border-radius: 999px;
  vertical-align: middle;
}
.theme-picker-card-add {
  flex-direction: column;
  gap: 0.25rem;
  background: transparent;
  border-style: dashed;
  color: var(--muted);
}
.theme-picker-card-add:hover { color: var(--accent); border-color: var(--accent); text-decoration: none; }
.theme-picker-card-icon { font-size: 1.25rem; line-height: 1; font-weight: 400; }

@media (max-width: 800px) {
  .settings-section {
    grid-template-columns: 1fr;
    gap: 1.25rem;
    padding: 1.5rem;
  }
  .form-row {
    flex-direction: column;
    gap: 1rem;
  }
}

/* Post / page editor */
.editor {
  display: flex;
  flex-direction: column;
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: 12px;
  padding: 1.25rem;
}
.editor-pane { display: flex; flex-direction: column; gap: 0.5rem; min-width: 0; }
.editor-label { font-size: 0.85rem; font-weight: 600; letter-spacing: 0.02em; color: var(--muted); text-transform: uppercase; }
.markdown-editor {
  flex: 1;
  min-height: 560px;
  font-family: ui-monospace, Menlo, monospace;
  resize: vertical;
}
/* Syntax-highlighted editor (CodeMirror 6) — wraps the textarea, which is
   hidden via inline style by the CodeEditor hook. */
.code-editor {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 560px;
  background: var(--bg);
  border: 1px solid var(--rule);
  border-radius: 8px;
  overflow: hidden;
}
.code-editor .cm-editor {
  flex: 1;
  min-height: 560px;
  font-size: 0.9rem;
}
.code-editor .cm-editor.cm-focused { outline: none; }
.code-editor .cm-scroller {
  font-family: ui-monospace, Menlo, monospace;
  line-height: 1.5;
}
.code-editor .cm-gutters {
  background: var(--card);
  border-right: 1px solid var(--rule);
  color: var(--muted);
}
.code-editor-short, .code-editor-short .cm-editor { min-height: 180px; }
.editor.editor-short .code-editor, .editor.editor-short .code-editor .cm-editor {
  min-height: 180px;
}

/* Content editor layout — body editor (left) + control rail (right) */
.content-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  gap: 1.5rem;
  align-items: start;
}
.content-main { min-width: 0; }
.content-sidebar {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  position: sticky;
  top: 1.5rem;
}
.sidebar-card {
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: 12px;
  padding: 1rem 1.1rem;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}
.sidebar-card-title {
  margin: 0;
  font-size: 0.74rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted);
}
.btn-block { width: 100%; justify-content: center; }
.sidebar-card-danger { border-color: var(--danger-soft); }

/* Read-only publish-state badge in the editor header */
.publish-status {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  border-radius: 999px;
  padding: 0.5rem 1.1rem;
  font-weight: 600;
  font-size: 0.9rem;
  letter-spacing: 0.01em;
}
.publish-status::before {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: currentColor;
}
.publish-status.is-published {
  background: var(--good-soft);
  color: #166534;
  border: 1px solid #86efac;
}
.publish-status.is-draft {
  background: var(--bg-soft);
  color: var(--muted);
  border: 1px solid var(--rule);
}

@media (max-width: 900px) {
  .content-layout { grid-template-columns: 1fr; }
  .content-sidebar { position: static; }
}
/* Prose — rendered post/page body. Tailwind preflight resets default
   heading/paragraph styles to inherit, so we restore the typical
   "rendered Markdown" look explicitly here. */
.prose { font-size: 0.95rem; line-height: 1.6; color: var(--fg); }
.prose > *:first-child { margin-top: 0; }
.prose > *:last-child { margin-bottom: 0; }
.prose h1, .prose h2, .prose h3, .prose h4, .prose h5, .prose h6 {
  font-weight: 600;
  letter-spacing: -0.015em;
  line-height: 1.25;
  margin: 1.6em 0 0.6em;
}
.prose h1 { font-size: 1.7em; }
.prose h2 { font-size: 1.4em; }
.prose h3 { font-size: 1.2em; }
.prose h4 { font-size: 1.05em; }
.prose h5, .prose h6 { font-size: 1em; color: var(--muted); }
.prose p { margin: 0 0 1em; }
.prose ul, .prose ol { margin: 0 0 1em; padding-left: 1.4em; }
.prose ul { list-style: disc; }
.prose ol { list-style: decimal; }
.prose li { margin-bottom: 0.3em; }
.prose li > p { margin-bottom: 0.3em; }
.prose a { color: var(--accent); text-decoration: underline; }
.prose a:hover { color: var(--accent-hover); }
.prose strong { font-weight: 600; }
.prose em { font-style: italic; }
.prose hr { border: 0; border-top: 1px solid var(--rule); margin: 1.5em 0; }
.prose code {
  font-family: ui-monospace, Menlo, monospace;
  font-size: 0.88em;
  background: #f1f5f9;
  padding: 0.1em 0.4em;
  border-radius: 4px;
}
.prose pre {
  background: #f1f5f9;
  color: var(--fg);
  border: 1px solid var(--rule);
  padding: 0.85rem 1rem;
  border-radius: 8px;
  overflow-x: auto;
  margin: 0 0 1em;
  font-size: 0.86em;
  line-height: 1.55;
}
.prose pre code { background: transparent; padding: 0; color: inherit; font-size: 1em; }
.prose img { max-width: 100%; height: auto; border-radius: 6px; margin: 0.5em 0; }
.prose blockquote {
  border-left: 3px solid var(--accent);
  background: var(--accent-soft);
  padding: 0.4em 0.9em;
  margin: 0 0 1em;
  border-radius: 0 6px 6px 0;
  color: var(--fg-soft);
}
.prose blockquote p:last-child { margin-bottom: 0; }
.prose table { border-collapse: collapse; margin: 0 0 1em; }
.prose th, .prose td { border: 1px solid var(--rule); padding: 0.4em 0.7em; }
.prose th { background: var(--bg-soft); font-weight: 600; text-align: left; }

@media (max-width: 800px) {
  .admin-header { flex-wrap: wrap; gap: 1rem; }
}

/* Uploads */
.dropzone {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  border: 2px dashed var(--rule-strong);
  border-radius: 12px;
  padding: 2.5rem 2rem;
  text-align: center;
  background: var(--bg-soft);
  cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.dropzone:hover {
  border-color: var(--accent);
  background: var(--accent-soft);
}
.dropzone:hover .dropzone-icon { color: var(--accent); }
.dropzone p { margin: 0; }
.dropzone-icon {
  width: 40px;
  height: 40px;
  color: var(--muted);
  margin-bottom: 0.5rem;
  transition: color 0.15s ease;
}
.dropzone-headline {
  font-weight: 600;
  color: var(--fg);
  font-size: 0.95rem;
}

/* Visually hide the native file input — the whole label is the drop target */
.dropzone input[type="file"] {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.upload-entries { list-style: none; padding: 0; margin: 0; }
.upload-entries li {
  padding: 0.6rem 0;
  border-bottom: 1px solid var(--rule);
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: wrap;
}
.upload-entries li:last-child { border-bottom: 0; }
.upload-entries .rename-input {
  flex: 1;
  min-width: 0;
  padding: 0.4rem 0.65rem;
  border: 1px solid var(--rule);
  border-radius: 6px;
  font-family: inherit;
  font-size: 0.88rem;
  background: var(--card);
  color: var(--fg);
}
.upload-entries .rename-input:focus {
  outline: 2px solid var(--accent);
  outline-offset: -1px;
  border-color: var(--accent);
}
.upload-entries .entry-progress {
  font-size: 0.8rem;
  min-width: 3rem;
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.upload-entries .entry-error {
  flex-basis: 100%;
  margin: 0.2rem 0 0;
  font-size: 0.82rem;
}

/* Modal */
/* Dialog (named to avoid collisions with daisyUI's .modal-* classes) */
.dialog-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(15, 23, 42, 0.55);
  backdrop-filter: blur(4px);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
  padding: 1.5rem;
  animation: dialog-fade 0.15s ease-out;
}
.dialog-close-overlay {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  background: transparent;
  border: 0;
  cursor: pointer;
  padding: 0;
  margin: 0;
}
.dialog-close-overlay:focus { outline: none; }
@keyframes dialog-fade {
  from { opacity: 0; }
  to { opacity: 1; }
}
.dialog {
  position: relative;
  z-index: 1;
  background: var(--card);
  border-radius: 16px;
  box-shadow: var(--shadow-lg);
  width: 100%;
  max-width: 520px;
  max-height: calc(100vh - 3rem);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  animation: dialog-pop 0.18s ease-out;
}
@keyframes dialog-pop {
  from { opacity: 0; transform: translateY(8px) scale(0.98); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}
.dialog-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1.1rem 1.5rem;
  border-bottom: 1px solid var(--rule);
}
.dialog-header h2 { margin: 0; font-size: 1.1rem; font-weight: 600; letter-spacing: -0.01em; }
.dialog-close {
  width: 32px;
  height: 32px;
  border: 0;
  background: transparent;
  border-radius: 8px;
  font-size: 1.5rem;
  line-height: 1;
  color: var(--muted);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background 0.12s ease, color 0.12s ease;
}
.dialog-close:hover { background: var(--bg); color: var(--fg); }
.dialog-form {
  padding: 1.5rem;
  display: flex;
  flex-direction: column;
  gap: 1rem;
  overflow-y: auto;
}
.dialog-form > label {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  font-size: 0.9rem;
  font-weight: 500;
}
.dialog-form input[type="text"],
.dialog-form input[type="email"],
.dialog-form textarea {
  padding: 0.55rem 0.75rem;
  border: 1px solid var(--rule);
  border-radius: 6px;
  font-size: 0.95rem;
  font-family: inherit;
  resize: none;
  background: var(--card);
  color: var(--fg);
}
.dialog-form input[type="text"]:focus,
.dialog-form input[type="email"]:focus,
.dialog-form textarea:focus {
  outline: 2px solid var(--accent);
  outline-offset: -1px;
  border-color: var(--accent);
}
.dialog-form small { color: var(--muted); font-weight: 400; font-size: 0.8rem; }
.dialog-footer {
  display: flex;
  justify-content: flex-end;
  gap: 0.5rem;
  padding-top: 0.5rem;
  border-top: 1px solid var(--rule);
  margin: 0.5rem -1.5rem -1.5rem;
  padding: 1rem 1.5rem;
  background: var(--bg-soft);
}
/* Create-site modal: scroll only the fields, keep the footer pinned below
   the scroll region. With the default .dialog-form the footer lives inside
   the scroll area, so on a short viewport it scrolls away and the scrollbar
   runs over the footer and the dialog's rounded bottom corners. The fields
   go in .dialog-scroll (the only scroller); the footer sits flush beneath
   it, so no negative-margin bleed is needed. */
#new-site-form,
#invite-user-form {
  padding: 0;
  gap: 0;
  overflow: hidden;
  min-height: 0;
}
#new-site-form .dialog-scroll,
#invite-user-form .dialog-scroll {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  padding: 1.5rem;
  overflow-y: auto;
  min-height: 0;
}
#new-site-form .dialog-footer,
#invite-user-form .dialog-footer { margin: 0; }
/* The negative margins above exist to bleed out of .dialog-form's padding.
   A footer placed straight under .dialog has no padding to escape. */
.dialog > .dialog-footer { margin: 0; }
.section-heading { margin-top: 2.5rem; }

.upload-grid {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 1rem;
}
.upload-grid li { display: block; }
.upload-card {
  position: relative;
  display: block;
  background: var(--card);
  border-radius: 12px;
  overflow: hidden;
  box-shadow: var(--shadow-sm);
  color: inherit;
  transition: box-shadow 0.18s ease;
}
.upload-card::after {
  content: "View";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(37, 99, 235, 0.25), rgba(37, 99, 235, 0.5));
  color: white;
  font-size: 0.95rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transition: opacity 0.18s ease;
  pointer-events: none;
  z-index: 1;
}
.upload-card:hover {
  box-shadow: var(--shadow-md);
  text-decoration: none;
}
.upload-card:hover::after { opacity: 1; }
.upload-thumb {
  position: relative;
  width: 100%;
  aspect-ratio: 4 / 3;
  background: var(--bg);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.upload-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.upload-meta {
  padding: 0.7rem 0.9rem;
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
}
.upload-meta .filename {
  font-size: 0.88rem;
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.upload-meta .muted { font-size: 0.78rem; }

/* Selected-file preview in a settings file-token field — styled as a
   control box so it lines up with the text/color/select inputs. */
.token-file {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  width: 100%;
  box-sizing: border-box;
  min-height: 42px;
  padding: 0.3rem 0.4rem 0.3rem 0.55rem;
  border: 1px solid var(--rule);
  border-radius: 6px;
  background: var(--card);
}
.token-file-thumb {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border-radius: 6px;
  overflow: hidden;
  background: var(--bg);
  border: 1px solid var(--rule);
  flex-shrink: 0;
}
.token-file-thumb img { width: 100%; height: 100%; object-fit: cover; }
/* Filename-extension placeholder for non-image uploads (PDF) shown in
   thumbnails where an <img> would otherwise break. */
.file-badge {
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  color: var(--muted);
}
.file-badge-sm { font-size: 0.5rem; }
.file-badge-lg { font-size: 1.5rem; }
.token-file-name {
  font-size: 0.9rem;
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}
.token-file-empty { color: var(--muted); font-size: 0.9rem; font-weight: 400; }
.token-file-actions { margin-left: auto; display: flex; gap: 0.4rem; flex-shrink: 0; }

/* File-token picker modal: scrollable body, card grid, upload divider */
.dialog-body {
  padding: 1.25rem 1.5rem 1.5rem;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}
/* Fixed 3 columns: the picker loads exactly enough cards to fill 3 rows,
   so the grid should not reflow into a different column count.
   `minmax(0, 1fr)` — not a bare `1fr`, whose `auto` minimum is min-content:
   .picker-name is nowrap, so a long filename would widen its track and push
   the grid past the dialog (and, via the thumb's aspect-ratio, make every
   card taller). A zero minimum lets the name ellipsize as intended. */
.picker-grid {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.75rem;
}
.picker-grid li { display: block; }
/* .dialog-body is a flex column with its own gap — no margins here, or the
   search box and hint get spaced twice. */
.picker-search { margin: 0; }
/* The dialog surface is already --card, so the input takes --bg to stay
   distinguishable (the reverse of .admin-search out on the page). */
.picker-search input[type="search"] {
  width: 100%;
  box-sizing: border-box;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--rule);
  border-radius: 6px;
  font-size: 0.9rem;
  font-family: inherit;
  background: var(--bg);
  color: var(--fg);
}
.picker-search input[type="search"]::placeholder { color: var(--muted); }
.picker-search input[type="search"]:focus {
  outline: none;
  border-color: var(--accent);
}
.picker-hint { margin: 0; font-size: 0.8rem; color: var(--muted); }
@media (max-width: 500px) {
  .picker-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.picker-card {
  position: relative;
  display: block;
  width: 100%;
  padding: 0;
  text-align: left;
  background: var(--card);
  border: 2px solid var(--rule);
  border-radius: 10px;
  overflow: hidden;
  cursor: pointer;
  color: inherit;
  transition: border-color 0.15s ease, box-shadow 0.18s ease;
}
.picker-card:hover {
  border-color: var(--accent);
  box-shadow: var(--shadow-sm);
}
.picker-card.is-selected { border-color: var(--accent); }
.picker-card.is-selected::after {
  content: "✓";
  position: absolute;
  top: 0.4rem;
  right: 0.4rem;
  width: 1.4rem;
  height: 1.4rem;
  border-radius: 50%;
  background: var(--accent);
  color: #fff;
  font-size: 0.85rem;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1;
}
.picker-thumb {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  aspect-ratio: 4 / 3;
  background: var(--bg);
  overflow: hidden;
}
.picker-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.picker-name {
  display: block;
  padding: 0.4rem 0.55rem;
  font-size: 0.78rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.picker-none-icon { color: var(--muted); font-size: 1.6rem; line-height: 1; }
.picker-card-add { border-style: dashed; }
.picker-card-add .picker-thumb { background: transparent; }
.picker-card-add .picker-name { color: var(--muted); }
.picker-add-icon { color: var(--muted); font-size: 2rem; line-height: 1; }
.picker-card-add:hover .picker-add-icon,
.picker-card-add:hover .picker-name { color: var(--accent); }

/* Command palette (Cmd/Ctrl+K) */

/* The hidden trigger app.js clicks. Not display:none — it stays in the
   accessibility tree so the shortcut has a real, labelled control behind it. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
/* Sits high rather than centred: the list grows downward as you type, and a
   centred palette would jump around while the result count changes. */
.palette-backdrop { align-items: flex-start; padding-top: 12vh; }
.palette { max-width: 40rem; }
.palette-form { margin: 0; }
.palette-input {
  width: 100%;
  box-sizing: border-box;
  padding: 1.1rem 1.25rem;
  border: 0;
  border-bottom: 1px solid var(--rule);
  border-radius: 16px 16px 0 0;
  font-size: 1.05rem;
  font-family: inherit;
  background: transparent;
  color: var(--fg);
}
.palette-input:focus { outline: none; }
.palette-input::placeholder { color: var(--muted); }
.palette-empty {
  padding: 2rem 1.25rem;
  text-align: center;
  color: var(--muted);
  font-size: 0.9rem;
}
.palette-results {
  overflow-y: auto;
  max-height: 22rem;
  padding: 0.5rem 0;
}
.palette-group + .palette-group { border-top: 1px solid var(--rule); }
.palette-group-title {
  margin: 0;
  padding: 0.6rem 1.25rem 0.3rem;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
}
.palette-group ul { list-style: none; margin: 0; padding: 0; }
.palette-item {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.55rem 1.25rem;
  color: inherit;
  text-decoration: none;
}
.palette-item:hover { background: var(--bg-soft); text-decoration: none; }
/* Keyboard cursor. Distinct from :hover so moving the mouse over the list
   doesn't make it ambiguous which row Enter will open. */
.palette-item.is-active { background: var(--bg-soft); box-shadow: inset 3px 0 0 var(--accent); }
.palette-item-label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.palette-item-meta { flex: none; font-size: 0.78rem; color: var(--muted); }
.palette-footer {
  display: flex;
  gap: 1rem;
  padding: 0.6rem 1.25rem;
  border-top: 1px solid var(--rule);
  font-size: 0.75rem;
  color: var(--muted);
}
.palette-footer kbd {
  display: inline-block;
  min-width: 1.1rem;
  margin-right: 0.2rem;
  padding: 0.05rem 0.3rem;
  border: 1px solid var(--rule);
  border-radius: 4px;
  background: var(--bg);
  font-family: inherit;
  font-size: 0.72rem;
  text-align: center;
}
@media (max-width: 640px) {
  .palette-backdrop { padding-top: 6vh; }
  .palette-footer { display: none; }
}

/* Upload show / detail */
.upload-show {
  display: grid;
  grid-template-columns: 1fr 320px;
  gap: 2rem;
  align-items: start;
}
.upload-preview {
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: 14px;
  padding: 1.25rem;
  box-shadow: var(--shadow-sm);
  display: flex;
  align-items: center;
  justify-content: center;
}
.upload-preview img {
  max-width: 100%;
  max-height: 70vh;
  border-radius: 6px;
  display: block;
}
/* The browser's own PDF viewer. It needs an explicit height — an <object>
   has no intrinsic size, so without one it collapses to nothing. */
.pdf-viewer {
  width: 100%;
  height: 75vh;
  min-height: 24rem;
  border: 0;
  border-radius: 6px;
  background: var(--bg);
}
/* Shown only when the browser can't render the PDF, as <object> child
   content — so this is the no-viewer path, not a second preview. */
.pdf-fallback {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
  padding: 2rem 1rem;
  text-align: center;
}
.pdf-fallback p { margin: 0; }
.upload-side {
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
}
.upload-side-block {
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: 14px;
  padding: 1.25rem 1.4rem;
  box-shadow: var(--shadow-sm);
}
.upload-side-block .section-heading {
  margin: 0 0 0.9rem;
}
.kv {
  display: grid;
  grid-template-columns: 70px 1fr;
  gap: 0.45rem 1rem;
  margin: 0;
  font-size: 0.88rem;
}
.kv dt {
  color: var(--muted);
  font-weight: 500;
}
.kv dd {
  margin: 0;
  color: var(--fg);
  word-break: break-word;
}
.snippet {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  margin-bottom: 0.6rem;
  font-size: 0.82rem;
  font-weight: 500;
  color: var(--muted);
}
.snippet input {
  font-family: ui-monospace, Menlo, monospace;
  font-size: 0.8rem;
  padding: 0.45rem 0.65rem;
  border: 1px solid var(--rule);
  border-radius: 6px;
  background: var(--bg-soft);
  color: var(--fg);
}
.copy-btn { width: 100%; justify-content: center; margin-bottom: 0.85rem; }
.copy-btn-success {
  background: var(--good) !important;
  border-color: var(--good) !important;
  color: white !important;
}
.danger-block {
  width: 100%;
  justify-content: center;
  border-radius: 8px;
  padding: 0.55rem 1rem;
}
.danger-block + .danger-block { margin-top: 0.6rem; }

/* Warning callout (used in danger-style modals) — named "callout" to avoid daisyUI's .alert */
.callout {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  padding: 0.85rem 1rem;
  border-radius: 8px;
  font-size: 0.88rem;
  line-height: 1.5;
  margin: 0;
}
.callout strong { font-weight: 600; }
.callout-warning {
  background: var(--amber-soft);
  color: #92400e;
  border: 1px solid #fcd34d;
}

@media (max-width: 900px) {
  .upload-show {
    grid-template-columns: 1fr;
  }
}

/* ---- Landing page ---- */
.landing {
  font-family: -apple-system, BlinkMacSystemFont, "Inter", "Helvetica Neue", Arial, sans-serif;
  color: var(--landing-fg);
  background: var(--landing-bg);
  min-height: 100vh;
  -webkit-font-smoothing: antialiased;
}

.landing a { color: var(--landing-accent); text-decoration: none; }
.landing a:hover { color: var(--landing-accent-hover); }

/* Nav */
.landing-nav {
  max-width: 1100px;
  margin: 0 auto;
  padding: 1.4rem 1.5rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.landing-nav .brand {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  color: var(--landing-fg);
  font-weight: 600;
  font-size: 1rem;
}
.landing-nav .brand:hover { color: var(--landing-fg); }
.landing .brand-mark { color: var(--landing-accent); }
.landing-nav .brand-logo {
  width: 1.6rem;
  height: 1.6rem;
  border-radius: 30%;
  object-fit: cover;
}
.landing-nav .nav-cta { display: flex; align-items: center; gap: 1rem; }
.landing-nav .nav-link { color: var(--landing-fg-soft); font-weight: 500; font-size: 0.92rem; }
.landing-nav .nav-link:hover { color: var(--landing-fg); }
.landing-nav .nav-link.is-active {
  color: var(--landing-fg);
  font-weight: 600;
  position: relative;
}
.landing-nav .nav-link.is-active::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -0.5rem;
  height: 2px;
  border-radius: 2px;
  background: var(--landing-accent);
}
/* Base GitHub button for admin contexts (e.g. the Themes top bar). The
   landing page overrides these with its own palette via the more specific
   `.landing-nav` / `.landing-footer` rules below. */
.github-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.4rem 0.75rem;
  border-radius: 8px;
  border: 1px solid var(--rule);
  background: var(--card);
  color: var(--fg);
  font-weight: 500;
  font-size: 0.88rem;
  text-decoration: none;
  transition: background 0.15s ease, border-color 0.15s ease;
}
.github-btn:hover {
  background: var(--bg);
  border-color: var(--rule-strong);
  text-decoration: none;
}
.github-btn svg { width: 18px; height: 18px; }

.landing .github-btn,
.landing-nav .github-btn,
.landing-footer .github-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.4rem 0.75rem;
  border-radius: 8px;
  border: 1px solid var(--landing-rule);
  background: var(--landing-card);
  color: var(--landing-fg) !important;
  font-weight: 500;
  font-size: 0.88rem;
  transition: background 0.15s ease, border-color 0.15s ease;
}
.landing .github-btn:hover,
.landing-nav .github-btn:hover,
.landing-footer .github-btn:hover {
  background: var(--landing-bg);
  border-color: var(--landing-fg);
  text-decoration: none;
}
.landing .github-btn svg,
.landing-nav .github-btn svg,
.landing-footer .github-btn svg { width: 18px; height: 18px; }

/* Buttons (landing variants) */
.landing .btn,
.landing-nav .btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.55rem 1.05rem;
  border-radius: 8px;
  font-weight: 500;
  font-size: 0.92rem;
  transition: transform 0.1s ease, background 0.15s ease, box-shadow 0.15s ease;
  border: 1px solid transparent;
  cursor: pointer;
}
.landing .btn-sm,
.landing-nav .btn-sm { padding: 0.45rem 0.85rem; font-size: 0.88rem; }
.landing .btn-lg { padding: 0.8rem 1.5rem; font-size: 1rem; }
.landing .btn-primary,
.landing-nav .btn-primary {
  background: var(--landing-accent);
  color: white !important;
  box-shadow: 0 1px 2px rgba(37, 99, 235, 0.25);
}
.landing .btn-primary:hover,
.landing-nav .btn-primary:hover {
  background: var(--landing-accent-hover);
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(37, 99, 235, 0.3);
}
.landing .btn-ghost {
  background: var(--landing-card);
  color: var(--landing-fg) !important;
  border-color: var(--landing-rule);
}
.landing .btn-ghost:hover {
  background: var(--landing-accent-soft);
  border-color: var(--landing-accent);
}

/* Hero */
.landing-hero {
  max-width: 1100px;
  margin: 3rem auto 5rem;
  padding: 0 1.5rem;
  display: grid;
  grid-template-columns: 1.1fr 1fr;
  align-items: center;
  gap: 4rem;
}
.hero-eyebrow {
  display: inline-block;
  padding: 0.25rem 0.7rem;
  background: var(--landing-accent-soft);
  color: var(--landing-accent);
  border-radius: 999px;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  margin-bottom: 1.25rem;
}
.landing-hero h1 {
  font-size: clamp(2.2rem, 4.5vw, 3.4rem);
  line-height: 1.07;
  letter-spacing: -0.03em;
  margin: 0 0 1.25rem;
  color: var(--landing-fg);
  font-weight: 700;
}
.hero-lede {
  font-size: 1.15rem;
  line-height: 1.6;
  color: var(--landing-fg-soft);
  margin: 0 0 2rem;
  max-width: 55ch;
}
.hero-cta { display: flex; gap: 0.85rem; flex-wrap: wrap; }

/* Hero mock */
.hero-mock { display: flex; justify-content: center; }
.mock-window {
  width: 100%;
  max-width: 460px;
  background: var(--landing-card);
  border: 1px solid var(--landing-rule);
  border-radius: 14px;
  box-shadow: 0 25px 60px -20px rgba(37, 99, 235, 0.25), 0 10px 30px -10px rgba(15, 23, 42, 0.15);
  overflow: hidden;
  transform: rotate(-1.5deg);
  transition: transform 0.3s ease;
}
.mock-window:hover { transform: rotate(0); }
.mock-chrome {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.7rem 1rem;
  background: #f1f5f9;
  border-bottom: 1px solid var(--landing-rule);
}
.mock-chrome .dot { width: 11px; height: 11px; border-radius: 50%; }
.mock-chrome .dot-r { background: #fb7185; }
.mock-chrome .dot-y { background: #fbbf24; }
.mock-chrome .dot-g { background: #4ade80; }
.mock-url {
  margin-left: 0.6rem;
  font-size: 0.78rem;
  color: var(--landing-muted);
  font-family: ui-monospace, Menlo, monospace;
}
.mock-body { padding: 1.5rem 1.75rem 1.75rem; }
.mock-eyebrow {
  display: block;
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--landing-accent);
  margin-bottom: 0.75rem;
}
.mock-body h3 {
  font-size: 1.3rem;
  line-height: 1.25;
  letter-spacing: -0.015em;
  margin: 0 0 0.6rem;
}
.mock-body p {
  font-size: 0.92rem;
  color: var(--landing-fg-soft);
  line-height: 1.55;
  margin: 0 0 0.9rem;
}
.mock-link { color: var(--landing-accent); font-weight: 500; font-size: 0.9rem; }

/* Features */
.landing-features {
  max-width: 1100px;
  margin: 0 auto 5rem;
  padding: 0 1.5rem;
}
.landing-features .section-title {
  font-size: clamp(1.5rem, 2.5vw, 2rem);
  letter-spacing: -0.02em;
  margin: 0 0 2rem;
  font-weight: 600;
}
.feature-grid {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 1rem;
}
.feature-card {
  background: var(--landing-card);
  border: 1px solid var(--landing-rule);
  border-radius: 12px;
  padding: 1.5rem;
  transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
}
.feature-card:hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 20px -8px rgba(15, 23, 42, 0.1);
  border-color: var(--landing-accent);
}
.feature-icon {
  width: 40px;
  height: 40px;
  border-radius: 10px;
  background: var(--landing-accent-soft);
  color: var(--landing-accent);
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 1rem;
}
.feature-icon svg { width: 22px; height: 22px; }
.feature-card h3 {
  font-size: 1.05rem;
  letter-spacing: -0.01em;
  margin: 0 0 0.5rem;
  color: var(--landing-fg);
}
.feature-card p {
  font-size: 0.92rem;
  line-height: 1.55;
  color: var(--landing-fg-soft);
  margin: 0;
}

/* FAQ */
.landing-faq {
  max-width: 1100px;
  margin: 0 auto 5rem;
  padding: 0 1.5rem;
}
.landing-faq .section-title {
  font-size: clamp(1.5rem, 2.5vw, 2rem);
  letter-spacing: -0.02em;
  margin: 0 0 2rem;
  font-weight: 600;
}
.faq-list {
  display: grid;
  gap: 0.75rem;
}
.faq-item {
  background: var(--landing-card);
  border: 1px solid var(--landing-rule);
  border-radius: 12px;
  padding: 0 1.5rem;
  transition: border-color 0.18s ease;
}
.faq-item[open] {
  border-color: var(--landing-accent);
}
.faq-item summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.25rem 0;
  cursor: pointer;
  list-style: none;
}
.faq-item summary::-webkit-details-marker {
  display: none;
}
.faq-item summary h3 {
  font-size: 1.05rem;
  letter-spacing: -0.01em;
  margin: 0;
  font-weight: 600;
  color: var(--landing-fg);
}
.faq-marker {
  position: relative;
  flex: 0 0 14px;
  width: 14px;
  height: 14px;
}
.faq-marker::before,
.faq-marker::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 12px;
  height: 2px;
  background: var(--landing-accent);
  border-radius: 2px;
  transform: translate(-50%, -50%);
  transition: transform 0.18s ease, opacity 0.18s ease;
}
.faq-marker::after {
  transform: translate(-50%, -50%) rotate(90deg);
}
.faq-item[open] .faq-marker::after {
  opacity: 0;
}
.faq-item p {
  font-size: 0.95rem;
  line-height: 1.6;
  color: var(--landing-fg-soft);
  margin: 0;
  padding: 0 0 1.4rem;
}

/* Bottom CTA */
.landing-cta {
  max-width: 1100px;
  margin: 0 auto 4rem;
  padding: 0 1.5rem;
}
.cta-card {
  background: linear-gradient(135deg, var(--landing-accent) 0%, #4f46e5 100%);
  color: white;
  border-radius: 16px;
  padding: 3rem 2.5rem;
  text-align: center;
  box-shadow: 0 20px 50px -20px rgba(37, 99, 235, 0.5);
}
.cta-card h2 {
  font-size: clamp(1.5rem, 3vw, 2rem);
  letter-spacing: -0.02em;
  margin: 0 0 0.7rem;
  font-weight: 600;
}
.cta-card p {
  font-size: 1.05rem;
  opacity: 0.9;
  margin: 0 0 1.75rem;
}
.cta-card .hero-cta { justify-content: center; }
.cta-card .btn-primary {
  background: white;
  color: var(--landing-accent) !important;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.cta-card .btn-primary:hover {
  background: white;
  color: var(--landing-accent-hover) !important;
  transform: translateY(-1px);
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.15);
}
.cta-card .btn-ghost {
  background: transparent;
  color: white !important;
  border-color: rgba(255, 255, 255, 0.35);
}
.cta-card .btn-ghost:hover {
  background: rgba(255, 255, 255, 0.1);
  border-color: rgba(255, 255, 255, 0.6);
}
/* Footer */
.landing-footer {
  max-width: 1100px;
  margin: 0 auto;
  padding: 1.5rem 1.5rem 2rem;
  border-top: 1px solid var(--landing-rule);
  color: var(--landing-muted);
  font-size: 0.85rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
}
.landing-footer-brand {
  display: inline-flex;
  align-items: baseline;
  gap: 0.5rem;
}
.landing-footer-brand strong { color: var(--landing-fg); font-weight: 600; }
.landing-footer .brand-mark { color: var(--landing-accent); }
.landing-footer .github-btn {
  font-size: 0.82rem;
  padding: 0.3rem 0.65rem;
}
.landing-version {
  font-family: ui-monospace, Menlo, monospace;
  letter-spacing: 0.02em;
  font-size: 0.75rem;
}
.landing-footer-links {
  display: inline-flex;
  align-items: center;
  gap: 1.25rem;
}
.landing-footer-links a {
  color: var(--landing-muted);
  text-decoration: none;
  font-size: 0.85rem;
  transition: color 0.15s ease;
}
.landing-footer-links a:hover { color: var(--landing-fg); }

/* Stacked and centred on a phone — as three left-aligned rows the brand,
   links and GitHub button read as unrelated fragments. */
@media (max-width: 640px) {
  .landing-footer {
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 1.25rem;
    padding: 1.75rem 1.25rem 2.5rem;
  }
  .landing-footer-links {
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.75rem 1.25rem;
  }
}

/* The signed-out marketplace: an admin body sitting between the marketing nav
   and footer. Same 1100px column as the homepage, so nothing shifts when a
   visitor arrives through the front page. */
.public-shell {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--landing-bg);
}
/* As flex items the nav and footer would shrink to their content — their
   `margin: 0 auto` opts them out of the default stretch. */
.public-shell > .landing-nav,
.public-shell > .landing-footer { width: 100%; }
.public-content {
  flex: 1;
  width: 100%;
  max-width: 1100px;
  margin: 0 auto;
  padding: 0.5rem 1.5rem 4rem;
}

@media (max-width: 800px) {
  .landing-hero {
    grid-template-columns: 1fr;
    gap: 2.5rem;
    margin: 2rem auto 3rem;
  }
  .hero-mock { display: none; }
  .cta-card { padding: 2rem 1.5rem; }
}

/* Mobile nav: the inline links collapse behind a hamburger. The toggle is a
   checkbox rather than a scripted button so it works on the landing page,
   which is a plain controller render with no LiveView attached. */
.nav-burger { display: none; }
/* Off-screen rather than display:none, so the menu is still keyboard-openable. */
.nav-toggle {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: 0;
  opacity: 0;
  pointer-events: none;
}

@media (max-width: 640px) {
  .landing-nav { position: relative; padding: 1rem 1.25rem; }
  .nav-burger {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    margin: -0.25rem 0;
    border-radius: 9px;
    color: var(--landing-fg);
    cursor: pointer;
  }
  .nav-burger svg { width: 24px; height: 24px; }
  .nav-toggle:focus-visible + .nav-burger {
    outline: 2px solid var(--landing-accent);
    outline-offset: 2px;
  }

  .landing-nav .nav-cta {
    display: none;
    position: absolute;
    top: 100%;
    left: 1.25rem;
    right: 1.25rem;
    z-index: 40;
    flex-direction: column;
    align-items: stretch;
    gap: 0.9rem;
    padding: 1rem;
    background: var(--landing-card);
    border: 1px solid var(--landing-rule);
    border-radius: 12px;
    box-shadow: 0 12px 30px rgba(0, 0, 0, 0.14);
  }
  .nav-toggle:checked ~ .nav-cta { display: flex; }
  .landing-nav .nav-link { font-size: 1rem; }
  /* The underline would sit on the row below in a stacked menu. */
  .landing-nav .nav-link.is-active::after { display: none; }
  .landing-nav .github-btn,
  .landing-nav .btn { justify-content: center; }
}

/* Page intro paragraph — sits below the page-head title. */
.page-intro {
  margin: 0 0 1.5rem;
  color: var(--muted);
  max-width: 60ch;
  line-height: 1.55;
}

/* Generic chip — small labelled tag without the pill's leading dot. */
.chip {
  display: inline-flex;
  align-items: center;
  padding: 0.18rem 0.6rem;
  border-radius: 999px;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  white-space: nowrap;
}
.chip-neutral { background: var(--rule); color: var(--fg-soft, #525252); }
/* "You" tag beside the current member's email — nudge right of the email and
   optically center it against the text. */
.chip-you { margin-left: 0.55rem; vertical-align: middle; position: relative; top: -1px; }
.chip-accent { background: var(--accent-soft); color: var(--accent-strong); }
/* Green chip for a verified marketplace theme. */
.chip-verified { background: var(--good-soft); color: #166534; }
/* Amber chip for a theme its author keeps private (not on the marketplace). */
.chip-private { background: var(--amber-soft); color: #92400e; }
/* Green chip marking an installed marketplace theme in the library. */
.chip-marketplace { background: var(--good-soft); color: #166534; }

/* Marketplace grid — image-forward cards; the preview leads each card. */
.marketplace-grid {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(300px, 100%), 1fr));
  gap: 1.25rem;
}
.marketplace-grid li { display: block; }
.marketplace-card {
  display: flex;
  flex-direction: column;
  height: 100%;
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: 12px;
  overflow: hidden;
  box-shadow: var(--shadow-sm);
  transition: box-shadow 0.18s ease, border-color 0.18s ease;
  color: inherit;
  text-decoration: none;
}
.marketplace-card:hover {
  box-shadow: var(--shadow-md);
  border-color: var(--rule-strong);
  text-decoration: none;
}
.marketplace-thumb {
  position: relative;
  aspect-ratio: 16 / 9;
  width: 100%;
  background: var(--rule);
  overflow: hidden;
}
.marketplace-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Screenshots are tall; the top of a page is the recognisable part. */
  object-position: top;
  display: block;
}
/* The thumbnail is a link to the theme's detail page. */
.marketplace-thumb-btn {
  display: block;
  width: 100%;
  height: 100%;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}
.marketplace-thumb-zoom {
  position: absolute;
  bottom: 0.5rem;
  right: 0.5rem;
  width: 1.7rem;
  height: 1.7rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 7px;
  background: rgba(0, 0, 0, 0.55);
  color: #fff;
  font-size: 1rem;
  opacity: 0;
  transition: opacity 0.15s ease;
}
.marketplace-card:hover .marketplace-thumb-zoom { opacity: 1; }
/* Status + version chips overlaid on the top-right of the preview, like
   the theme library cards. */
.marketplace-card-tags {
  position: absolute;
  top: 0.5rem;
  right: 0.5rem;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
}

/* Compact in-line icon buttons in a card's footer (edit / install). */
.card-icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  padding: 0;
  flex-shrink: 0;
  border: 1px solid var(--rule);
  border-radius: 8px;
  background: var(--card);
  color: var(--fg-soft);
  cursor: pointer;
  text-decoration: none;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.card-icon-btn svg { width: 1.1rem; height: 1.1rem; }
.card-icon-btn:hover {
  background: var(--bg-soft);
  border-color: var(--rule-strong);
  color: var(--fg);
  text-decoration: none;
}
.card-icon-btn.is-primary {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}
.card-icon-btn.is-primary:hover {
  filter: brightness(1.05);
  color: #fff;
}
.card-icon-btn.is-installed {
  color: var(--accent);
  border-color: var(--accent-soft);
}
.card-icon-btn:disabled {
  opacity: 0.55;
  cursor: default;
}
.marketplace-thumb-placeholder {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.marketplace-card-meta {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.9rem 1rem;
}
.marketplace-card-id { min-width: 0; }
/* Two lines of the author's description, so the grid is scannable without
   opening every card. */
.marketplace-card-desc {
  margin: 0.25rem 0 0;
  color: var(--muted);
  font-size: 0.82rem;
  line-height: 1.45;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.marketplace-card-meta h3 {
  margin: 0;
  font-size: 1rem;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.marketplace-card-meta h3 a { color: inherit; text-decoration: none; }
.marketplace-card-meta h3 a:hover { color: var(--accent); }
.marketplace-card-meta .btn { flex-shrink: 0; }
.marketplace-card-by {
  display: block;
  color: var(--muted);
  font-size: 0.8rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* A right-aligned button row inside a dialog form (e.g. "Add images"). */
.dialog-form-inline {
  display: flex;
  justify-content: flex-end;
  margin-top: 0.75rem;
}

/* Header title that carries inline status/version chips. */
.dialog-title {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-wrap: wrap;
  min-width: 0;
}

/* Drag-to-reorder preview list in the publish modal. */
.preview-list-hint { margin: 0 0 0.6rem; font-size: 0.82rem; }
.preview-list {
  list-style: none;
  padding: 0;
  margin: 0 0 1.25rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.preview-row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.5rem 0.6rem;
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: 10px;
}
.preview-row.is-dragging {
  opacity: 0.5;
  border-style: dashed;
  border-color: var(--accent);
}
.preview-drag {
  display: inline-flex;
  color: var(--muted);
  cursor: grab;
}
.preview-drag svg { width: 1rem; height: 1rem; }
.preview-thumb {
  width: 4.5rem;
  height: 3rem;
  object-fit: cover;
  border-radius: 6px;
  display: block;
}
.preview-row-spacer { flex: 1; }

/* Theme library grid — cards rather than a table. */
.theme-grid {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 1rem;
}
.theme-grid li { display: block; }
.theme-card {
  position: relative;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  height: 100%;
  /* Fixed height so every card matches across rows regardless of whether
     it has a description (the description is clamped to keep this true). */
  min-height: 9rem;
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: 12px;
  /* Extra bottom padding reserves space for the absolutely-positioned
     delete icon so the description never overlaps it. */
  padding: 1.1rem 1.15rem 2.7rem;
  box-shadow: var(--shadow-sm);
  transition: box-shadow 0.18s ease, border-color 0.18s ease;
}
.theme-card:hover {
  box-shadow: var(--shadow-md);
  border-color: var(--rule-strong);
}
/* Dashed, see-through placeholder card linking to the GitHub template.
   Defined after .theme-card (and its :hover) so these overrides win. */
.theme-card-add {
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  width: 100%;
  padding: 1.1rem 1.15rem;
  background: transparent;
  border-style: dashed;
  border-color: var(--rule-strong);
  text-align: center;
  color: var(--muted);
  font: inherit;
  cursor: pointer;
  box-shadow: none;
}
.theme-card-add:hover {
  color: var(--accent);
  border-color: var(--accent);
  box-shadow: none;
  text-decoration: none;
}
.theme-card-add-icon { font-size: 1.5rem; line-height: 1; font-weight: 400; }
.theme-card-add-label { font-weight: 600; font-size: 0.95rem; }
.theme-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
}
.theme-card-tags {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  flex-shrink: 0;
}
.theme-card-title {
  margin: 0;
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: -0.01em;
}
.theme-card-desc {
  margin: 0;
  color: var(--muted);
  font-size: 0.88rem;
  line-height: 1.5;
  /* Clamp to two lines so a long description can't make one card (and so
     its whole row) taller than the rest. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
/* Quiet, icon-only delete in the bottom-right of the card. Fades in
   slightly on card hover and turns destructive-red on its own hover.
   Disabled state (built-ins, themes owned by someone else) stays muted
   and unresponsive. */
.theme-card-actions {
  position: absolute;
  bottom: 0.6rem;
  right: 0.6rem;
  display: inline-flex;
  align-items: center;
  gap: 0.15rem;
}
.theme-card-icon-btn {
  width: 1.85rem;
  height: 1.85rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--muted);
  opacity: 0.55;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease, opacity 0.15s ease;
}
.theme-card:hover .theme-card-icon-btn { opacity: 1; }
.theme-card-icon-btn:hover:not(:disabled) {
  background: var(--accent-soft);
  color: var(--accent-strong);
}
/* The delete button turns destructive-red on its own hover. */
.theme-card-icon-btn.is-danger:hover:not(:disabled) {
  background: var(--danger-soft);
  color: var(--danger);
}
/* A published theme's marketplace toggle reads as "live" (green). */
.theme-card-icon-btn.is-live {
  color: var(--good);
  opacity: 1;
}
.theme-card-icon-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.theme-card-icon-btn:disabled {
  cursor: not-allowed;
  opacity: 0.35;
}
.theme-card-icon-btn svg { width: 1.05rem; height: 1.05rem; }
.theme-card-version {
  /* Version numbers shouldn't get the chip's all-caps treatment — the
     'v' prefix and digits read better as-is, with tabular numerals so
     the right column doesn't jitter across cards. */
  text-transform: none;
  letter-spacing: 0;
  font-variant-numeric: tabular-nums;
}

/* Theme upload — single-file row inside the upload modal. */
.upload-entries .entry-name {
  font-size: 0.9rem;
  font-weight: 500;
  flex: 1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ---- Custom domain ---- */
.domain-summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
}

.import-summary {
  margin-top: 1rem;
  padding: 1rem 1.25rem;
  border: 1px solid var(--accent-soft);
  border-radius: 12px;
  background: var(--accent-soft);
}
.import-summary p { margin: 0 0 0.5rem; }
.import-summary p:last-child { margin-bottom: 0; }
.import-summary-links { display: flex; gap: 1rem; }
.import-problems { margin-top: 0.5rem; }
.import-problems summary { cursor: pointer; color: var(--danger); font-weight: 500; }
.import-problems ul { margin: 0.5rem 0 0; padding-left: 1.25rem; }
.import-problems li { font-size: 0.85rem; margin-bottom: 0.25rem; }

.domain-badge {
  display: inline-block;
  margin-left: 0.5rem;
  padding: 0.1rem 0.5rem;
  border-radius: 999px;
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: lowercase;
  background: var(--accent-soft);
  color: var(--accent-strong);
}
.domain-badge-active {
  background: #dcfce7;
  color: #166534;
}
.domain-badge-failed {
  background: var(--danger-soft);
  color: var(--danger);
}

.dns-card {
  border: 1px solid var(--rule);
  border-radius: 14px;
  background: var(--card);
  box-shadow: var(--shadow-sm);
  padding: 1.5rem 1.75rem;
  margin: 0 0 1.5rem;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}
.dns-intro {
  margin: 0;
  color: var(--muted);
  font-size: 0.9rem;
  line-height: 1.55;
}
.dns-record {
  border: 1px solid var(--rule);
  border-radius: 10px;
  background: var(--bg-soft);
  padding: 0.9rem 1rem;
}
.dns-record-head {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  margin-bottom: 0.6rem;
  flex-wrap: wrap;
}
.dns-type {
  font-family: ui-monospace, Menlo, monospace;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  background: var(--accent-soft);
  color: var(--accent-strong);
  padding: 0.15rem 0.5rem;
  border-radius: 999px;
}
.dns-purpose { color: var(--muted); font-size: 0.85rem; }
.dns-fields {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}
.dns-fields > div {
  display: flex;
  gap: 0.6rem;
  align-items: baseline;
}
.dns-fields dt {
  margin: 0;
  width: 3.5rem;
  flex: none;
  color: var(--muted);
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}
.dns-fields dd { margin: 0; min-width: 0; }
.dns-fields dd code { word-break: break-all; }
.dns-apex { margin-top: 0.25rem; }
.dns-apex > summary {
  cursor: pointer;
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--accent);
}
.dns-apex-note {
  color: var(--muted);
  font-size: 0.85rem;
  margin: 0.6rem 0;
}
.dns-apex .dns-record { margin-top: 0.6rem; }

.domain-status { font-size: 0.95rem; }
.domain-status-active {
  padding: 0.6rem 0.8rem;
  border-radius: var(--radius-box);
  background: #dcfce7;
  color: #166534;
}
.domain-error {
  margin: 0 0 1.25rem;
  padding: 0.6rem 0.85rem;
  border-radius: var(--radius-box);
  background: var(--danger-soft);
  color: var(--danger);
  font-size: 0.9rem;
}
/* Inside the result card the flex gap already spaces it. */
.dns-card .domain-error {
  margin: 0;
}

/* This file is for your main application CSS */

/* Nested object/list settings fields (theme-page object & list field types) */
.settings-group-field {
  border: 1px solid var(--rule);
  border-radius: 12px;
  padding: 1rem 1.1rem 1.15rem;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}
.settings-group-field > legend {
  font-weight: 600;
  font-size: 0.92rem;
  padding: 0 0.4rem;
}
.settings-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}
.settings-list-item {
  display: flex;
  align-items: flex-start;
  gap: 0.65rem;
  padding: 0.75rem;
  background: var(--bg, #f8fafc);
  border: 1px solid var(--rule);
  border-radius: 10px;
}
.settings-list-item.is-dragging {
  opacity: 0.5;
  border-style: dashed;
  border-color: var(--accent);
}
.settings-list-drag {
  display: inline-flex;
  color: var(--muted);
  cursor: grab;
  padding-top: 0.4rem;
}
.settings-list-drag svg { width: 1rem; height: 1rem; }
.settings-list-fields { flex: 1; }
.settings-list-remove { align-self: flex-start; }

/* Install/Installed action on a browse card, in a site's install context. */
.marketplace-card-actions {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  flex-shrink: 0;
}

/* "Upload theme" tile in the My themes grid — matches a card's footprint. */
.marketplace-card-add {
  width: 100%;
  box-sizing: border-box;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  min-height: 12rem;
  border-style: dashed;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  font: inherit;
  box-shadow: none;
}
.marketplace-card-add:hover {
  color: var(--fg);
  border-color: var(--rule-strong);
}
.marketplace-card-add-icon { font-size: 1.6rem; line-height: 1; }
.marketplace-card-add-label { font-size: 0.9rem; font-weight: 500; }

/* Site picker modal — a stack of full-width site buttons (install target). */
.site-picker-list {
  list-style: none;
  margin: 0.5rem 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}
.site-picker-list .btn {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

/* Banner shown when the marketplace is opened in a site's install context. */
.marketplace-context-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 1rem;
  padding: 0.75rem 1rem;
  background: var(--accent-soft);
  border: 1px solid var(--rule);
  border-radius: 8px;
  font-size: 0.9rem;
}

/* ---- Theme manage page ---- */
.manage-description-form textarea {
  width: 100%;
  box-sizing: border-box;
  margin-bottom: 0.75rem;
  padding: 0.6rem 0.7rem;
  border: 1px solid var(--rule);
  border-radius: 8px;
  background: var(--card);
  color: var(--fg);
  font: inherit;
  resize: vertical;
}
.manage-description-form textarea:focus {
  outline: none;
  border-color: var(--accent);
}
.manage-upload-submit { margin-top: 0.9rem; }

/* Theme detail page — a product page: preview gallery and description on the
   left, a sticky install card on the right. */
.theme-detail {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 320px;
  gap: 1.5rem;
  align-items: start;
}
.theme-detail-main {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  min-width: 0;
}

/* The preview sits in a browser-like frame so a screenshot reads as a site
   rather than a loose image. */
.theme-preview {
  margin: 0;
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: 14px;
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}
.theme-preview-chrome {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.6rem 0.9rem;
  border-bottom: 1px solid var(--rule);
  background: var(--bg);
}
.theme-preview-dots { display: flex; gap: 0.35rem; }
.theme-preview-dots i {
  width: 0.55rem;
  height: 0.55rem;
  border-radius: 999px;
  background: var(--rule-strong);
}
.theme-preview-count {
  font-size: 0.75rem;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
}
/* A fixed window onto the preview: screenshots vary in height, and anchoring
   to the top shows the part of a page that sells a theme. */
.theme-preview-stage {
  display: flex;
  justify-content: center;
  align-items: center;
  aspect-ratio: 16 / 9;
  background: var(--bg);
}
/* Nothing to frame yet — don't reserve a screen-sized void. */
.theme-preview-stage.is-empty {
  aspect-ratio: auto;
  min-height: 11rem;
}
.theme-preview-stage img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top;
}
.theme-preview-empty {
  margin: auto;
  color: var(--muted);
  font-size: 0.9rem;
}

/* `overflow-x: auto` clips the vertical axis too, so the padding has to be
   deep enough to hold a thumbnail's remove button where it overhangs the
   corner; the matching negative margin keeps the strip flush with the frame. */
.theme-thumbs {
  display: flex;
  gap: 0.6rem;
  overflow-x: auto;
  padding: 0.6rem;
  margin: -0.6rem;
}
.theme-thumb-strip,
.theme-thumbs form {
  display: flex;
  gap: 0.6rem;
}
.theme-thumb-wrap { position: relative; }
.theme-thumb-wrap[draggable="true"] { cursor: grab; }
.theme-thumb-wrap.is-dragging { opacity: 0.4; }
.theme-thumb {
  display: block;
  width: 6.5rem;
  padding: 0;
  border: 1px solid var(--rule);
  border-radius: 10px;
  overflow: hidden;
  background: var(--card);
  cursor: pointer;
  transition: box-shadow 0.18s ease, border-color 0.18s ease;
}
.theme-thumb img {
  width: 100%;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  object-position: top;
  display: block;
  pointer-events: none;
}
.theme-thumb:hover { border-color: var(--rule-strong); }
.theme-thumb.is-active {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

/* Remove control, revealed on hover so the strip stays calm while browsing. */
.theme-thumb-remove {
  position: absolute;
  top: -0.35rem;
  right: -0.35rem;
  width: 1.35rem;
  height: 1.35rem;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 1px solid var(--rule);
  border-radius: 50%;
  background: var(--card);
  color: var(--muted);
  font-size: 0.9rem;
  line-height: 1;
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.15s ease, color 0.15s ease;
}
.theme-thumb-wrap:hover .theme-thumb-remove,
.theme-thumb-remove:focus-visible { opacity: 1; }
.theme-thumb-remove:hover { color: var(--danger); border-color: currentColor; }

/* "Add image" tile — the same footprint as a thumbnail, dashed like the
   upload tile in the theme grid. */
.theme-thumb-add {
  flex: 0 0 6.5rem;
  aspect-ratio: 16 / 10;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.1rem;
  border: 1px dashed var(--rule-strong);
  border-radius: 10px;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  transition: border-color 0.15s ease, color 0.15s ease, background 0.15s ease;
}
.theme-thumb-add:hover {
  border-color: var(--accent);
  color: var(--accent);
  background: var(--accent-soft);
}
.theme-thumb-add input[type="file"] {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  border: 0;
}
.theme-thumb-add-icon { font-size: 1.2rem; line-height: 1; }
.theme-thumb-add-label { font-size: 0.72rem; font-weight: 500; }
.theme-upload-progress { margin: 0; font-size: 0.8rem; }

/* Inline description editing. */
.theme-about-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 0.6rem;
}
.theme-about-form { display: flex; flex-direction: column; gap: 0.75rem; }
.theme-about-form textarea {
  width: 100%;
  box-sizing: border-box;
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--rule);
  border-radius: 8px;
  font: inherit;
  line-height: 1.6;
  resize: vertical;
  background: var(--card);
}
.theme-about-form textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.theme-about-actions { display: flex; justify-content: flex-end; gap: 0.5rem; }

.theme-about {
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: 14px;
  box-shadow: var(--shadow-sm);
  padding: 1.5rem 1.75rem;
}
.theme-about h2 {
  margin: 0 0 0.6rem;
  font-size: 1.05rem;
  font-weight: 600;
  letter-spacing: -0.015em;
}
.theme-about p {
  margin: 0;
  max-width: 68ch;
  line-height: 1.7;
}
.theme-about p + p { margin-top: 0.85rem; }

/* The sidebar stays in view while the previews and description scroll. */
.theme-detail-aside {
  position: sticky;
  top: 1.5rem;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

/* Install card — the page's one call to action. */
.install-card {
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: 14px;
  box-shadow: var(--shadow-sm);
  padding: 1.5rem;
}
.install-card h2 {
  margin: 0;
  font-size: 1.05rem;
  font-weight: 600;
  letter-spacing: -0.015em;
}
.install-card label {
  display: block;
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 0.35rem;
}

/* Site combobox — a text filter over the user's sites. Rendered by the
   LiveView rather than a native datalist, so the menu matches the app. */
.site-select { position: relative; }
.site-select-input {
  width: 100%;
  box-sizing: border-box;
  padding: 0.55rem 2.2rem 0.55rem 0.75rem;
  border: 1px solid var(--rule);
  border-radius: 8px;
  font-size: 0.95rem;
  font-family: inherit;
  background: var(--card);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2371717a' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.7rem center;
}
.site-select-input:focus,
.site-select-input.is-open {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.site-select-menu {
  position: absolute;
  z-index: 20;
  top: calc(100% + 0.35rem);
  left: 0;
  right: 0;
  margin: 0;
  padding: 0.3rem;
  list-style: none;
  max-height: 14rem;
  overflow-y: auto;
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: 10px;
  box-shadow: var(--shadow-md);
}
.site-select-option {
  display: flex;
  flex-direction: column;
  gap: 0.05rem;
  width: 100%;
  text-align: left;
  padding: 0.45rem 0.55rem;
  border: 0;
  border-radius: 7px;
  background: none;
  font: inherit;
  cursor: pointer;
}
.site-select-option:hover { background: var(--bg); }
.site-select-option.is-selected { background: var(--accent-soft); }
.site-select-name { font-size: 0.9rem; font-weight: 500; }
.site-select-slug { font-size: 0.78rem; color: var(--muted); }
.site-select-empty { padding: 0.5rem 0.55rem; color: var(--muted); font-size: 0.85rem; }
.install-card .btn { padding: 0.6rem 1rem; }
.install-card-next {
  margin: 0;
  font-size: 0.85rem;
  text-align: center;
}

/* Author card — who made this theme and where to reach them. The listing's
   publish/delete controls live in the page header, not here: they're the
   author's chrome, not part of what a visitor is reading. */
.author-card {
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: 14px;
  box-shadow: var(--shadow-sm);
  padding: 1.25rem 1.5rem;
}
.author-identity {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  min-width: 0;
}
.author-avatar {
  width: 38px;
  height: 38px;
  border-radius: 50%;
  background: var(--accent);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.95rem;
  font-weight: 600;
  flex-shrink: 0;
}
.author-avatar.is-platform { background: var(--fg); }
.author-lines {
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.author-name {
  font-size: 0.95rem;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.author-meta {
  font-size: 0.8rem;
  color: var(--muted);
  line-height: 1.45;
}

/* Author-defined pointers to docs, source, support — a hairline below the
   identity rather than a card of their own. */
.author-links {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding-top: 0.9rem;
  border-top: 1px solid var(--rule);
}
.author-links-empty { margin: 0; font-size: 0.82rem; line-height: 1.5; }
.author-add-link {
  align-self: flex-start;
  padding: 0;
  border: 0;
  background: none;
  color: var(--muted);
  font: inherit;
  font-size: 0.82rem;
  cursor: pointer;
}
.author-add-link:hover { color: var(--accent); }
.theme-links {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
}
.theme-link {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.25rem 0.4rem;
  margin: 0 -0.4rem;
  border-radius: 7px;
}
.theme-link::before {
  content: "↗";
  color: var(--muted);
  font-size: 0.8rem;
  line-height: 1;
}
.theme-link:hover { background: var(--bg); }
.theme-link[draggable="true"] { cursor: grab; }
.theme-link.is-dragging { opacity: 0.4; }
.theme-link a {
  flex: 1;
  min-width: 0;
  font-size: 0.88rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.theme-link-remove {
  flex-shrink: 0;
  width: 1.25rem;
  height: 1.25rem;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  color: var(--muted);
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
  opacity: 0;
}
.theme-link:hover .theme-link-remove,
.theme-link-remove:focus-visible { opacity: 1; }
.theme-link-remove:hover { color: var(--danger); }
.link-form { display: flex; flex-direction: column; gap: 0.5rem; }
.link-form input[type="text"] {
  width: 100%;
  box-sizing: border-box;
  padding: 0.45rem 0.6rem;
  border: 1px solid var(--rule);
  border-radius: 8px;
  font: inherit;
  font-size: 0.9rem;
  background: var(--card);
}
.link-form input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.link-form-actions { display: flex; justify-content: flex-end; gap: 0.5rem; }

@media (max-width: 900px) {
  .theme-detail { grid-template-columns: 1fr; }
  .theme-detail-aside { position: static; }
}

/* Manage dialog — a titled row with its control on the right. */
.manage-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
}
.manage-row h3 {
  margin: 0 0 0.2rem;
  font-size: 0.95rem;
  font-weight: 600;
}
.manage-row p {
  margin: 0;
  max-width: 44ch;
  color: var(--muted);
  font-size: 0.85rem;
  line-height: 1.55;
}
.manage-row .btn { flex-shrink: 0; }
.manage-row.is-danger {
  padding-top: 1.25rem;
  border-top: 1px solid var(--rule);
}

/* Confetti burst on install (see phx:celebrate in app.js). Pieces are
   positioned and animated from JS; this only gives them a body. */
.confetti-layer {
  position: fixed;
  inset: 0;
  z-index: 200;
  pointer-events: none;
  overflow: hidden;
}
.confetti-piece {
  position: absolute;
  width: 9px;
  height: 12px;
  margin: -6px 0 0 -4px;
  border-radius: 2px;
  will-change: transform, opacity;
}

/* The install button's moment: it pops in as "Installed". */
.install-card .btn-installed {
  animation: installed-pop 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
}
@keyframes installed-pop {
  0% { transform: scale(0.9); }
  60% { transform: scale(1.04); }
  100% { transform: scale(1); }
}
@media (prefers-reduced-motion: reduce) {
  .install-card .btn-installed { animation: none; }
}
