/* ==========================================================================
   Kerui admin panel — self-contained stylesheet.
   Dark sidebar, light content area, responsive down to small phones.
   ========================================================================== */

:root {
  --sidebar-bg: #0f172a;
  --sidebar-bg-soft: #1e293b;
  --sidebar-fg: #cbd5e1;
  --sidebar-fg-dim: #94a3b8;
  --sidebar-active: #2563eb;
  --content-bg: #f1f5f9;
  --card-bg: #ffffff;
  --text: #0f172a;
  --text-dim: #64748b;
  --border: #e2e8f0;
  --border-strong: #cbd5e1;
  --primary: #2563eb;
  --primary-dark: #1d4ed8;
  --danger: #dc2626;
  --danger-dark: #b91c1c;
  --success-bg: #dcfce7;
  --success-fg: #166534;
  --error-bg: #fee2e2;
  --error-fg: #991b1b;
  --info-bg: #dbeafe;
  --info-fg: #1e40af;
  --radius: 10px;
  --radius-sm: 6px;
  --shadow: 0 1px 2px rgba(15, 23, 42, .06), 0 8px 24px rgba(15, 23, 42, .06);
  --sidebar-w: 240px;
  --topbar-h: 60px;
  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "PingFang SC", "Microsoft YaHei", sans-serif;
}

* { box-sizing: border-box; }

html, body { margin: 0; padding: 0; }

body.admin {
  min-height: 100vh;
  background: var(--content-bg);
  color: var(--text);
  font-family: var(--font);
  font-size: 14px;
  line-height: 1.5;
  -webkit-text-size-adjust: 100%;
}

code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: .92em;
  background: #f1f5f9;
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 0 4px;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  background: #fff;
  color: var(--text);
  padding: 8px 14px;
  z-index: 50;
  border-radius: 0 0 var(--radius-sm) 0;
}
.skip-link:focus { left: 0; }

/* ------------------------------------------------------------------ topbar */

.topbar {
  position: fixed;
  inset: 0 0 auto 0;
  height: var(--topbar-h);
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 0 16px;
  background: var(--sidebar-bg);
  color: #fff;
  z-index: 30;
  border-bottom: 1px solid rgba(255, 255, 255, .08);
}

