/* =========================================================================
   ROMOTANA — admin stylesheet
   Loaded after site.css: the tokens, buttons, forms, tables and alerts all
   come from there, and this file adds the application shell around them.
   ========================================================================= */

/* The admin shell's navy ramp.
 *
 * These four tokens were used throughout this file from the day it was written
 * and defined nowhere, so every var() referencing them resolved to nothing:
 * the sidebar had no background, the sign-in card had no gradient, and the
 * current page in the navigation was white text on white. Found on
 * 4 September 2026 while screenshotting the new Page content screen, whose
 * nav item was invisible for exactly this reason.
 *
 * Derived from site.css's --blue-deep (#072a63) so the admin reads as the same
 * publication as the public site rather than as a second product.
 */
:root {
  --navy-900: #061f4a;
  --navy-800: #072a63;   /* = --blue-deep, the public site's darkest blue */
  --navy-700: #0b3a8f;   /* = --blue */
  --navy-600: #1b4ea8;

  /* Same family of bug as --shadow-1 above: admin.css uses var(--muted) and
     var(--line) in twelve places — muted captions, panel borders, table rules
     — and neither was ever defined, here or in site.css, so all twelve
     resolved to nothing. Aliased to the real site tokens rather than renamed
     at each use, so the two vocabularies stay in step.
     Found and corrected 4 September 2026. */
  --muted: var(--ink-3);
  --line:  var(--rule);

  /* Four more of the same, found on 4 September by the design-token check in
     smoke-test.php rather than by eye — which is the point of writing it. Each
     is named by admin templates that predate the Spread rewrite: soft panel
     grounds, the small radius on a thumbnail, the hairline between rows of a
     mini list, and the gold rule on the "here is the password" panel. All four
     resolved to nothing, so those surfaces were flat white and square.
     Aliased, not renamed at each use, so the two vocabularies stay in step. */
  --bg-soft:   var(--paper-2);
  --line-soft: var(--rule);
  --radius-sm: var(--radius);
  --gold-500:  var(--yellow);
}

body.admin {
  background: var(--bg-soft);
  font-size: 1rem;
}

/* --------------------------------------------------------------- shell --- */
.admin-shell {
  display: grid;
  grid-template-columns: 16rem minmax(0, 1fr);
  min-height: 100vh;
}

