/* ============================================================
   ADMIN SHELL

   Every admin section is the same page: a head, a list down the left, an
   editor on the right. These rules were written inline in the events section
   and are lifted out here VERBATIM the moment a second section needed them,
   because the alternative is two copies that agree today and not in a month.

   Section-specific styling still belongs in that section's own <style>. This
   file is only the shell they share.
   ============================================================ */

  .ad { max-width: 1180px; margin: 0 auto; padding: var(--s-8) var(--s-7) var(--s-11); }
  .ad-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--s-6); flex-wrap: wrap; margin-bottom: var(--s-7); }
  .ad-grid { display: grid; grid-template-columns: 300px 1fr; gap: var(--s-6); align-items: start; }
  @media (max-width: 900px) { .ad-grid { grid-template-columns: 1fr; } }

  .ad-card { border: var(--bw) solid var(--line-strong); border-radius: var(--radius); background: var(--surface); padding: var(--s-6); }
  .ad-sec { font-family: var(--f-mono); font-size: var(--t-label); font-weight: 700; letter-spacing: 0.16em; text-transform: uppercase; color: var(--accent); margin-bottom: var(--s-5); }

  .ad-item { width: 100%; text-align: left; display: block; padding: var(--s-5); margin-bottom: var(--s-3); cursor: pointer;
    background: var(--surface-2); border: var(--bw) solid var(--line-strong); border-radius: var(--radius); color: var(--ink); }
  .ad-item:hover { border-color: var(--accent); }
  .ad-item.on { border-color: var(--accent); background: var(--accent-soft); }
  .ad-item-t { font-weight: 900; font-style: italic; text-transform: uppercase; font-size: var(--t-md); line-height: 1.15; }
  .ad-item-m { font-family: var(--f-mono); font-size: var(--t-micro); letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); margin-top: var(--s-1); }
  .ad-live { color: var(--ok); }

  .ad-row { margin-bottom: var(--s-6); }
  .ad-lab { display: flex; align-items: baseline; justify-content: space-between; gap: var(--s-4); font-family: var(--f-mono); font-size: var(--t-label); font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; color: var(--muted); margin-bottom: var(--s-2); }
  .ad-hint { text-transform: none; letter-spacing: 0; font-size: var(--t-label); color: var(--muted); }
  .ad-in, .ad-ta { width: 100%; background: var(--surface-2); color: var(--ink); border: var(--bw) solid var(--line-strong);
    border-radius: var(--radius); padding: var(--s-4) var(--s-5); font: inherit; font-size: var(--t-md); }
  .ad-in:focus, .ad-ta:focus { outline: none; border-color: var(--accent); }
  .ad-ta { min-height: 90px; resize: vertical; }
  .ad-two { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-5); }
  .ad-check { display: inline-flex; align-items: center; gap: var(--s-3); font-family: var(--f-mono); font-size: var(--t-mono); letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted); cursor: pointer; }
  .ad-actions { display: flex; align-items: center; gap: var(--s-5); flex-wrap: wrap; margin-top: var(--s-6); }
  .ad-note { font-family: var(--f-mono); font-size: var(--t-mono); color: var(--muted); }

  .ad-prev { position: sticky; top: 20px; }
  .ad-prevbox { border: var(--bw) dashed var(--line-strong); border-radius: var(--radius); padding: var(--s-6); background: var(--bg); }

  /* Values the site computes; shown so it is obvious they are not typed here. */
  .ad-derived { border: var(--bw) dashed var(--line-strong); border-radius: var(--radius); padding: var(--s-5) var(--s-6);
    font-family: var(--f-mono); font-size: var(--t-mono); line-height: 1.6; color: var(--muted); }
  .ad-derived b { color: var(--ink); }

  /* drag to reorder */
  .ad-item { position: relative; }
  .ad-item.drag { opacity: 0.4; }
  .ad-item.over { border-color: var(--accent); border-style: dashed; }
  .ad-grip { position: absolute; top: 11px; right: 10px; color: var(--muted); font-size: var(--t-sm); cursor: grab; letter-spacing: 1px; }