.topbar__burger {
  display: none;
  flex-direction: column;
  justify-content: space-between;
  width: 34px;
  height: 28px;
  padding: 6px 6px;
  background: transparent;
  border: 1px solid rgba(255, 255, 255, .25);
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.topbar__burger span {
  display: block;
  height: 2px;
  background: #fff;
  border-radius: 1px;
}

.topbar__brand {
  display: flex;
  align-items: center;
  gap: 10px;
  color: #fff;
  text-decoration: none;
  font-weight: 600;
  letter-spacing: .2px;
  white-space: nowrap;
}
.topbar__logo {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border-radius: 8px;
  background: linear-gradient(135deg, #3b82f6, #1d4ed8);
  color: #fff;
  font-weight: 700;
  flex: 0 0 auto;
}
.topbar__spacer { flex: 1 1 auto; }

.topbar__user {
  display: flex;
  align-items: center;
  gap: 10px;
}

/* Interface-language switcher, top right. A segmented pill: the active
   language is a solid chip so the current choice is obvious at a glance. */
.langswitch {
  display: inline-flex;
  align-items: center;
  padding: 2px;
  border-radius: 999px;
  background: rgba(255, 255, 255, .07);
  border: 1px solid rgba(255, 255, 255, .14);
  flex: 0 0 auto;
}
.langswitch__opt {
  padding: 4px 10px;
  border-radius: 999px;
  color: var(--sidebar-fg);
  text-decoration: none;
  font-size: 12.5px;
  line-height: 1.4;
  white-space: nowrap;
  transition: background .12s ease, color .12s ease;
}
.langswitch__opt:hover { color: #fff; background: rgba(255, 255, 255, .12); }
.langswitch__opt.is-active {
  background: #fff;
  color: var(--sidebar-bg);
  font-weight: 650;
}
.topbar__account {
  display: flex;
  align-items: center;
  gap: 8px;
  color: var(--sidebar-fg);
  text-decoration: none;
}
.topbar__account:hover { color: #fff; }
.topbar__user-name { font-size: 13px; }

.avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--sidebar-bg-soft);
  color: #fff;
  font-weight: 600;
  font-size: 13px;
  border: 1px solid rgba(255, 255, 255, .15);
}

/* ----------------------------------------------------------------- sidebar */

.sidebar {
  position: fixed;
  top: var(--topbar-h);
  bottom: 0;
  left: 0;
  width: var(--sidebar-w);
  background: var(--sidebar-bg);
  color: var(--sidebar-fg);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: 12px 10px;
  overflow-y: auto;
  z-index: 25;
}

.sidebar__nav { display: flex; flex-direction: column; gap: 2px; }
.sidebar__footer { border-top: 1px solid rgba(255, 255, 255, .08); padding-top: 8px; margin-top: 12px; }

.sidebar__link {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 12px;
  border-radius: var(--radius-sm);
  color: var(--sidebar-fg);
  text-decoration: none;
  font-size: 13.5px;
  transition: background .12s ease, color .12s ease;
}
.sidebar__link:hover { background: var(--sidebar-bg-soft); color: #fff; }
.sidebar__link.is-active {
  background: var(--sidebar-active);
  color: #fff;
  font-weight: 600;
}
.sidebar__icon {
  width: 18px;
  text-align: center;
  opacity: .9;
  flex: 0 0 auto;
}
.sidebar__label { flex: 1 1 auto; }

.badge {
  display: inline-block;
  min-width: 20px;
  padding: 1px 6px;
  border-radius: 999px;
  background: var(--danger);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  text-align: center;
}

.scrim {
  position: fixed;
  inset: var(--topbar-h) 0 0 0;
  background: rgba(15, 23, 42, .45);
  z-index: 24;
}

/* ----------------------------------------------------------------- content */

/* Full-bleed: the panel fills the viewport at every width. A `max-width` here
   used to cap the content at 1400px, which on a 1920px monitor left a ~280px
   dead gutter down the right-hand side of every page. The listing tables have
   columns to spare, so they are the last thing that should be boxed in. */
.content {
  margin: var(--topbar-h) 0 0 var(--sidebar-w);
  padding: 22px;
}

.page-head { margin-bottom: 16px; }
.page-head__title {
  margin: 0;
  font-size: 22px;
  font-weight: 650;
  letter-spacing: -.2px;
}

/* ------------------------------------------------------------------- cards */

.card {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 18px;
  margin-bottom: 18px;
}

.card__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
  margin-bottom: 14px;
}
.card__title { margin: 0; font-size: 16px; font-weight: 650; }
.card__sub { margin: 4px 0 0; color: var(--text-dim); font-size: 12.5px; }
.card__actions { display: flex; gap: 8px; flex-wrap: wrap; }

.card--error { text-align: center; padding: 48px 18px; }
.error-code {
  margin: 0 0 6px;
  font-size: 44px;
  font-weight: 700;
  color: var(--border-strong);
  line-height: 1;
}

.grid-2 {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(360px, 1fr));
  gap: 18px;
}
/* A grid item defaults to `min-width: auto`, so it refuses to shrink below its
   content's min-content width. The dashboard pairs cards that hold tables, and
   a table's min-content width is large — which made the card, and with it the
   whole page, wider than a phone screen, and left `.table-wrap`'s
   `overflow-x: auto` with nothing to do. Let the item shrink so the table
   scrolls inside its card instead of dragging the page sideways. */
.grid-2 > * { min-width: 0; }

.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 12px;
  margin-bottom: 18px;
}
.stat {
  display: block;
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 14px 16px;
  text-decoration: none;
  color: var(--text);
  transition: transform .12s ease, border-color .12s ease;
}
.stat:hover { transform: translateY(-1px); border-color: var(--border-strong); }
.stat__value { display: block; font-size: 26px; font-weight: 700; letter-spacing: -.5px; }
.stat__label { display: block; color: var(--text-dim); font-size: 12.5px; margin-top: 2px; }
.stat--alert .stat__value { color: var(--danger); }

.quicklinks { display: flex; flex-wrap: wrap; gap: 8px; }