.admin-side {
  background: var(--navy-900);
  color: #b9c7de;
  padding: 1.5rem 1rem;
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
  position: sticky;
  top: 0;
  height: 100vh;
  overflow-y: auto;
}
.admin-side__brand {
  display: flex;
  align-items: center;
  gap: .7rem;
  color: #fff;
  text-decoration: none;
  padding-inline: .5rem;
}
.admin-side__brand img { height: 2.25rem; }
.admin-side__brand strong { font-size: .95rem; letter-spacing: .08em; text-transform: uppercase; }
.admin-side__brand span { display: block; font-size: .7rem; color: #8ea1c0; letter-spacing: .04em; }

.admin-nav { display: grid; gap: .15rem; }
.admin-nav__label {
  font-size: .68rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: #6d80a3;
  padding: 1rem .75rem .35rem;
}
.admin-nav a {
  display: flex;
  align-items: center;
  gap: .65rem;
  padding: .6rem .75rem;
  border-radius: var(--radius-sm);
  color: #cbd7ea;
  text-decoration: none;
  font-size: .94rem;
  font-weight: 550;
}
.admin-nav a:hover { background: rgba(255, 255, 255, .07); color: #fff; }
.admin-nav a[aria-current="page"] { background: var(--navy-700); color: #fff; }
.admin-nav svg { width: 1.05rem; height: 1.05rem; fill: currentColor; opacity: .85; flex: 0 0 auto; }
.admin-nav__count {
  margin-left: auto;
  background: var(--red-600);
  color: #fff;
  border-radius: 999px;
  font-size: .72rem;
  font-weight: 700;
  padding: .1rem .45rem;
}

.admin-side__foot { margin-top: auto; font-size: .8rem; color: #8ea1c0; padding: .75rem; }
.admin-side__foot a { color: #cbd7ea; }

.admin-main { display: flex; flex-direction: column; min-width: 0; }

.admin-top {
  background: #fff;
  border-bottom: 1px solid var(--line);
  padding: 1rem clamp(1.25rem, 3vw, 2.25rem);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  position: sticky;
  top: 0;
  z-index: 20;
}
.admin-top h1 { font-size: 1.35rem; margin: 0; }
.admin-top__meta { font-size: .85rem; color: var(--muted); margin-top: .15rem; }
.admin-top__actions { display: flex; align-items: center; gap: .75rem; flex-wrap: wrap; }

.admin-body { padding: clamp(1.25rem, 3vw, 2.25rem); display: grid; gap: 1.5rem; align-content: start; }

.admin-menu-toggle { display: none; }

/* ------------------------------------------------------------- widgets --- */
.kpi-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr)); gap: 1rem; }
/* The admin stays utilitarian, but it uses the same three shading steps as the
   public site so the two halves read as one product. See design-spread.md §3a. */
.kpi {
  background: #fff;
  box-shadow: var(--shade-1);
  border: 1px solid var(--line);
  border-left: 4px solid var(--navy-700);
  border-radius: var(--radius);
  padding: 1.1rem 1.25rem;
  text-decoration: none;
  display: block;
  color: inherit;
}
.kpi:hover { box-shadow: var(--shade-2); color: inherit; }
.kpi--gold { border-left-color: var(--gold-500); }
.kpi--red  { border-left-color: var(--red-500); }
.kpi--green { border-left-color: #2e9e63; }
.kpi__value { font-size: 1.9rem; font-weight: 800; color: var(--ink); line-height: 1.1; }
.kpi__label { font-size: .85rem; color: var(--muted); margin-top: .2rem; }

.panel {
  background: #fff;
  box-shadow: var(--shade-1);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
}
.panel__head {
  padding: 1rem 1.25rem;
  border-bottom: 1px solid var(--line);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
}
.panel__head h2 { font-size: 1.05rem; margin: 0; }
.panel__body { padding: 1.25rem; }
.panel__body--flush { padding: 0; }
.panel__foot {
  padding: .85rem 1.25rem;
  border-top: 1px solid var(--line);
  background: var(--bg-soft);
  font-size: .9rem;
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  align-items: center;
}

.toolbar {
  display: flex;
  gap: .75rem;
  flex-wrap: wrap;
  align-items: center;
}
.toolbar form { display: flex; gap: .5rem; flex-wrap: wrap; align-items: center; }
.toolbar input[type="search"], .toolbar select { min-width: 12rem; }

.filter-tabs { display: flex; gap: .3rem; flex-wrap: wrap; }
.filter-tabs a {
  padding: .4rem .8rem;
  border-radius: 999px;
  font-size: .88rem;
  font-weight: 600;
  text-decoration: none;
  color: var(--body);
  background: var(--bg-soft);
  border: 1px solid var(--line);
}
.filter-tabs a:hover { border-color: var(--navy-600); }
.filter-tabs a[aria-current="true"] { background: var(--navy-800); border-color: var(--navy-800); color: #fff; }

.status {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  padding: .18rem .55rem;
  border-radius: 999px;
  font-size: .75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .04em;
  white-space: nowrap;
}
.status--new, .status--pending   { background: var(--warn-bg); color: var(--warn-fg); }
.status--approved, .status--active, .status--published, .status--closed { background: var(--ok-bg); color: var(--ok-fg); }
.status--draft, .status--lapsed, .status--in_progress { background: var(--bg-soft); color: var(--muted); }
.status--declined, .status--spam, .status--cancelled { background: var(--err-bg); color: var(--err-fg); }
/* The ELD sync log writes `status--ok` and `status--danger`, and neither
   existed — so a run that FAILED wore the same neutral pill as one that
   loaded, on the one screen whose job is to say whether the register copied
   cleanly. Matched to the same green and red as every other state here. */
.status--ok     { background: var(--ok-bg);  color: var(--ok-fg); }
.status--danger { background: var(--err-bg); color: var(--err-fg); }
.status--registered { background: var(--info-bg); color: var(--info-fg); }
.status--attended   { background: var(--ok-bg);   color: var(--ok-fg); }


.detail-list { display: grid; gap: .1rem; margin: 0; }
.detail-list div {
  display: grid;
  grid-template-columns: 11rem minmax(0, 1fr);
  gap: 1rem;
  padding: .6rem 0;
  border-bottom: 1px solid var(--line-soft);
}
.detail-list dt { color: var(--muted); font-size: .9rem; }
.detail-list dd { margin: 0; color: var(--ink); overflow-wrap: anywhere; }

.form-actions {
  display: flex;
  gap: .75rem;
  flex-wrap: wrap;
  align-items: center;
  padding-top: .5rem;
}
.form-actions--split { justify-content: space-between; }

.empty-state {
  text-align: center;
  padding: clamp(2rem, 5vw, 3.5rem) 1.5rem;
  color: var(--muted);
}
.empty-state h3 { color: var(--ink); }

.login-page {
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 2rem 1.25rem;
  background:
    radial-gradient(60rem 30rem at 80% -10%, rgba(242, 193, 28, .12), transparent 60%),
    linear-gradient(160deg, var(--navy-900), var(--navy-700));
}
.login-card {
  width: 100%;
  max-width: 25rem;
  background: #fff;
  border-radius: var(--radius-lg);
  /* --shadow-1 and --shadow-3 were referenced here and on .kpi:hover but were
     never defined anywhere — leftovers from the stylesheet this replaced, so
     both shadows had silently been doing nothing. Now they use the real
     tokens. Corrected 4 September 2026. */
  box-shadow: var(--shade-2);
  padding: clamp(1.75rem, 4vw, 2.5rem);
}
/* The mark is the way back to the public site: these two screens are the only
   ones with no navigation at all, so without it a signed-out visitor who does
   not want to sign in has nowhere to go but the browser's back button. */
.login-card__brand {
  display: block;
  text-align: center;
  margin-bottom: 1.5rem;
  text-decoration: none;
  color: inherit;
  border-radius: var(--radius);
}
.login-card__brand:hover strong { color: var(--navy-600); }
.login-card__brand:focus-visible { outline: 2px solid var(--navy-700); outline-offset: 4px; }
.login-card__brand img { height: 3.5rem; margin: 0 auto .75rem; }
.login-card__brand strong { display: block; letter-spacing: .1em; text-transform: uppercase; color: var(--navy-800); }
.login-card__brand span { font-size: .85rem; color: var(--muted); }

/* The forced first-sign-in password change reuses this card as a dialog:
   nothing of the administration area is rendered behind it. */
.login-card--dialog { box-shadow: var(--shade-3); }
.login-card__title { font-size: 1.25rem; margin: 0 0 .75rem; text-align: center; }
.login-card__lede { margin: 0 0 1.5rem; color: var(--muted); font-size: .92rem; }
.login-card__aside {
  margin-top: 1.5rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--line);
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  flex-wrap: wrap;
  gap: .5rem 1rem;
  font-size: .85rem;
  color: var(--muted);
}
.linkish {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  color: var(--navy-700);
  text-decoration: underline;
  cursor: pointer;
}

/* ---------------------------------------------------------------- data --- */
/* Every admin list — news, members, inquiries, events, partners, team, users,
   activity, newsletter, registrations, partner categories — writes
   `<table class="data">`, and until today `.data` matched nothing at all.
   Eleven screens were rendering as bare browser tables: `th` centred and bold
   because that is the user-agent default, no padding, no rules, columns sized
   by whatever the longest string happened to be. The news list looked the
   worst only because it has the most to say per row.

   The shape follows `.table` in site.css so the admin reads as the same
   publication as the public site: a firm rule under the head, hairlines
   between rows, small caps for the column names. */
.table-wrap { overflow-x: auto; max-width: 100%; }

.data {
  width: 100%;
  border-collapse: collapse;
  font-family: var(--sans);
  font-size: var(--step--1);
}

.data th {
  text-align: left;
  font-weight: 700;
  color: var(--muted);
  font-size: var(--step--2);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
  padding: 0.55rem 0.9rem 0.55rem 0;
  border-bottom: 2px solid var(--ink);
}

.data td {
  padding: 0.7rem 0.9rem 0.7rem 0;
  border-bottom: 1px solid var(--line, var(--rule));
  /* middle, not baseline: a cell holding a title above a muted meta line sits
     ragged against a single-line cell beside it when baselines are aligned. */
  vertical-align: middle;
  color: var(--ink);
}

/* The row header carries the record's name. It is the thing being scanned, so
   it is left-aligned and normal weight — the browser's centred bold is what
   made these tables look like spreadsheets. */
.data tbody th {
  text-align: left;
  font-weight: 600;
  color: var(--ink);
  border-bottom: 1px solid var(--line, var(--rule));
  padding: 0.7rem 0.9rem 0.7rem 0;
  text-transform: none;
  letter-spacing: 0;
  font-size: var(--step--1);
  white-space: normal;
  vertical-align: middle;
}

.data tbody tr:hover { background: var(--bg-soft); }
.data tbody tr:last-child th,
.data tbody tr:last-child td { border-bottom: 2px solid var(--ink); }

/* Dates and counts read as columns of figures, so they get tabular numerals
   and never wrap mid-date. */
.data .num,
.data .when { white-space: nowrap; font-variant-numeric: tabular-nums; }

/* Actions sit at the right edge, on one line, and stay put. */
.data .row-actions {
  text-align: right;
  white-space: nowrap;
  width: 1%;
  padding-right: 0;
}
.data .row-actions form { display: inline; }
.data .row-actions > *, .data .row-actions form > * { margin-left: 0.3rem; }

.data th:last-child, .data td:last-child { padding-right: 0; }

/* The news row: a mark, a title, and one muted line that qualifies it. The
   mark is the category illustration the article already carries, at the size
   of a bullet — it gives the eye something to run down the left edge, and it
   is real information rather than an ornament. */
.row-title { display: flex; align-items: flex-start; gap: 0.7rem; }
.row-title__mark {
  flex: 0 0 auto;
  width: 2rem; height: 2rem;
  object-fit: contain;
  background: var(--bg-soft);
  border: 1px solid var(--line, var(--rule));
  border-radius: var(--radius);
  padding: 0.1rem;
  margin-top: 0.05rem;
}
.row-title__text { min-width: 0; }
.row-title__text > a {
  font-weight: 600;
  color: var(--ink);
  text-decoration: none;
  /* The whole row is a list of links; underlining every title turns the column
     into a thicket. The underline arrives on hover, where it means something. */
}
.row-title__text > a:hover,
.row-title__text > a:focus-visible { text-decoration: underline; }
.row-title__meta {
  margin: 0.15rem 0 0;
  font-size: var(--step--2);
  color: var(--muted);
  font-weight: 400;
}
.row-title__meta a { color: inherit; }

/* Said once, above the table, instead of on every row. */
.panel__note {
  margin: 0;
  padding: 0.85rem clamp(1rem, 2.5vw, 1.5rem);
  border-bottom: 1px solid var(--line, var(--rule));
  background: var(--info-bg);
  color: var(--info-fg);
  font-size: var(--step--2);
}

/* A draft close to being swept. Red, because it is the only thing on the
   screen that will happen without somebody deciding it. */
.row-flag {
  display: block;
  font-size: var(--step--2);
  color: var(--red);
  font-weight: 600;
}

/* A caption over a thing rather than under it — "Current image", "Current
   photograph", "Listing" — used in four admin forms and styled in none, so it
   arrived as ordinary body text next to the thumbnail it was labelling.
   `.field__hint` is its sibling and sits below; this one sits above and carries
   the weight of a label. */
.field__label {
  display: block;
  font-size: var(--step--2);
  font-weight: 700;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin-bottom: 0.3rem;
}

/* "You", beside your own row in the admin users list. The badge base gives it
   a shape and nothing else, so it read as plain text in a list where every
   other cell is plain text — which is the one place it needed to stand out. */
.badge--navy { background: var(--blue-deep); color: #fff; }

/* ---------------------------------------------------------- responsive --- */
@media (max-width: 900px) {
  .admin-shell { grid-template-columns: 1fr; }
  .admin-side {
    position: static;
    height: auto;
    display: none;
  }
  .admin-side.is-open { display: flex; }
  .admin-menu-toggle { display: inline-flex; }
  .detail-list div { grid-template-columns: 1fr; gap: .15rem; }
}

/* Below 44rem an admin list stops being a table and becomes a list of records.
   Scrolling a 330px box sideways is what it did before, and it is a poor answer
   for the same reason the public register's is: by the time you have dragged
   across to the status you have lost the row you were reading. The same
   decision, and the same 44rem, as `.table--stack` on the public side.

   admin.js copies each column heading onto its cells as data-label, and the
   labels are printed here — so a date says which date it is. Without that
   script the tables scroll as they always did. */
@media (max-width: 44rem) {
  .data, .data tbody, .data tr, .data th, .data td { display: block; width: 100%; }

  /* Gone from the screen, kept in the accessibility tree: the headings are
     still the labels for cells that no longer sit beneath them. */
  .data thead {
    position: absolute; width: 1px; height: 1px; overflow: hidden;
    clip-path: inset(50%); white-space: nowrap;
  }

  /* A card per record.
     
     The public register argues the other way — "the rules are what make it a
     register rather than a list of cards" — and it is right about a document
     somebody reads. This is not that. Here each record carries five labelled
     fields and up to three buttons, and a hairline is too quiet a boundary
     between one set of those and the next: on a phone the eye loses which
     Delete belongs to which headline. A card is the boundary.
     
     Kept cheap: one hairline border, the panel's own radius, no shadow. The
     table already sits inside a panel, and a shadow on every row inside a
     shadowed box is the sort of thing that makes an interface feel padded.
     
     A column, so the record's name leads whatever column it occupies. On the
     partner list the logo is the first cell and the name the second, and
     stacked in source order every partner opened with "LOGO" and a picture
     before it said whose it was. */
  .data tbody tr {
    display: flex;
    flex-direction: column;
    padding: 0.85rem 0.9rem;
    margin: 0 0 0.7rem;
    background: var(--white, #fff);
    border: 1px solid var(--line, var(--rule));
    border-radius: var(--radius);
    border-left: 3px solid var(--ink);
  }
  .data tbody th[scope="row"] { order: -1; }
  .data .row-actions { order: 99; }

  /* A group heading — the partner list's category rows — is not a record and
     should not look like one. Matched by class rather than :has(), which is
     well supported now but not universally, and a heading rendered as a card
     is a worse failure than the class costing one attribute. */
  .data tbody tr.data__group {
    background: none;
    border: 0;
    border-radius: 0;
    padding: 1.1rem 0 0.35rem;
    margin: 0;
  }
  .data tbody tr:last-child { margin-bottom: 0; }
  .data tbody tr:hover { background: var(--white, #fff); }   /* no hover target on a phone */

  /* The record's name leads, at the size it deserves. */
  .data tbody th[scope="row"] {
    border: 0;
    padding: 0 0 0.4rem;
    font-size: var(--step-0);
  }

  .data tbody td {
    border: 0;
    padding: 0.15rem 0;
    display: flex;
    gap: 0.6rem;
    align-items: baseline;
    justify-content: space-between;
  }
  .data tbody td:empty { display: none; }

  .data tbody td[data-label]::before {
    content: attr(data-label);
    flex: 0 0 auto;
    color: var(--muted);
    font-size: var(--step--2);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    font-weight: 700;
  }

  /* Actions get the full width and sit together at the end of the record,
     which is where somebody reaching for them expects them. */
  .data .row-actions {
    width: 100%;
    text-align: left;
    padding-top: 0.6rem;
    white-space: normal;
  }
  .data .row-actions > *, .data .row-actions form > * { margin: 0.3rem 0.3rem 0 0; }

  /* The news list's mark and title share a line as they do on a desktop. */
  .row-title { align-items: flex-start; }
}

@media (max-width: 640px) {
  .admin-top { flex-direction: column; align-items: flex-start; gap: .75rem; }
  .toolbar input[type="search"], .toolbar select { min-width: 0; width: 100%; }
}
