/* ============================================================
   ENGENE Voting Calendar — admin pages
   Extends style.css + form.css. Denser than the public list:
   one line per event, edit reachable in a single click, and a
   drawer that holds every field without leaving the page.
   ============================================================ */

.admin-tag {
  font-family: var(--font-display);
  font-variation-settings: 'wdth' 85, 'wght' 800;
  font-size: 0.625rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--color-primary);
  border: 1px solid color-mix(in srgb, var(--color-primary) 45%, transparent);
  background: var(--color-primary-highlight);
  border-radius: var(--radius-sm);
  padding: 0.1875rem 0.375rem 0.125rem;
  margin-left: var(--space-1);
}

/* ---------- Alert button ---------- */

.alert-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 0.375rem var(--space-3) 0.375rem 0.625rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-full);
  background: var(--color-surface);
  color: var(--color-text-muted);
  text-decoration: none;
  transition:
    color var(--transition-interactive),
    border-color var(--transition-interactive),
    background var(--transition-interactive);
}
.alert-btn:hover {
  color: var(--color-text);
  border-color: var(--color-text-faint);
}
.alert-btn.is-current {
  color: var(--color-text);
  border-color: var(--color-text-faint);
}
.alert-label {
  font-family: var(--font-display);
  font-variation-settings: 'wdth' 92, 'wght' 700;
  font-size: 0.6875rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
.alert-count {
  min-width: 1.375rem;
  height: 1.375rem;
  padding: 0 0.3125rem;
  display: inline-grid;
  place-items: center;
  border-radius: var(--radius-full);
  font-family: var(--font-display);
  font-variation-settings: 'wdth' 85, 'wght' 800;
  font-size: 0.6875rem;
  font-variant-numeric: tabular-nums;
  background: var(--color-surface-2);
  color: var(--color-text-faint);
}
.alert-count[data-tone='waiting'] {
  background: var(--color-primary);
  color: #fff;
}
/* One soft pulse on arrival, then it stops asking for attention. */
.alert-btn:has(.alert-count[data-tone='waiting']) {
  border-color: color-mix(in srgb, var(--color-primary) 55%, transparent);
  background: var(--color-primary-highlight);
  color: var(--color-text);
}

@media (max-width: 720px) {
  .alert-label {
    display: none;
  }
}

/* ---------- Intro + mode bar ---------- */

.intro--admin {
  padding-bottom: var(--space-6);
}

.mode-bar {
  margin-top: var(--space-5);
  border: 1px solid var(--color-border);
  border-left: 3px solid var(--color-prep);
  border-radius: var(--radius-md);
  background: var(--color-surface);
  padding: var(--space-4) var(--space-5);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
  max-width: 78ch;
}
.mode-bar b {
  color: var(--color-text);
  font-weight: 700;
}
.mode-bar[data-tone='live'] {
  border-left-color: var(--color-live);
}
.mode-bar[data-tone='bad'] {
  border-left-color: var(--color-primary);
}
.mode-bar a {
  color: var(--color-text);
}

/* ---------- Toolbar ---------- */

.admin-bar {
  margin-top: var(--space-6);
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--space-3);
}
.admin-bar .field-label {
  margin: 0;
}
.admin-bar .btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  cursor: pointer;
  white-space: nowrap;
}

/* Sits directly under the search row, so it needs less air above it than the
   search row has — the two read as one control block. */
.admin-filter {
  margin-top: var(--space-4);
}

@media (max-width: 640px) {
  .admin-bar {
    grid-template-columns: 1fr;
  }
  .admin-bar .btn {
    justify-content: center;
  }
}

/* ---------- List ---------- */