/* ============================================================
   THE ADMIN BAR

   It is the SITE navbar, filled differently. Same `.nav` shell, same 62px row,
   same brand and chip sizes, because a tool that looks like different software
   from the site it administers is what the first version of this felt like.

   The slot lives in each page's static HTML, so the browser reserves the row
   during parsing. The first version created it in JS and prepended it after
   first paint, which drew the page and then shoved it down by the height of a
   bar that had just appeared - the glitch on every navigation.
   ============================================================ */
  .nav-left { display: flex; align-items: center; gap: var(--s-4); min-width: 0; }

  /* Says where you are, quietly. The brand beside it goes to the public site,
     so without this the bar reads as the front page. */
  .nav-where {
    font-family: var(--f-mono); font-size: var(--t-label); font-weight: 700;
    letter-spacing: 0.16em; text-transform: uppercase; color: var(--accent);
    padding: 3px var(--s-3); border: var(--bw) solid var(--accent); border-radius: var(--radius);
  }

  /* A chip that is a link. Same height and shape as every other chip in the
     navbar, so the row reads as one set of controls. */
  .nav-link { text-decoration: none; color: var(--muted); }
  .nav-link:hover { border-color: var(--accent); color: var(--accent); }

  @media (max-width: 620px) { .nav-where { display: none; } }