/* ----------------------------------------------------------------- buttons */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 8px 14px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-strong);
  background: #fff;
  color: var(--text);
  font: inherit;
  font-size: 13px;
  font-weight: 550;
  text-decoration: none;
  cursor: pointer;
  transition: background .12s ease, border-color .12s ease, color .12s ease;
  white-space: nowrap;
}
.btn:hover { background: #f8fafc; border-color: #94a3b8; }
.btn:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.btn[disabled], .btn[aria-disabled="true"] { opacity: .45; cursor: not-allowed; }

.btn--primary { background: var(--primary); border-color: var(--primary); color: #fff; }
.btn--primary:hover { background: var(--primary-dark); border-color: var(--primary-dark); }

.btn--danger { background: #fff; border-color: #fca5a5; color: var(--danger); }
.btn--danger:hover { background: var(--danger); border-color: var(--danger); color: #fff; }

.btn--ghost { background: transparent; border-color: transparent; color: var(--text-dim); }
.btn--ghost:hover { background: #e2e8f0; color: var(--text); }

/* Back and Cancel. A plain .btn is white, which reads as another submit
   button next to the primary one; grey says "this leaves without saving". */
.btn--muted { background: #e2e8f0; border-color: #cbd5e1; color: #334155; }
.btn--muted:hover { background: #cbd5e1; border-color: #94a3b8; color: var(--text); }

.btn--sm { padding: 5px 10px; font-size: 12.5px; }
.btn--block { width: 100%; }

.inline { display: inline-flex; margin: 0; }
/* Row action buttons stay on one line: wrapping them made the Actions cell
   taller than the row and pushed Delete out of view on narrow screens. The
   cell is `width: 1%; white-space: nowrap`, so the column sizes to the
   buttons and never squeezes them. */
.rowactions { display: flex; gap: 6px; flex-wrap: nowrap; align-items: center; }

/* --------------------------------------------------------------- flash/alerts */

.alert {
  border-radius: var(--radius);
  padding: 12px 14px;
  margin-bottom: 16px;
  font-size: 13.5px;
  border: 1px solid transparent;
}
.alert--success { background: var(--success-bg); color: var(--success-fg); border-color: #86efac; }
.alert--error { background: var(--error-bg); color: var(--error-fg); border-color: #fca5a5; }
.alert__title { margin: 0 0 6px; font-weight: 650; }
.alert__list { margin: 0; padding-left: 20px; }

/* --------------------------------------------------------------- toolbar */

.toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 12px;
  padding: 12px 14px;
  background: #f8fafc;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  margin-bottom: 14px;
}
.toolbar__field { display: flex; flex-direction: column; gap: 4px; min-width: 190px; flex: 1 1 190px; }
.toolbar__label { font-size: 12px; color: var(--text-dim); font-weight: 600; }
.toolbar__actions { display: flex; gap: 8px; }

.tabs {
  display: flex;
  gap: 4px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 14px;
}
.tabs__tab {
  padding: 8px 14px;
  text-decoration: none;
  color: var(--text-dim);
  border-bottom: 2px solid transparent;
  font-size: 13.5px;
}
.tabs__tab:hover { color: var(--text); }
.tabs__tab.is-active { color: var(--primary); border-bottom-color: var(--primary); font-weight: 600; }

/* --------------------------------------------------------------- tables */

.table-wrap { overflow-x: auto; }

.table { width: 100%; border-collapse: collapse; font-size: 13.5px; }
.table th, .table td {
  text-align: left;
  padding: 9px 10px;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}
.table th {
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: .4px;
  color: var(--text-dim);
  background: #f8fafc;
  white-space: nowrap;
}
.table tbody tr:hover { background: #f8fafc; }
.table tr.is-unread td { font-weight: 600; background: #f8fbff; }
.table tr.is-unread:hover { background: #eff6ff; }
.table__actions-col { width: 1%; white-space: nowrap; }

.thumb {
  width: 46px;
  height: 34px;
  object-fit: cover;
  border-radius: 5px;
  border: 1px solid var(--border);
  background: #f1f5f9;
  display: block;
}

/* ------------------------------------------------------- image viewer */

/* Every thumbnail in the panel opens full size. A 46px table thumbnail is not
   enough to tell one product photo from another. */
img.thumb, .preview img, .gallery__thumb { cursor: zoom-in; }
img.thumb:hover, .preview img:hover, .gallery__thumb:hover { border-color: var(--primary); }
img.thumb:focus-visible, .preview img:focus-visible, .gallery__thumb:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

.lightbox {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: rgba(2, 6, 23, .84);
}
.lightbox[hidden] { display: none; }
.lightbox__frame {
  margin: 0;
  max-width: 100%;
  max-height: 100%;
  display: flex;
  flex-direction: column;
  gap: 10px;
  align-items: center;
}
.lightbox__img {
  max-width: min(1200px, 92vw);
  max-height: 78vh;
  width: auto;
  height: auto;
  object-fit: contain;
  background: #fff;
  border-radius: var(--radius-sm);
  box-shadow: 0 20px 60px rgba(2, 6, 23, .5);
}
.lightbox__bar {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  justify-content: center;
  max-width: 92vw;
  color: #e2e8f0;
  font-size: 12.5px;
}
.lightbox__path {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 60vw;
}
.lightbox__hint { color: var(--sidebar-fg-dim); }
.lightbox__close { flex: 0 0 auto; }
body.has-lightbox { overflow: hidden; }

/* --------------------------------------------------- upload feedback */

.spinner {
  display: inline-block;
  width: 13px;
  height: 13px;
  border: 2px solid var(--border-strong);
  border-top-color: var(--primary);
  border-radius: 50%;
  animation: spin .7s linear infinite;
  vertical-align: -2px;
}
.spinner--lg { width: 26px; height: 26px; border-width: 3px; }
@keyframes spin { to { transform: rotate(360deg); } }

/* Shown beside a file input while the browser reads the chosen file. */
.filechip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 9px;
  border-radius: 999px;
  background: var(--info-bg);
  color: var(--info-fg);
  font-size: 12px;
  white-space: nowrap;
}
.filechip .spinner { border-color: rgba(30, 64, 175, .25); border-top-color: var(--info-fg); }

/* Covers the page while a form with a file in it is being uploaded. */
.uploading {
  position: fixed;
  inset: 0;
  z-index: 110;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(2, 6, 23, .55);
}
.uploading[hidden] { display: none; }
.uploading__card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  padding: 26px 34px;
  background: #fff;
  border-radius: var(--radius);
  box-shadow: 0 20px 50px rgba(2, 6, 23, .35);
  text-align: center;
  max-width: min(420px, 90vw);
}
.uploading__title { margin: 0; font-weight: 650; }
.uploading__note { margin: 0; color: var(--text-dim); font-size: 12.5px; }

@media (prefers-reduced-motion: reduce) {
  .spinner { animation-duration: 2s; }
}

.muted { color: var(--text-dim); font-weight: 400; }
.nowrap { white-space: nowrap; }
.empty {
  margin: 0;
  padding: 26px 14px;
  text-align: center;
  color: var(--text-dim);
  background: #f8fafc;
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-sm);
}

.pill {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 11.5px;
  font-weight: 650;
  line-height: 1.6;
}
.pill--ok { background: var(--success-bg); color: var(--success-fg); }
.pill--muted { background: #e2e8f0; color: #475569; }
.pill--info { background: var(--info-bg); color: var(--info-fg); }

/* --------------------------------------------------------------- pager */

/* The summary stays on the left; the page-size picker and the page links are
   pushed together to the right. The auto margin sits on the picker rather than
   on the nav so the two controls end up as one right-hand group — with
   `space-between` the picker would be stranded in the middle of a 1680px row. */
.pager {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  padding-top: 14px;
  margin-top: 4px;
  border-top: 1px solid var(--border);
}
.pager__summary { margin: 0; color: var(--text-dim); font-size: 12.5px; }
.pager__nav { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; }
.pager__link {
  min-width: 32px;
  padding: 5px 9px;
  text-align: center;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  text-decoration: none;
  color: var(--text);
  font-size: 12.5px;
  background: #fff;
}
.pager__link:hover { background: #f1f5f9; }
.pager__link.is-current { background: var(--primary); border-color: var(--primary); color: #fff; font-weight: 600; }
.pager__link.is-disabled { opacity: .45; pointer-events: none; }
.pager__gap { padding: 0 4px; color: var(--text-dim); }

/* Page-size picker. Right-aligned, immediately left of the page links. */
.pager__size { display: flex; align-items: center; gap: 7px; margin: 0 0 0 auto; }
.pager__size-label { color: var(--text-dim); font-size: 12.5px; white-space: nowrap; }
.pager__size .input { width: auto; padding: 5px 8px; font-size: 12.5px; }
.pager__size .btn { padding: 5px 10px; font-size: 12.5px; }

/* --------------------------------------------------------------- forms */

.form__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 14px 18px;
}
.form__section {
  margin: 20px 0 12px;
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: .5px;
  color: var(--text-dim);
  border-bottom: 1px solid var(--border);
  padding-bottom: 6px;
}
.form__publicid { margin: -6px 0 14px; }
.form__publicid code { white-space: nowrap; }

.form__actions {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  align-items: center;
  margin-top: 20px;
  padding-top: 16px;
  border-top: 1px solid var(--border);
}

.field { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.field--wide { grid-column: 1 / -1; }
.field__label { font-weight: 600; font-size: 12.5px; color: #334155; }
.field.has-error .input { border-color: var(--danger); }
.field__error { margin: 0; color: var(--danger); font-size: 12.5px; }
.req { color: var(--danger); font-weight: 700; }

.input {
  width: 100%;
  padding: 8px 10px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: #fff;
  color: var(--text);
  font: inherit;
  font-size: 13.5px;
}
.input:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px rgba(37, 99, 235, .15); }

/* A control that sits inside a field's right edge — currently the password
   reveal button on the sign-in screen. The wrapper is what positions it, so the
   button stays attached to the input it acts on rather than to the form.
   The input gains right padding to clear it, or a long value would run under. */
.input-affix { position: relative; display: flex; }
.input-affix .input { padding-right: 38px; }
.input-affix__toggle {
  position: absolute;
  right: 3px;
  top: 50%;
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  border: 0;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--text-dim);
  cursor: pointer;
}
.input-affix__toggle:hover { color: var(--text); background: #eef2f7; }
.input-affix__toggle:focus-visible { outline: 2px solid var(--primary); outline-offset: 1px; }
/* Both icons live in the DOM and one is shown, keyed off the same aria-pressed
   the script sets — so what is drawn cannot drift from the state a screen
   reader is told. */
.input-affix__toggle svg { display: block; }
.input-affix__toggle svg + svg { display: none; }
.input-affix__toggle[aria-pressed="true"] svg:first-of-type { display: none; }
.input-affix__toggle[aria-pressed="true"] svg + svg { display: block; }
.input--area { resize: vertical; min-height: 76px; line-height: 1.5; }
.input--file { padding: 6px; background: #f8fafc; }

/* The stored image path: shown, not typed. It reads as a value rather than a
   box waiting for input, while staying selectable so it can be copied. */
.input--path[readonly] {
  background: #f1f5f9;
  color: var(--text-dim);
  cursor: default;
}
.input--path[readonly]:focus {
  border-color: var(--border-strong);
  box-shadow: none;
}

.hint { margin: 0; color: var(--text-dim); font-size: 12px; }

/* ------------------------------------------------------------ rich editor */

.rte { display: flex; flex-direction: column; gap: 0; min-width: 0; }

.rte__toolbar {
  display: flex;
  align-items: center;
  gap: 3px;
  flex-wrap: wrap;
  padding: 5px 6px;
  background: #f8fafc;
  border: 1px solid var(--border-strong);
  border-bottom: 0;
  border-radius: var(--radius-sm) var(--radius-sm) 0 0;
}
.rte__btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 30px;
  height: 28px;
  padding: 0 7px;
  border: 1px solid transparent;
  border-radius: 5px;
  background: transparent;
  color: #334155;
  font: inherit;
  font-size: 13px;
  line-height: 1;
  cursor: pointer;
}
.rte__btn:hover { background: #e2e8f0; }
.rte__btn:focus-visible { outline: 2px solid var(--primary); outline-offset: 1px; }
.rte__btn.is-active { background: var(--primary); border-color: var(--primary); color: #fff; }
.rte__btn--wide { min-width: 0; padding: 0 10px; font-size: 12.5px; white-space: nowrap; }
.rte__sep { width: 1px; height: 18px; background: var(--border-strong); margin: 0 3px; }
.rte__spacer { flex: 1 1 auto; }
.rte__select {
  height: 28px;
  padding: 0 6px;
  border: 1px solid var(--border-strong);
  border-radius: 5px;
  background: #fff;
  color: var(--text);
  font: inherit;
  font-size: 12.5px;
}

/* The editable area. It inherits the textarea's box so switching between the
   two does not jump the layout. */
.rte__surface {
  min-height: 260px;
  max-height: 70vh;
  overflow-y: auto;
  padding: 10px 12px;
  border: 1px solid var(--border-strong);
  border-radius: 0 0 var(--radius-sm) var(--radius-sm);
  background: #fff;
  /* Typography is the theme's, not this panel's: the surface previews a public
     page, so it has to measure like one. Where these values come from is
     documented with the heading rules below. */
  font-family: "Fira Sans", sans-serif;
  font-size: 14px;
  line-height: 26px;
  color: #878D97;
  overflow-wrap: anywhere;
}
.rte__surface:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px rgba(37, 99, 235, .15); }
.rte__surface img { max-width: 100%; height: auto; }
.rte__surface table { max-width: 100%; }
/* Headings, paragraphs and lists, at the theme's measurements.
   A CMS body is set in Fira Sans and sized and spaced by the theme's own
   rules, so an editor that renders it at the panel's 13.5px system font puts
   every line break somewhere the live page will not, and every heading at a
   fraction of its real size — the author cannot tell how the page will read.
   Copied from public/images/style.css: `--body-font` / `--title-font` /
   `--body-color` / `--title-color`, the shared h1–h6 block plus each level's
   size, and the `p` rule. The list inset is Bootstrap's Reboot list rule as
   it lands on the site (2rem against the theme's 14px root). Update these
   alongside the theme, or the preview drifts again. */
.rte__surface h1, .rte__surface h2, .rte__surface h3,
.rte__surface h4, .rte__surface h5, .rte__surface h6 {
  font-family: "Exo", sans-serif;
  color: #1A1A1A;
  font-weight: 700;
  line-height: 1.5;
  margin: 0 0 15px 0;
}
.rte__surface h1 { font-size: 48px; }
.rte__surface h2 { font-size: 40px; }
.rte__surface h3 { font-size: 36px; }
.rte__surface h4 { font-size: 30px; }
.rte__surface h5 { font-size: 24px; }
.rte__surface h6 { font-size: 20px; }
.rte__surface p { margin: 0 0 18px 0; line-height: 1.63; }
.rte__surface ul, .rte__surface ol { padding-left: 28px; margin: 0 0 14px 0; }

/* The grid the content is written against.
   Product and article bodies lay themselves out with the theme's Bootstrap
   classes — `row`, `col-md-6` — and the theme's spacing utilities, because
   that is what the public pages load. This panel loads only this stylesheet,
   so without these rules the same markup previews as full-width stacked
   blocks: the author arranges a grid, saves, and the live page comes out
   different, which is exactly what the classes were copied here to prevent.

   Only the handful of rules the stored content actually uses are mirrored —
   `row`, `col-md-6`, `col-xl-4`, `mt-30`, `mb-30` cover every body in the
   database. Values and breakpoints are copied from
   public/images/bootstrap.min.css and public/images/style.css so the preview
   and the site agree; if content ever adopts another class, mirror it here. */
.rte__surface .row {
  --bs-gutter-x: 1.5rem;
  --bs-gutter-y: 0;
  display: flex;
  flex-wrap: wrap;
  margin-top: calc(var(--bs-gutter-y) * -1);
  margin-right: calc(var(--bs-gutter-x) / -2);
  margin-left: calc(var(--bs-gutter-x) / -2);
}
.rte__surface .row > * {
  flex-shrink: 0;
  width: 100%;
  max-width: 100%;
  padding-right: calc(var(--bs-gutter-x) / 2);
  padding-left: calc(var(--bs-gutter-x) / 2);
  margin-top: var(--bs-gutter-y);
}
@media (min-width: 768px) {
  .rte__surface .col-md-6 { flex: 0 0 auto; width: 50%; }
}
@media (min-width: 1200px) {
  .rte__surface .col-xl-4 { flex: 0 0 auto; width: 33.3333333333%; }
}
.rte__surface .mt-30 { margin-top: 30px; }
.rte__surface .mb-30 { margin-bottom: 30px; }
.rte__surface blockquote {
  margin: .6em 0;
  padding: 2px 12px;
  border-left: 3px solid var(--border-strong);
  color: var(--text-dim);
}
/* In source mode the toolbar stays put but the formatting tools are moot. */
.rte__toolbar.is-source .rte__btn:not(.rte__btn--wide),
.rte__toolbar.is-source .rte__select,
.rte__toolbar.is-source .rte__sep { opacity: .4; pointer-events: none; }
.rte__source { border-radius: 0 0 var(--radius-sm) var(--radius-sm); min-height: 260px; }
.rte__hint { margin-top: 5px; }

/* Images inside the editor open full size on double-click. */
.rte__surface img { cursor: zoom-in; }

/* Image picker, anchored under the toolbar. */
.rte { position: relative; }
.rte__pop {
  position: absolute;
  top: 40px;
  left: 6px;
  z-index: 20;
  width: min(430px, 92%);
  padding: 12px;
  background: #fff;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  box-shadow: 0 12px 30px rgba(2, 6, 23, .18);
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.rte__pop[hidden] { display: none; }
.rte__pop-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.rte__pop-label { font-size: 12.5px; font-weight: 600; color: #334155; min-width: 84px; }
.rte__pop-row .input { flex: 1 1 150px; min-width: 0; }
.rte__pop-status { margin: 0; font-size: 12.5px; color: var(--text-dim); min-height: 1em; }
.rte__pop-status:not(:empty) { color: var(--info-fg); }

/* Size panel. Its rows have more controls than the picker's, so the label
   column is dropped and the whole row is used. */
.rte__pop--size .rte__pop-row { flex-wrap: nowrap; }
.rte__pop--size .input[type="number"] { flex: 0 1 92px; min-width: 0; }
.rte__pop-times { color: var(--text-dim); flex: 0 0 auto; }
@media (max-width: 640px) {
  .rte__pop--size .rte__pop-row { flex-wrap: wrap; }
  .rte__pop--size .rte__pop-row .btn { flex: 1 1 auto; }
}

.switch { display: inline-flex; align-items: center; gap: 9px; cursor: pointer; }
.switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.switch__track {
  position: relative;
  width: 42px;
  height: 24px;
  border-radius: 999px;
  background: var(--border-strong);
  transition: background .15s ease;
  flex: 0 0 auto;
}
.switch__knob {
  position: absolute;
  top: 3px;
  left: 3px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: #fff;
  transition: transform .15s ease;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .25);
}
.switch input:checked + .switch__track { background: var(--primary); }
.switch input:checked + .switch__track .switch__knob { transform: translateX(18px); }
.switch input:focus-visible + .switch__track { box-shadow: 0 0 0 3px rgba(37, 99, 235, .25); }
.switch__text { font-size: 13px; color: #334155; }

/* Menu permissions on the user screen. Plain checkboxes, unlike the single
   on/off .switch above: several are ticked at once and the ticked set *is* the
   value, so a row of toggle switches would both misread and imply that the
   choices exclude each other. */
.perm { margin: 20px 0 12px; padding: 0; border: 0; }
/* Matches .form__section, so the permission block reads as one more section of
   the form rather than a line of text crowding the hint above it. */
.perm__legend {
  display: block;
  width: 100%;
  padding: 0 0 6px;
  margin: 0 0 10px;
  border-bottom: 1px solid var(--border);
  font-size: 13px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .5px;
  color: var(--text-dim);
}
.perm__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 8px 16px;
  margin-top: 8px;
}
.perm__item { display: flex; align-items: center; gap: 8px; font-size: 13px; color: #334155; cursor: pointer; }
.perm__box { flex: 0 0 auto; width: 15px; height: 15px; margin: 0; accent-color: var(--primary); cursor: pointer; }
/* A menu that is always available (the dashboard) is shown ticked and disabled
   rather than hidden, so the list matches the sidebar and the account can see
   there is nothing to grant. */
.perm__item--locked { color: var(--text-dim); cursor: default; }
.perm__item--locked .perm__box { cursor: default; }
.perm__note { font-size: 12px; color: var(--text-dim); }

.imagefield { display: flex; flex-direction: column; gap: 8px; }
.imagefield__row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.preview {
  width: 150px;
  height: 105px;
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-sm);
  background: #f8fafc;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.preview img { width: 100%; height: 100%; object-fit: contain; display: block; }
.preview__empty { color: var(--text-dim); font-size: 12px; }

/* --------------------------------------------------------------- gallery */

.gallery {
  margin-top: 22px;
  padding-top: 18px;
  border-top: 1px solid var(--border);
}
.gallery__head { margin-bottom: 12px; }
.gallery__title { margin: 0 0 4px; font-size: 14px; font-weight: 650; }
.gallery__list { list-style: none; margin: 0 0 14px; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.gallery__item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: #f8fafc;
}
.gallery__thumb {
  width: 72px;
  height: 54px;
  object-fit: cover;
  border-radius: 5px;
  border: 1px solid var(--border);
  background: #fff;
  flex: 0 0 auto;
}
.gallery__meta { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex: 1 1 auto; min-width: 0; flex-wrap: wrap; }
/* The stored address is not shown anywhere any more; each item is identified
   by its position and its picture. */
.gallery__index {
  font-size: 12.5px;
  color: var(--text-dim);
  white-space: nowrap;
}
.gallery__actions { display: flex; gap: 6px; }
.gallery__empty {
  padding: 18px;
  text-align: center;
  color: var(--text-dim);
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-sm);
  background: #f8fafc;
}
.gallery__add {
  display: flex;
  align-items: flex-end;
  gap: 10px;
  flex-wrap: wrap;
}
.gallery__add-field { display: flex; flex-direction: column; gap: 4px; flex: 1 1 220px; }

/* --------------------------------------------------------------- details */

.details {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 10px;
  margin: 0 0 16px;
}
.details__row { display: flex; flex-direction: column; gap: 2px; padding: 9px 12px; background: #f8fafc; border-radius: var(--radius-sm); }
.details dt { font-size: 11.5px; text-transform: uppercase; letter-spacing: .4px; color: var(--text-dim); font-weight: 600; }
.details dd { margin: 0; font-size: 13.5px; overflow-wrap: anywhere; }

.message-body__title { margin: 0 0 8px; font-size: 13px; text-transform: uppercase; letter-spacing: .4px; color: var(--text-dim); }
.message-body__text {
  margin: 0;
  padding: 14px;
  background: #f8fafc;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-family: var(--font);
  font-size: 13.5px;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* --------------------------------------------------------------- login */

body.admin--login {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  padding: 20px;
  background: linear-gradient(160deg, #0f172a 0%, #1e293b 60%, #334155 100%);
}
.login { width: 100%; max-width: 400px; }
.login__card {
  background: #fff;
  border-radius: 14px;
  padding: 26px;
  box-shadow: 0 20px 50px rgba(2, 6, 23, .35);
}
.login__brand { display: flex; align-items: center; gap: 12px; margin-bottom: 20px; }
.login__title { margin: 0; font-size: 16px; font-weight: 650; }
.login__sub { margin: 2px 0 0; color: var(--text-dim); font-size: 12.5px; }
.login__form { display: flex; flex-direction: column; gap: 14px; }
.login__foot { margin: 16px 0 0; color: var(--text-dim); font-size: 11.5px; text-align: center; }

/* --------------------------------------------------------------- responsive */

@media (max-width: 900px) {
  .content { padding: 16px; }
  .grid-2 { grid-template-columns: 1fr; }
}

@media (max-width: 760px) {
  .topbar__burger { display: flex; }
  .topbar__brand-text { display: none; }
  .topbar__user-name { display: none; }
  .content { margin-left: 0; padding: 14px; }
  .sidebar {
    transform: translateX(-100%);
    transition: transform .2s ease;
    width: 260px;
    box-shadow: 0 10px 30px rgba(2, 6, 23, .3);
  }
  body.sidebar-open .sidebar { transform: translateX(0); }
  body.sidebar-open { overflow: hidden; }
  .page-head__title { font-size: 19px; }
  .stats { grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); }
  .stat__value { font-size: 22px; }
  .card { padding: 14px; }
  .form__grid { grid-template-columns: 1fr; }
  .toolbar { flex-direction: column; align-items: stretch; }
  /* Once the toolbar stacks, `.toolbar__field`'s `flex-basis: 190px` is read
     as a HEIGHT, so each field became a 190px-tall box holding a 40px input —
     a wall of dead space. Reset it so fields size to their content. */
  .toolbar__field { flex: 0 0 auto; min-width: 0; }
  .toolbar__actions { justify-content: flex-end; }
  .pager { justify-content: center; }
  /* Once the picker wraps onto its own line, `margin-left: auto` would push it
     to the right of that line instead of centring it with the rest. */
  .pager__size { margin-left: 0; }
}

/* ------------------------------------------------- table on small screens */
/* The listing tables are wider than a phone. Rather than clipping columns or
   letting the whole page scroll sideways, the table scrolls inside its own
   container and the Actions column is pinned to the right edge, so the row
   controls are always reachable. */
.table__actions-col {
  position: sticky;
  right: 0;
  background: #fff;
  box-shadow: -6px 0 8px -6px rgba(2, 6, 23, .18);
}
.table th.table__actions-col { background: #f8fafc; }
/* The sticky cell paints its own background, so it must repeat the row's
   background for every row state — otherwise hovering (or an unread message
   row) leaves a white patch under the buttons. */
.table tbody tr:hover td.table__actions-col { background: #f8fafc; }
.table tr.is-unread td.table__actions-col { background: #f8fbff; }
.table tr.is-unread:hover td.table__actions-col { background: #eff6ff; }

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; }
}