.admin-wrap {
  padding-bottom: var(--space-24);
}
.admin-count {
  font-family: var(--font-display);
  font-variation-settings: 'wdth' 92, 'wght' 700;
  font-size: 0.6875rem;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  color: var(--color-text-faint);
  margin: 0 0 var(--space-3);
}
.admin-list,
.review-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.admin-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--space-4);
  border: 1px solid var(--color-border);
  border-left: 3px solid var(--focus-hue, var(--color-border));
  border-radius: var(--radius-md);
  background: var(--color-surface);
  padding: var(--space-4) var(--space-4) var(--space-4) var(--space-5);
  transition: border-color var(--transition-interactive);
}
.admin-row:hover {
  border-color: var(--color-text-faint);
  border-left-color: var(--focus-hue, var(--color-text-faint));
}
.admin-row-main {
  min-width: 0;
}
.admin-row-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin-bottom: var(--space-2);
}
.admin-row-name {
  font-family: var(--font-display);
  font-variation-settings: 'wdth' 100, 'wght' 700;
  font-size: var(--text-base);
  margin: 0 0 var(--space-1);
  line-height: 1.2;
}
.admin-row-times {
  font-size: var(--text-xs);
  color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
  margin: 0;
}
.admin-row-actions {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}
.row-btn {
  width: 36px;
  height: 36px;
  display: grid;
  place-items: center;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface-2);
  color: var(--color-text-muted);
  cursor: pointer;
  transition:
    color var(--transition-interactive),
    border-color var(--transition-interactive),
    background var(--transition-interactive);
}
.row-btn:hover {
  color: var(--color-text);
  border-color: var(--color-text-faint);
  background: var(--color-surface);
}
.row-btn[data-on='true'] {
  color: var(--color-primary);
  border-color: color-mix(in srgb, var(--color-primary) 45%, transparent);
  background: var(--color-primary-highlight);
}
.admin-empty {
  font-size: var(--text-sm);
  color: var(--color-text-muted);
  padding: var(--space-8) 0;
}

@media (max-width: 640px) {
  .admin-row {
    grid-template-columns: 1fr;
    gap: var(--space-3);
  }
  .admin-row-actions {
    justify-content: flex-end;
  }
}

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

.review-card {
  border: 1px solid var(--color-border);
  border-left: 3px solid var(--focus-hue, var(--color-prep));
  border-radius: var(--radius-lg);
  background: var(--color-surface);
  padding: var(--space-5);
}
.review-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
}
.review-name {
  font-family: var(--font-display);
  font-variation-settings: 'wdth' 100, 'wght' 700;
  font-size: var(--text-lg);
  margin: var(--space-2) 0;
  line-height: 1.2;
}
.review-when {
  font-size: var(--text-xs);
  color: var(--color-text-faint);
  font-variant-numeric: tabular-nums;
}
.review-times {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-6);
  font-size: var(--text-xs);
  color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
  margin-bottom: var(--space-4);
}
.review-times b {
  display: block;
  font-size: var(--text-sm);
  color: var(--color-text);
  font-weight: 500;
}
.review-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--space-4);
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-border);
}
.review-item .detail-key {
  display: block;
  font-family: var(--font-display);
  font-variation-settings: 'wdth' 92, 'wght' 700;
  font-size: 0.625rem;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  color: var(--color-text-faint);
  margin-bottom: var(--space-1);
}
.review-item p {
  font-size: var(--text-sm);
  color: var(--color-text-muted);
  margin: 0;
  line-height: 1.55;
  white-space: pre-line;
}
.review-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  margin-top: var(--space-5);
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-border);
}
.review-actions .btn {
  cursor: pointer;
}
.review-contact {
  font-size: var(--text-xs);
  color: var(--color-text-faint);
  margin-left: auto;
}
.review-empty {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
  padding: var(--space-12) var(--space-6);
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-4);
}

/* ---------- Drawer ---------- */

.drawer-veil {
  position: fixed;
  inset: 0;
  /* Follows the visible area for the same reason the panel does, so no lit
     strip of the list shows above the dimmed layer while the keyboard is up. */
  top: var(--drawer-top, 0px);
  background: rgba(8, 8, 11, 0.55);
  backdrop-filter: blur(2px);
  z-index: 40;
  animation: veil-in 160ms ease-out;
}
@keyframes veil-in {
  from {
    opacity: 0;
  }
}