/* ============================================================
   THE CUSTOM CONTROLS

   A native date input and a native dropdown are drawn by the operating system:
   they ignore the skin and the type scale and look like different software
   wedged into the page. These are the replacements, applied by
   admin-controls.js, which keeps the real element in the DOM holding the value.
   ============================================================ */
  /* The real input, kept for its value and its events, taken out of the layout
     without being hidden from assistive tech in a way that breaks the label.

     !important, AND IT HAS TO BE. This is a single-class selector, so ANY other
     single-class rule loaded after it wins on source order alone - and every
     page's own <style> loads after this file. The Calendar styled its inputs
     `.cal-in { width: 100% }`, which beat `width: 1px` here, so seven
     absolutely positioned date inputs stretched to the full width of their
     containing block and gave the page a horizontal scrollbar with nothing
     visible to explain it. Took a console query to find, because a
     `clip: rect(0 0 0 0)` element is invisible while it is overflowing.

     A visually-hidden utility is exactly the case !important exists for: it is
     not a style, it is a promise that the element takes up no room. */
  .jc-hidden {
    position: absolute !important;
    width: 1px !important; height: 1px !important;
    padding: 0 !important; margin: -1px !important; border: 0 !important;
    min-width: 0 !important; max-width: none !important;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
  }

  .jc-btn {
    display: flex; align-items: center; justify-content: space-between; gap: var(--s-3);
    width: 100%; cursor: pointer; text-align: left;
    font-family: var(--f-body); font-size: var(--t-sm);
    background: var(--surface-2); color: var(--ink);
    border: var(--bw) solid var(--line-strong); border-radius: var(--radius);
    padding: var(--s-3) var(--s-4);
  }
  .jc-btn:hover { border-color: var(--accent); }
  .jc-btn:focus-visible { outline: none; border-color: var(--accent); }
  .jc-ph { color: var(--muted); }
  .jc-cal { color: var(--muted); font-size: var(--t-sm); }
  .jc-clear { color: var(--muted); font-size: var(--t-md); line-height: 1; padding: 0 var(--s-1); }
  .jc-clear:hover { color: var(--accent); }
  .jc-caret { width: 0; height: 0; flex: 0 0 auto;
    border-left: 4px solid transparent; border-right: 4px solid transparent; border-top: 5px solid var(--muted); }

  .jc-pop {
    position: absolute; z-index: 90;
    background: var(--surface); border: var(--bw) solid var(--ink); border-radius: var(--radius);
    box-shadow: 0 14px 40px var(--shadow); padding: var(--s-4);
  }

  /* the calendar */
  .jc-cal-pop { width: 268px; }
  .jc-cal-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--s-4); }
  /* The title is a BUTTON now: it zooms out to the months so a date two years
     back is two clicks instead of twenty-four. Styled to look like the label it
     replaced until you touch it, because a permanently outlined control in the
     middle of the header reads as the thing to press, and the days are. */
  .jc-cal-t {
    font-family: var(--f-mono); font-size: var(--t-mono); font-weight: 700; letter-spacing: 0.04em;
    cursor: pointer; color: var(--ink); padding: 3px var(--s-3);
    background: transparent; border: var(--bw) solid transparent; border-radius: var(--radius);
  }
  .jc-cal-t:hover { border-color: var(--accent); color: var(--accent); }
  .jc-nav {
    width: 26px; height: 26px; display: grid; place-items: center; cursor: pointer;
    background: transparent; color: var(--muted); font-size: var(--t-md);
    border: var(--bw) solid var(--line-strong); border-radius: var(--radius);
  }
  .jc-nav:hover { border-color: var(--accent); color: var(--accent); }

  .jc-dow, .jc-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
  .jc-dow span {
    text-align: center; font-family: var(--f-mono); font-size: var(--t-micro);
    color: var(--muted); padding-bottom: var(--s-2);
  }
  .jc-day {
    aspect-ratio: 1; display: grid; place-items: center; cursor: pointer;
    font-family: var(--f-mono); font-size: var(--t-mono); font-variant-numeric: tabular-nums;
    background: transparent; color: var(--ink); border: var(--bw) solid transparent; border-radius: var(--radius);
  }
  .jc-day:hover { border-color: var(--accent); }
  .jc-day.out { cursor: default; }
  /* Today is outlined, the chosen day is filled: two different facts, so two
     different treatments rather than one that has to win. */
  .jc-day.today { border-color: var(--line-strong); }
  .jc-day.on { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }

  /* The year view. Four across rather than three so the block stays close to
     the square the day grid occupies and the popover does not jump height when
     it zooms. */
  .jc-mgrid { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--s-2); }
  .jc-month {
    padding: var(--s-4) 0; cursor: pointer; text-align: center;
    font-family: var(--f-mono); font-size: var(--t-mono);
    background: transparent; color: var(--ink);
    border: var(--bw) solid transparent; border-radius: var(--radius);
  }
  .jc-month:hover { border-color: var(--accent); }
  .jc-month.today { border-color: var(--line-strong); }
  .jc-month.on { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }
  .jc-cal-note { font-family: var(--f-mono); font-size: var(--t-label); letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); }

  .jc-cal-foot { display: flex; justify-content: space-between; margin-top: var(--s-4); padding-top: var(--s-3);
    border-top: var(--bw) solid var(--line-strong); }
  .jc-link {
    cursor: pointer; background: transparent; border: 0; padding: 0;
    font-family: var(--f-mono); font-size: var(--t-label); letter-spacing: 0.08em; text-transform: uppercase;
    color: var(--muted);
  }
  .jc-link:hover { color: var(--accent); }

  /* the dropdown */
  .jc-list { padding: var(--s-2); max-height: 320px; overflow-y: auto; display: flex; flex-direction: column; }
  .jc-opt {
    text-align: left; cursor: pointer; background: transparent; color: var(--ink); border: 0;
    font-family: var(--f-body); font-size: var(--t-sm);
    padding: var(--s-3) var(--s-4); border-radius: var(--radius); white-space: nowrap;
  }
  .jc-opt:hover { background: var(--surface-2); }
  .jc-opt.on { background: var(--accent); color: var(--accent-ink); }

  /* A suggestion carries a face, which is the fastest way to tell two similar
     Twitch names apart before you commit to one. */
  .jc-sugg { max-height: 300px; }
  .jc-sugg-opt { display: flex; align-items: center; gap: var(--s-3); }
  .jc-sugg-opt img, .jc-sugg-blank {
    width: 26px; height: 26px; flex: 0 0 auto; border-radius: 4px;
    object-fit: cover; background: var(--surface-2);
  }
  .jc-sugg-l { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .jc-sugg-s { flex: 0 0 auto; font-family: var(--f-mono); font-size: var(--t-micro); color: var(--muted); }
  .jc-sugg-opt.on .jc-sugg-s { color: var(--accent-ink); }

/* ============================================================ THE GATE

   NOTHING BEHIND IT IS DRAWN UNTIL THE SERVER SAYS WHO YOU ARE.

   This is not what keeps the data safe: every endpoint checks server-side on
   every call, and it did before this existed. What this keeps back is the
   SHAPE of the admin. A stranger could walk into every panel and read the
   sections, the controls, the warnings and the copy describing exactly what
   each tool does to which collection. That is a map of the place, and handing
   it to anybody who guesses a URL is the wrong default.

   FAIL SHUT. `data-gate="shut"` is set inline before the first paint, and only
   a positive answer from adminWhoAmI opens it. A failed call, an offline
   network or a script that never ran all leave it closed. */
html[data-gate="shut"] .ad,
html[data-gate="shut"] [data-juq-adminbar],
html[data-gate="closed"] .ad,
html[data-gate="closed"] [data-juq-adminbar] { display: none; }

/* What a stranger gets instead. Deliberately says nothing about what is here:
   naming the areas they cannot reach is the map all over again. */
.gate-msg {
  min-height: 70vh; display: grid; place-items: center; padding: var(--s-7);
  text-align: center;
}
.gate-in { max-width: 44ch; display: flex; flex-direction: column; gap: var(--s-5); align-items: center; }
.gate-h {
  font-weight: 900; font-style: italic; text-transform: uppercase;
  font-size: var(--t-h2); letter-spacing: -0.02em;
}
.gate-p { color: var(--muted); font-size: var(--t-body); line-height: 1.6; }
/* Tarnished. Sits between the verdict and the explanation, which is where the
   pause is when somebody says this out loud.

   The negative margins pull it into the gap the column's own gap already
   leaves, so it reads as sitting BETWEEN the two lines rather than as a third
   item spaced evenly from both. Rounded to the same radius as the buttons
   underneath it, because a square image over two rounded rectangles is the one
   thing on this page that would look unfinished. */
.gate-emote { margin: calc(var(--s-3) * -1) 0; line-height: 0; }
.gate-emote img {
  height: 128px; width: auto; display: block;
  border-radius: var(--radius);
}
.gate-acts { display: flex; gap: var(--s-3); flex-wrap: wrap; justify-content: center; }

/* The wait, which is one call and usually instant. Shown rather than left
   blank, because a blank page and a refused page look identical. */
.gate-wait {
  font-family: var(--f-mono); font-size: var(--t-micro); letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--muted);
}

/* ---------- the video proof, in Happening Now ----------
   A thumbnail of the video that was actually pasted, sitting under the field.

   THE FAILURE THIS IS FOR IS NOT A BAD LINK. The server refuses anything that
   is not a YouTube URL, so a malformed paste is already handled and says so.
   What nothing else can catch is a WELL-FORMED LINK TO THE WRONG VIDEO, and
   this puts a video on the front page of the site: the wrong one goes live and
   stays live until somebody notices. A picture of the real thing is the only
   check that reads at a glance, and it costs one image request in an admin
   screen. */
.pv-proof {
  display: flex; gap: var(--s-4); align-items: center;
  margin-top: var(--s-3); padding: var(--s-3);
  border: var(--bw) solid var(--line); border-radius: var(--radius);
  background: var(--surface-2, var(--surface));
}
/* An explicit rule, because .pv-proof sets display and that beats the browser's
   own [hidden]. Six occurrences of this on the site and counting. */
.pv-proof[hidden] { display: none; }
.pv-thumb {
  width: 160px; height: 90px; object-fit: cover; flex: none;
  border-radius: var(--radius); background: var(--surface); border: var(--bw) solid var(--line);
}
.pv-proof-t { display: flex; flex-direction: column; gap: var(--s-2); min-width: 0; }
.pv-proof-t b { font-family: var(--f-mono); font-size: var(--t-mono); }
/* The field is not editable while a video is set, and greyed is not enough on
   its own: the hint beside the label says why. */
.ad-in:disabled { opacity: 0.45; cursor: not-allowed; }

/* THE AUTO-LOGGER SUBSCRIPTION STATUS. Reload re-checks every Twitch
   subscription and used to report nothing, so it read as a dead button. */
.al-subs { display: flex; flex-wrap: wrap; gap: var(--s-3); margin-bottom: var(--s-5); }
.al-sub {
  font-family: var(--f-mono); font-size: var(--t-micro); letter-spacing: 0.04em;
  padding: var(--s-1) var(--s-3); border-radius: var(--radius);
  border: var(--bw) solid var(--line); color: var(--muted);
}
/* --f-sweet AND --f-sour WERE THE WRONG TOKENS, TWICE OVER.

   They are the Taste Tester’s FLAVOUR colours, not status colours: sweet is an
   ORANGE and sour is a YELLOW-GREEN, so healthy would have read orange and
   broken would have read green. Backwards. (The hex values are deliberately
   not quoted here - the drift checker reads a comment the same as a rule and
   flagged them as hardcoded colours, which is fair enough.)

   And they live in tasters.css, which this page does not load, so both rules
   were invalid and every chip simply inherited the colour around it - which is
   why all four looked identical whatever their status was.

   --ok is defined per skin in juq.css, which every page loads, and --accent is
   what this admin already uses for an error (see .rq-err). */
.al-sub-ok { border-color: var(--ok); color: var(--ok); }
.al-sub-bad { border-color: var(--accent); color: var(--accent); }