.drawer {
  position: fixed;
  /* Not a flat 0. `fixed` anchors to the layout viewport, which on iOS is not
     the same rectangle as the part of the screen you can see — the keyboard
     pans the visible area and leaves the layout viewport behind, dragging the
     panel's top edge off screen. admin.js keeps `--drawer-top` equal to
     visualViewport.offsetTop so the panel stays glued to the visible area. */
  top: var(--drawer-top, 0px);
  right: 0;
  /* `svh`, not `dvh`. dvh re-resolves every time mobile Safari's toolbar
     collapses or returns, which happens continuously while a finger drags: the
     panel changed height mid-scroll, every field under the thumb moved with it,
     and the whole drawer appeared to jump. svh is the SMALL viewport — the one
     with the toolbar showing — so it never changes while scrolling. The
     keyboard is the one case where the panel genuinely has to shrink, and
     admin.js sets `--drawer-h` from visualViewport for exactly that. */
  height: var(--drawer-h, 100svh);
  max-height: var(--drawer-h, 100svh);
  width: min(620px, 100vw);
  max-width: 100vw;
  z-index: 50;
  background: var(--color-bg);
  border-left: 1px solid var(--color-border);
  box-shadow: -24px 0 60px rgba(0, 0, 0, 0.28);
  display: flex;
  flex-direction: column;
  animation: drawer-in 220ms cubic-bezier(0.2, 0.7, 0.3, 1);
}
@keyframes drawer-in {
  from {
    transform: translateX(24px);
    opacity: 0;
  }
}
@media (prefers-reduced-motion: reduce) {
  .drawer,
  .drawer-veil {
    animation: none;
  }
}

.drawer-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-5) var(--space-6);
  border-bottom: 1px solid var(--color-border);
}
.drawer-kicker {
  font-family: var(--font-display);
  font-variation-settings: 'wdth' 92, 'wght' 700;
  font-size: 0.625rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--color-primary);
  margin: 0 0 var(--space-1);
}
.drawer-title {
  font-family: var(--font-display);
  font-variation-settings: 'wdth' 100, 'wght' 800;
  font-size: var(--text-lg);
  margin: 0;
  line-height: 1.15;
}
.drawer-body {
  flex: 1 1 auto;
  overflow-y: auto;
  /* Keep a flick at the end of the panel from handing the scroll to the list
     behind it, which is what made the drawer feel like it jumped. */
  overscroll-behavior: contain;
  /* Scroll anchoring works against us here: the long fields grow as they are
     typed into, the browser notices the content above the viewport got taller
     and "helpfully" shifts the scroll position to compensate, which reads as a
     jump under the thumb. The panel should stay exactly where it was put.

     (`-webkit-overflow-scrolling: touch` used to be on this rule. It is a
     legacy iOS property that puts the scroller on its own compositing layer,
     and inside a fixed panel it is a known source of stuttering and snap-backs.
     iOS has scrolled overflow containers natively for years.) */
  overflow-anchor: none;
  padding: var(--space-6);
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  /* The browser scrolls a focused field into view inside this scroller. Without
     the bottom reserve it stops with the field directly under the footer, so
     the moderator had to scroll again to see what they were typing. */
  scroll-padding-block: var(--space-4) 6rem;
}
/* admin.js grows these to fit their text, so they never become a second
   scroller inside the panel: a drag that began on a textarea used to scroll the
   textarea's own overflow rather than the drawer, which is the other half of
   what felt like jumping. Nothing here is lost — the field just gets taller. */
.drawer-body .field-textarea {
  overflow-y: hidden;
  resize: none;
}
/* The scope note inherits its own top margin from form.css, which the drawer's
   flex gap already provides. */
.form-notice--drawer {
  margin-top: 0;
  max-width: none;
}
.drawer-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  flex-wrap: wrap;
  padding: var(--space-4) var(--space-6);
  border-top: 1px solid var(--color-border);
  background: var(--color-surface);
}
.drawer-foot-main {
  display: flex;
  gap: var(--space-3);
  margin-left: auto;
}
.drawer-foot .btn {
  cursor: pointer;
}
.drawer-delete {
  color: var(--color-primary);
}
.drawer-delete[data-armed='true'] {
  background: var(--color-primary);
  color: #fff;
  border-color: var(--color-primary);
}

/* ---------- The drawer stops being a drawer on a phone ----------

   Everything above describes a panel fixed to the viewport with its own
   scrolling body, over a page whose scroll is locked. On a wide screen that is
   the right shape: the form slides in beside the list and the list stays
   readable behind it. On a phone it is the wrong shape and it fought iOS every
   way it was patched — a fixed box is positioned against the layout viewport,
   the keyboard pans the visible area instead, and no amount of compensation
   code makes the two agree.

   So below 640px the panel stops being fixed. It becomes an ordinary block in
   document flow, the document does the scrolling, nothing is locked, and there
   is no inner scroller. That is exactly how the public submit form is built,
   and that form has never had any of these problems on a phone. The head and
   foot stay put with `sticky`, which behaves in normal flow the way `fixed`
   refuses to.                                                              */

@media (max-width: 640px) {
  /* No overlay, so nothing to dim. */
  .drawer-veil {
    display: none;
  }

  .drawer {
    position: static;
    /* Undo every viewport-relative measurement, including the --drawer-top /
       --drawer-h variables admin.js sets for the keyboard: in page flow the
       form is as tall as its content and the browser handles the rest. */
    top: auto;
    height: auto;
    max-height: none;
    width: 100%;
    max-width: none;
    border-left: 0;
    box-shadow: none;
    /* The slide-in read as a panel arriving from the side. Here it is a page. */
    animation: none;
  }

  /* Deliberately NOT sticky. The masthead is already sticky at top: 0 with a
     higher stacking order, so a sticky head only slid underneath it and left
     the title half-hidden. It scrolls away instead, exactly like the heading on
     the public submit form — and the way out of the form is Cancel in the foot
     below, which does stay put. */
  .drawer-head {
    position: static;
  }

  .drawer-body {
    /* The document scrolls now, not this element. */
    overflow: visible;
    padding: var(--space-5);
    /* The foot floats over the end of the form while scrolling, so the last
       field needs room to clear it. */
    padding-bottom: 6rem;
  }

  .drawer-foot {
    position: sticky;
    bottom: 0;
    z-index: 2;
  }

  /* While the form is open it IS the page, so the list underneath goes away
     rather than sitting below the form as a second screenful of content. The
     masthead stays: it is how the moderator knows where they are. */
  html.drawer-page-open main {
    display: none;
  }
}

/* ---------- Toast ---------- */

/* `.toast` now lives in style.css, which every page loads, because the homepage
   uses it too for share confirmations. */

.review-empty[data-state='offline'] .done-mark {
  background: var(--color-surface-2);
  color: var(--color-text-faint);
}
.review-empty[data-state='offline'] .done-mark svg {
  display: none;
}
.review-empty[data-state='offline'] .done-mark::after {
  content: '…';
  font-size: 1.25rem;
  line-height: 1;
  transform: translateY(-0.25em);
}

/* Narrow masthead: the page itself says Admin, so the chip can go. */
@media (max-width: 620px) {
  .admin-tag {
    display: none;
  }
  .masthead-inner {
    gap: var(--space-3);
  }
  .alert-btn {
    padding-left: 0.5rem;
    padding-right: 0.5rem;
  }
}

/* ---------- Moderator sign-in ----------

   While data-auth="locked" the working controls are not merely faded, they are
   removed from the page, so a locked page cannot be poked at with a stray
   click. The real guard is server-side in Code.gs; this just keeps the page
   honest about what it can do.                                             */

body[data-auth='locked'] .admin-bar,
body[data-auth='locked'] .admin-filter,
body[data-auth='locked'] .admin-wrap {
  display: none;
}

.signin-gate {
  padding-top: var(--space-8);
  padding-bottom: var(--space-16);
}

.signin-card {
  max-width: 34rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-xl);
  background: var(--color-surface);
  box-shadow: var(--shadow-md);
  padding: var(--space-10);
}

.signin-lock {
  color: var(--color-primary);
}

.signin-title {
  margin: var(--space-4) 0 0;
  font-family: var(--font-display);
  font-size: var(--text-lg);
  font-weight: 800;
  letter-spacing: -0.01em;
  color: var(--color-text);
}

.signin-copy {
  margin: var(--space-3) 0 0;
  font-size: var(--text-sm);
  line-height: 1.55;
  color: var(--color-text-muted);
  max-width: 46ch;
}

/* The Google sign-in button.

   This used to be an empty div that Google Identity Services filled with its own
   rendered button. GIS is gone — its popup arrived blank — so this is our own
   control, driving the redirect flow. It carries .btn in the markup so it still
   looks like a button if this stylesheet is served stale from the edge while the
   HTML is fresh; that mismatch once turned a control into unstyled text that
   read like a sentence and was missed entirely. */
.btn-google {
  margin-top: var(--space-6);
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-6);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-full);
  background: var(--color-text);
  color: var(--color-surface);
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-weight: 600;
  letter-spacing: 0.01em;
  cursor: pointer;
  transition:
    transform 0.16s ease,
    opacity 0.16s ease;
}

.btn-google:hover {
  transform: translateY(-1px);
}

.btn-google:active {
  transform: translateY(0);
}

.btn-google:disabled {
  cursor: default;
  opacity: 0.7;
  transform: none;
}

/* The G keeps its own four brand colours, so it needs a light disc behind it to
   stay legible on the dark button face. */
.btn-google .g-mark {
  flex: none;
  background: #fff;
  border-radius: var(--radius-full);
  padding: 2px;
  box-sizing: content-box;
}

.btn-google[data-busy='1'] span::after {
  content: '…';
}

.signin-note {
  margin: var(--space-5) 0 0;
  border-left: 3px solid var(--color-prep);
  padding: var(--space-1) 0 var(--space-1) var(--space-4);
  font-size: var(--text-xs);
  line-height: 1.5;
  color: var(--color-text-muted);
}
.signin-note[data-tone='bad'] {
  border-left-color: var(--color-primary);
  color: var(--color-text);
}

/* ---------- Who is signed in ---------- */

.signin-who {
  margin-top: var(--space-5);
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
  font-size: var(--text-xs);
  color: var(--color-text-muted);
}
.signin-who b {
  color: var(--color-text);
  font-weight: 600;
}
.who-dot {
  width: 7px;
  height: 7px;
  border-radius: var(--radius-full);
  background: var(--color-live);
  flex: none;
}
.who-out {
  padding: var(--space-1) var(--space-3);
  font-size: var(--text-xs);
  cursor: pointer;
}

/* .btn sets a display value, which would otherwise defeat the hidden attribute. */
.btn-google[hidden] {
  display: none;
}

/* ---------- Tab strip (moderator page) ---------- */

/* Two panels behind one sign-in. The strip reads as a row of labels with the
   active one underlined, rather than as buttons: it switches a view, it does
   not perform an action. */
.tab-strip {
  margin-top: var(--space-6);
  display: flex;
  gap: var(--space-5);
  border-bottom: 1px solid var(--color-border);
}
.tab {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0 0 var(--space-3);
  margin-bottom: -1px;
  border: 0;
  background: none;
  cursor: pointer;
  font-family: var(--font-display);
  font-variation-settings: 'wdth' 92, 'wght' 700;
  font-size: 0.8125rem;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  line-height: 1;
  color: var(--color-text-muted);
  border-bottom: 2px solid transparent;
}
.tab:hover {
  color: var(--color-text);
}
.tab[aria-selected='true'] {
  color: var(--color-text);
  border-bottom-color: var(--color-primary);
}
/* The count only appears when something is waiting, so it never sits there as
   a permanent zero. */
.tab-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.125rem;
  height: 1.125rem;
  padding: 0 0.25rem;
  border-radius: var(--radius-full);
  background: var(--color-primary);
  color: #fff;
  font-size: 0.625rem;
  font-variation-settings: 'wdth' 92, 'wght' 800;
}

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

/* Same card as a waiting submission, minus the times: a report is one message
   about one event. Handled reports fade back so the open ones lead the eye. */
.correction-card[data-state='resolved'],
.correction-card[data-state='dismissed'] {
  opacity: 0.72;
}
.corr-state {
  display: inline-flex;
  align-items: center;
  padding: 0.25rem 0.4375rem 0.1875rem;
  border-radius: var(--radius-sm);
  font-family: var(--font-display);
  font-variation-settings: 'wdth' 92, 'wght' 800;
  font-size: 0.625rem;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  line-height: 1;
  background: var(--color-live-bg);
  color: var(--color-live);
}
.corr-state[data-state='resolved'] {
  background: var(--color-done-bg);
  color: var(--color-done);
}
.corr-state[data-state='dismissed'],
.corr-state[data-state='gone'] {
  background: transparent;
  color: var(--color-text-muted);
  box-shadow: inset 0 0 0 1px var(--color-border);
}
.correction-card .review-item a {
  color: inherit;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}
