/* ═══════════════════════════════════════════════════════════════════════════
   EILISH.SU CONSOLE — "LIQUID GLASS"

   This stylesheet is served to anonymous visitors on the login page, so it
   deliberately says nothing about what the console is for.

   The background is the loudest thing on the page, so the interface is built
   to sit ON it rather than cover it: translucent panels, blurred backdrops,
   hairline light strokes, generous radii. Everything the operator reads
   lives inside a panel; everything decorative lives behind one.

   Dark only. A glass system needs a known ground to tint against, and every
   background this app ships (photograph, shader field) is dark.
   ═══════════════════════════════════════════════════════════════════════ */

:root {
  color-scheme: dark;

  /* ── surfaces ──────────────────────────────────────────────────────── */
  --glass:        rgba(18, 20, 24, 0.62);
  --glass-strong: rgba(14, 16, 20, 0.72);
  --glass-well:   rgba(255, 255, 255, 0.045);
  --glass-hover:  rgba(255, 255, 255, 0.075);

  /* ── strokes. A glass edge catches light; it is never a dark line. ─── */
  --stroke:        rgba(255, 255, 255, 0.10);
  --stroke-strong: rgba(255, 255, 255, 0.18);
  --stroke-hair:   rgba(255, 255, 255, 0.06);
  /* 1px inner highlight along a panel's top edge — the main "glass" tell */
  --sheen: inset 0 1px 0 0 rgba(255, 255, 255, 0.07);

  /* ── ink ───────────────────────────────────────────────────────────── */
  --ink:   #F2F5F8;
  --ink-2: rgba(242, 245, 248, 0.74);
  --ink-3: rgba(242, 245, 248, 0.52);
  --ink-4: rgba(242, 245, 248, 0.34);

  /* ── semantics ─────────────────────────────────────────────────────── */
  --ok:   #5BE49B;
  --warn: #FFD166;
  --bad:  #FF7A6B;
  --info: #8FB6FF;
  --iris: #A78BFA;

  /* ── geometry ──────────────────────────────────────────────────────── */
  --r:    18px;
  --r-sm: 11px;
  --r-xs: 8px;
  --blur: 22px;
  --pad:  24px;

  /* ── motion ────────────────────────────────────────────────────────── */
  --fast: 140ms;
  --ease: cubic-bezier(.4, 0, .2, 1);

  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, Roboto,
          "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
          "Liberation Mono", monospace;
}

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  min-height: 100vh;
  font: 400 14px/1.55 var(--sans);
  letter-spacing: -0.005em;
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* Ground for when no background media is configured. */
  background:
    radial-gradient(120% 80% at 20% 0%, #1B1F27 0%, transparent 60%),
    radial-gradient(100% 80% at 90% 10%, #191B22 0%, transparent 55%),
    #0C0E12;
  background-attachment: fixed;
}

::selection { background: rgba(255, 255, 255, .18); }

a { color: var(--ink); text-decoration: none; }
a:hover { text-decoration: underline; text-underline-offset: 3px; }

:focus-visible {
  outline: 2px solid rgba(255, 255, 255, .55);
  outline-offset: 2px;
  border-radius: 4px;
}

.container {
  width: 100%;
  max-width: 1180px;
  margin: 0 auto;
  padding: 0 22px;
}


/* ══ HEADER — a floating glass pill ══════════════════════════════════════ */

header {
  position: sticky;
  top: 0;
  z-index: 60;
  padding: 14px 0 6px;
}

.header {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 9px 10px 9px 18px;
  background: var(--glass-strong);
  backdrop-filter: blur(20px) saturate(165%);
  -webkit-backdrop-filter: blur(20px) saturate(165%);
  border: 1px solid var(--stroke);
  border-radius: 999px;
  box-shadow: var(--sheen), 0 14px 34px -16px rgba(0, 0, 0, .7);
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
  color: var(--ink);
  font: 600 14px/1 var(--sans);
  letter-spacing: -0.015em;
  white-space: nowrap;
}
.brand:hover { text-decoration: none; }
.brand svg { flex: none; width: 18px; height: 18px; color: var(--ink); opacity: .9; }
.brand-name { overflow: hidden; text-overflow: ellipsis; min-width: 0; }

.main-nav {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-left: auto;
}
.nav-link {
  padding: 8px 15px;
  border-radius: 999px;
  color: var(--ink-3);
  font: 500 13px/1 var(--sans);
  white-space: nowrap;
  transition: color var(--fast) var(--ease), background-color var(--fast) var(--ease);
}
.nav-link:hover { color: var(--ink); background: var(--glass-well); text-decoration: none; }
/* The current page is the one solid element in the chrome. */
.nav-current,
.nav-current:hover {
  background: #FFFFFF;
  color: #0D0F13;
  font-weight: 600;
}

header form { display: inline-flex; }
header .link {
  padding: 8px 14px;
  border-radius: 999px;
  color: var(--ink-3);
  font: 500 13px/1 var(--sans);
  background: none;
  border: none;
}
header .link:hover { color: var(--ink); background: var(--glass-well); }


/* ══ PAGE OPENING ════════════════════════════════════════════════════════ */

main.container { padding-top: 26px; padding-bottom: 96px; }

h1 {
  margin: 18px 0 26px;
  font: 600 clamp(30px, 4.4vw, 42px)/1.08 var(--sans);
  letter-spacing: -0.035em;
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
}

h2 {
  margin: 0 0 16px;
  font: 600 16px/1.3 var(--sans);
  letter-spacing: -0.02em;
  color: var(--ink);
}

h3 {
  margin: 0 0 12px;
  font: 600 13px/1.3 var(--sans);
  letter-spacing: -0.01em;
  color: var(--ink);
}


/* ══ GLASS PANEL ═════════════════════════════════════════════════════════ */

.card {
  position: relative;
  padding: var(--pad) calc(var(--pad) + 2px) calc(var(--pad) + 2px);
  margin-bottom: 18px;
  background: var(--glass);
  backdrop-filter: blur(var(--blur)) saturate(160%);
  -webkit-backdrop-filter: blur(var(--blur)) saturate(160%);
  border: 1px solid var(--stroke);
  border-radius: var(--r);
  box-shadow: var(--sheen), 0 22px 54px -26px rgba(0, 0, 0, .62);
}

.grid-two {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 18px;
  /* The children have their own margin zeroed, so the row itself has to
     carry the gap to whatever panel follows it. */
  margin-bottom: 18px;
}
.grid-two > .card { margin-bottom: 0; }
@media (max-width: 860px) { .grid-two { grid-template-columns: 1fr; } }


/* ══ TYPE UTILITIES ══════════════════════════════════════════════════════ */

.muted { color: var(--ink-3); }
.meta {
  font: 400 12px/1.45 var(--mono);
  color: var(--ink-3);
}
.push { margin-left: auto; }
.inline { display: inline; }

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.dripfeed-help,
.notice {
  margin: 0 0 14px;
  font: 400 13px/1.6 var(--sans);
  color: var(--ink-3);
}
.dripfeed-help strong, .notice strong { color: var(--ink-2); font-weight: 600; }
.dripfeed-help em, .notice em { color: var(--ink-2); font-style: normal; }

.empty-state {
  margin: 0;
  padding: 26px 4px;
  text-align: center;
  font: 400 13px/1.6 var(--sans);
  color: var(--ink-3);
}

code {
  font: 400 .92em/1.4 var(--mono);
  padding: 2px 6px;
  border-radius: var(--r-xs);
  background: var(--glass-well);
  border: 1px solid var(--stroke-hair);
  color: var(--ink-2);
}
code:empty { display: none; }


/* ══ ALERTS ══════════════════════════════════════════════════════════════ */

.alert, .alert-ok, .alert-err {
  margin: 0 0 18px;
  padding: 12px 15px;
  border-radius: var(--r-sm);
  font: 400 13px/1.55 var(--sans);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
.alert, .alert-err {
  background: rgba(255, 122, 107, .12);
  border: 1px solid rgba(255, 122, 107, .34);
  color: #FFB3A8;
}
.alert-ok {
  background: rgba(91, 228, 155, .11);
  border: 1px solid rgba(91, 228, 155, .32);
  color: #9BEFC4;
}
.alert strong, .alert-ok strong, .alert-err strong { font-weight: 600; }


/* ══ FORMS ═══════════════════════════════════════════════════════════════ */

form label {
  display: block;
  margin-bottom: 14px;
  font: 500 12px/1.5 var(--sans);
  color: var(--ink-3);
}

input[type="text"], input[type="password"], input[type="email"],
input[type="number"], input[type="search"], input[type="datetime-local"],
select, textarea {
  display: block;
  width: 100%;
  margin-top: 6px;
  padding: 10px 13px;
  font: 400 13.5px/1.4 var(--sans);
  color: var(--ink);
  background: var(--glass-well);
  border: 1px solid var(--stroke);
  border-radius: var(--r-sm);
  transition: border-color var(--fast) var(--ease), background-color var(--fast) var(--ease);
}
input::placeholder, textarea::placeholder { color: var(--ink-4); }
input:hover, select:hover, textarea:hover { border-color: var(--stroke-strong); }
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: rgba(255, 255, 255, .34);
  background: var(--glass-hover);
  box-shadow: 0 0 0 3px rgba(255, 255, 255, .07);
}
textarea {
  min-height: 132px;
  font-family: var(--mono);
  font-size: 12.5px;
  line-height: 1.65;
  resize: vertical;
}
select {
  appearance: none;
  -webkit-appearance: none;
  padding-right: 34px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8' fill='none' stroke='%23F2F5F8' stroke-opacity='.55' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M1 1.5 6 6.5l5-5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 13px center;
  background-size: 11px;
}
select option { background: #14171C; color: var(--ink); }

input[type="file"] {
  display: block;
  width: 100%;
  margin-top: 6px;
  font: 400 12.5px/1.4 var(--sans);
  color: var(--ink-3);
}
input[type="file"]::file-selector-button {
  margin-right: 12px;
  padding: 8px 14px;
  font: 500 12.5px/1 var(--sans);
  color: var(--ink);
  background: var(--glass-well);
  border: 1px solid var(--stroke);
  border-radius: 999px;
  cursor: pointer;
  transition: background-color var(--fast) var(--ease);
}
input[type="file"]::file-selector-button:hover { background: var(--glass-hover); }

.hint {
  display: block;
  margin-top: 6px;
  font: 400 11.5px/1.45 var(--sans);
  color: var(--ink-4);
}

.check {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  cursor: pointer;
  color: var(--ink-2);
}
.check input[type="checkbox"] {
  appearance: none;
  -webkit-appearance: none;
  width: 16px; height: 16px;
  margin: 0;
  flex: none;
  border: 1px solid var(--stroke-strong);
  border-radius: 5px;
  background: var(--glass-well);
  cursor: pointer;
  transition: background-color var(--fast) var(--ease), border-color var(--fast) var(--ease);
}
.check input[type="checkbox"]:checked {
  background: #FFFFFF;
  border-color: #FFFFFF;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' fill='none' stroke='%230D0F13' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2.5 6.4 4.8 8.7 9.5 3.6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: center;
  background-size: 11px;
}

/* Horizontal field group. */
.row {
  display: flex;
  gap: 14px;
  align-items: flex-end;
  flex-wrap: wrap;
  margin-bottom: 14px;
}
.row > label { flex: 1 1 auto; min-width: 0; margin-bottom: 0; }
.row .grow { flex: 1 1 210px; min-width: 0; }
.row .port { flex: 0 0 104px; }


/* ══ BUTTONS ═════════════════════════════════════════════════════════════ */

button {
  font: 500 13px/1 var(--sans);
  letter-spacing: -0.005em;
  color: var(--ink);
  background: var(--glass-well);
  border: 1px solid var(--stroke);
  border-radius: 999px;
  padding: 10px 18px;
  cursor: pointer;
  transition: background-color var(--fast) var(--ease),
              border-color var(--fast) var(--ease),
              transform var(--fast) var(--ease);
}
button:hover { background: var(--glass-hover); border-color: var(--stroke-strong); }
button:active { transform: translateY(1px); }

/* The one solid control on the page. */
button.primary {
  background: #FFFFFF;
  border-color: #FFFFFF;
  color: #0D0F13;
  font-weight: 600;
}
button.primary:hover { background: #E8ECF1; border-color: #E8ECF1; }
button.primary.big { padding: 13px 26px; font-size: 14px; }

button.danger {
  color: #FFB3A8;
  border-color: rgba(255, 122, 107, .38);
  background: rgba(255, 122, 107, .10);
}
button.danger:hover {
  background: rgba(255, 122, 107, .18);
  border-color: rgba(255, 122, 107, .55);
}

button.link {
  padding: 6px 10px;
  background: none;
  border: none;
  color: var(--ink-3);
  border-radius: var(--r-xs);
}
button.link:hover { color: var(--ink); background: var(--glass-well); border-color: transparent; }
button.link.danger { color: #FFB3A8; background: none; border: none; }
button.link.danger:hover { background: rgba(255, 122, 107, .14); }

button:disabled { opacity: .4; cursor: default; }
button:disabled:hover { background: var(--glass-well); border-color: var(--stroke); }

.button-link {
  display: inline-flex;
  align-items: center;
  padding: 9px 16px;
  font: 500 12.5px/1 var(--sans);
  color: var(--ink);
  background: var(--glass-well);
  border: 1px solid var(--stroke);
  border-radius: 999px;
  white-space: nowrap;
  transition: background-color var(--fast) var(--ease), border-color var(--fast) var(--ease);
}
.button-link:hover {
  background: var(--glass-hover);
  border-color: var(--stroke-strong);
  text-decoration: none;
}


/* ══ TOOLBAR ═════════════════════════════════════════════════════════════ */

.toolbar {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-top: 20px;
  padding-top: 18px;
  border-top: 1px solid var(--stroke-hair);
}
.toolbar .link {
  padding: 6px 0;
  color: var(--ink-3);
  font: 500 12.5px/1 var(--sans);
  background: none;
  border: none;
}
.toolbar .link:hover { color: var(--ink); background: none; text-decoration: none; }
/* A toolbar that opens a panel has nothing above it to be divided from. */
.card > .toolbar:first-child { margin-top: 0; padding-top: 0; border-top: 0; }


/* ══ DISCLOSURE ══════════════════════════════════════════════════════════ */

details { margin-top: 6px; }
details > summary {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 0;
  list-style: none;
  cursor: pointer;
  font: 500 12.5px/1 var(--sans);
  color: var(--ink-3);
  transition: color var(--fast) var(--ease);
}
details > summary::-webkit-details-marker { display: none; }
details > summary::before {
  content: "";
  width: 9px; height: 9px;
  flex: none;
  background: currentColor;
  clip-path: polygon(0 40%, 40% 40%, 40% 0, 60% 0, 60% 40%, 100% 40%, 100% 60%, 60% 60%, 60% 100%, 40% 100%, 40% 60%, 0 60%);
  transition: transform var(--fast) var(--ease);
  opacity: .8;
}
details[open] > summary::before { transform: rotate(45deg); }
details > summary:hover { color: var(--ink); }
details[open] > summary { margin-bottom: 10px; }


/* ══ PRESET LISTS ════════════════════════════════════════════════════════ */

.preset-list { margin: 0 0 10px; padding: 0; list-style: none; }
.preset-list li {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 11px 14px;
  margin-bottom: 7px;
  background: var(--glass-well);
  border: 1px solid var(--stroke-hair);
  border-radius: var(--r-sm);
  transition: background-color var(--fast) var(--ease);
}
.preset-list li:hover { background: var(--glass-hover); }
.preset-list li.muted { justify-content: center; color: var(--ink-3); font-size: 12.5px; }
.preset-name {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font: 500 13px/1.4 var(--sans);
  color: var(--ink);
}
.preset-list form { flex: none; }


/* ══ TABS ════════════════════════════════════════════════════════════════ */

.input-tabs, .bg-mode-tabs {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  margin: 4px 0 18px;
  padding: 4px;
  background: var(--glass-well);
  border: 1px solid var(--stroke-hair);
  border-radius: 999px;
}
.tab-choice {
  position: relative;
  display: inline-flex;
  align-items: center;
  padding: 8px 16px;
  margin: 0;
  border-radius: 999px;
  cursor: pointer;
  font: 500 12.5px/1 var(--sans);
  color: var(--ink-3);
  white-space: nowrap;
  user-select: none;
  -webkit-user-select: none;
  transition: color var(--fast) var(--ease), background-color var(--fast) var(--ease);
}
.tab-choice input[type="radio"] {
  position: absolute;
  opacity: 0;
  width: 1px; height: 1px;
  margin: 0;
  pointer-events: none;
}
.tab-choice:hover { color: var(--ink-2); }
.tab-choice:has(input:checked) {
  background: rgba(255, 255, 255, .95);
  color: #0D0F13;
  font-weight: 600;
}
.tab-choice:has(input:focus-visible) {
  outline: 2px solid rgba(255, 255, 255, .55);
  outline-offset: 2px;
}


/* ══ DRIP-FEED PANEL ═════════════════════════════════════════════════════ */

.dripfeed {
  margin: 20px 0;
  padding: 18px 20px 20px;
  background: var(--glass-well);
  border: 1px solid var(--stroke-hair);
  border-radius: var(--r-sm);
}
/* A <legend> normally renders in the gap of the fieldset's own border, which
   with a filled box reads as two stacked panels. Floating it to full width
   drops it back inside as an ordinary block heading. */
.dripfeed legend {
  float: left;
  width: 100%;
  padding: 0;
  margin-bottom: 2px;
  font: 600 13px/1.3 var(--sans);
  color: var(--ink);
}
.dripfeed::after { content: ""; display: table; clear: both; }
.dripfeed legend .check { margin: 0; font-weight: 600; color: var(--ink); }
.dripfeed .dripfeed-help { margin: 10px 0 0; }
.dripfeed-controls { margin-top: 16px; }
.dripfeed-controls .row { margin-bottom: 10px; }
.dripfeed-preview {
  margin: 10px 0 0;
  padding: 11px 14px;
  background: rgba(143, 182, 255, .09);
  border: 1px solid rgba(143, 182, 255, .24);
  border-radius: var(--r-sm);
  font: 400 12px/1.55 var(--mono);
  color: #BBD2FF;
}


/* ══ TABLES ══════════════════════════════════════════════════════════════ */

.table-wrap {
  overflow-x: auto;
  overscroll-behavior-x: contain;
  border-radius: var(--r-sm);
  scrollbar-width: thin;
  scrollbar-color: rgba(255, 255, 255, .22) transparent;
}
.table-wrap.tall { max-height: 620px; overflow-y: auto; }
.table-wrap::-webkit-scrollbar { width: 10px; height: 10px; }
.table-wrap::-webkit-scrollbar-track { background: transparent; }
.table-wrap::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, .16);
  border-radius: 99px;
  border: 3px solid transparent;
  background-clip: content-box;
}
.table-wrap::-webkit-scrollbar-thumb:hover {
  background: rgba(255, 255, 255, .28);
  background-clip: content-box;
}

table { width: 100%; border-collapse: collapse; }

thead th {
  position: sticky;
  top: 0;
  z-index: 2;
  padding: 11px 14px;
  text-align: left;
  white-space: nowrap;
  font: 600 10.5px/1.2 var(--sans);
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ink-4);
  /* Opaque enough to hide rows scrolling under it in a .tall wrapper, light
     enough that it does not read as a dark band inside a glass panel. */
  background: rgba(16, 18, 22, .82);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--stroke);
}
tbody td {
  padding: 12px 14px;
  vertical-align: top;
  border-bottom: 1px solid var(--stroke-hair);
  font-size: 13px;
  color: var(--ink-2);
  overflow-wrap: anywhere;
}
tbody tr:last-child td { border-bottom: 0; }
tbody tr { transition: background-color var(--fast) var(--ease); }
tbody tr:hover { background: rgba(255, 255, 255, .035); }

/* A state tick down the left edge of notable rows. */
tbody tr:has(.status-running)                { background: rgba(255, 255, 255, .045); }
tbody tr:has(.status-running) td:first-child { box-shadow: inset 3px 0 0 var(--info); }
tbody tr:has(.status-failed)  td:first-child { box-shadow: inset 3px 0 0 var(--bad); }
tbody tr:has(.status-submitted---confirm-failed) td:first-child { box-shadow: inset 3px 0 0 var(--iris); }
tbody tr:has(.status-submitted---no-email)       td:first-child { box-shadow: inset 3px 0 0 var(--warn); }

table.jobs { min-width: 680px; }
table.jobs td { white-space: nowrap; }
table.jobs td:first-child,
table.jobs td:nth-child(3), table.jobs td:nth-child(4), table.jobs td:nth-child(5) {
  font: 400 12.5px/1.5 var(--mono);
  font-variant-numeric: tabular-nums slashed-zero;
  color: var(--ink);
}
table.jobs td:nth-child(6) { font: 400 12px/1.5 var(--mono); color: var(--ink-3); }

/* The entries grid is fixed so a 300-char error can never crush the columns
   that matter. The table is SIX columns normally (email, name, status,
   reply, request id, error) and SEVEN when drip-feed adds "scheduled", so
   widths are declared for seven; with table-layout:fixed a browser scales
   the set proportionally when the run only has six. */
table.entries { table-layout: fixed; min-width: 980px; }
table.entries th:nth-child(1) { width: 23%; }   /* email      */
table.entries th:nth-child(2) { width: 10%; }   /* name       */
table.entries th:nth-child(3) { width: 13%; }   /* status     */
table.entries th:nth-child(4) { width: 13%; }   /* reply / scheduled */
table.entries th:nth-child(5) { width: 16%; }   /* request id / reply */
table.entries th:nth-child(6) { width: 25%; }   /* error / request id */
table.entries th:nth-child(7) { width: 20%; }   /* error, drip runs only */
table.entries td { font-size: 12.5px; }
table.entries td:first-child { font-family: var(--mono); font-size: 12px; color: var(--ink); }

.status-cell { white-space: nowrap; }
.req-cell code {
  display: inline-block;
  max-width: 100%;
  user-select: all;
  -webkit-user-select: all;
  font-size: 11.5px;
}
.req-cell code:empty { display: none; }
.err-cell { color: var(--ink-3); font-size: 12px; overflow-wrap: anywhere; }
.sched-cell, .fu-cell { white-space: nowrap; font: 400 12px/1.5 var(--mono); color: var(--ink-3); }


/* ══ STATUS PILLS ════════════════════════════════════════════════════════ */

.status {
  --pig: var(--ink-3);
  display: inline-flex;
  align-items: center;
  gap: 7px;
  max-width: 100%;
  padding: 4px 11px 4px 9px;
  border-radius: 999px;
  font: 500 11.5px/1.45 var(--sans);
  color: var(--pig);
  background: color-mix(in srgb, var(--pig) 13%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--pig) 34%, transparent);
}
.status::before {
  content: "";
  width: 6px; height: 6px;
  flex: none;
  border-radius: 50%;
  background: var(--pig);
}

.status-queued  { --pig: var(--ink-3); }
.status-queued::before { background: transparent; box-shadow: inset 0 0 0 1.5px var(--pig); }
.status-pending { --pig: var(--ink-3); }
.status-pending::before { width: 5px; height: 5px; opacity: .65; }
.status-running { --pig: var(--info); }
.status-done, .status-success { --pig: var(--ok); }
.status-failed  { --pig: var(--bad); }
.status-failed::before { border-radius: 1.5px; transform: rotate(45deg); }
.status-stopped { --pig: var(--ink-2); }
.status-stopped::before { border-radius: 1.5px; }
.status-submitted---no-email       { --pig: var(--warn); }
.status-submitted---confirm-failed { --pig: var(--iris); }

/* Live runs get a breathing halo. */
.status-running::before { animation: statusPulse 2.1s var(--ease) infinite; }
@keyframes statusPulse {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--info) 55%, transparent); }
  50%      { box-shadow: 0 0 0 4px color-mix(in srgb, var(--info) 0%, transparent); }
}

h1 .status { font-size: 12.5px; padding: 5px 13px 5px 11px; }


/* ══ SCOREBOARD ══════════════════════════════════════════════════════════ */

.stats-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(118px, 1fr));
  gap: 1px;
  padding: 1px;
  background: var(--stroke-hair);
  border: 1px solid var(--stroke-hair);
  border-radius: var(--r-sm);
  overflow: hidden;
}
.stat {
  display: flex;
  flex-direction: column;
  gap: 7px;
  padding: 16px 16px 17px;
  background: rgba(255, 255, 255, .028);
}
.stat label {
  margin: 0;
  font: 600 10px/1 var(--sans);
  letter-spacing: .085em;
  text-transform: uppercase;
  color: var(--ink-4);
}
.stat span {
  font: 600 27px/1 var(--sans);
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}
.stat.running span { color: var(--info); }
.stat.success span { color: var(--ok); }
.stat.error   span { color: var(--bad); }


/* ══ TERMINAL ════════════════════════════════════════════════════════════ */

.terminal {
  margin-top: 4px;
  background: rgba(8, 10, 13, .74);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border: 1px solid var(--stroke);
  border-radius: var(--r-sm);
  overflow: hidden;
}
.terminal-titlebar {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  background: rgba(255, 255, 255, .035);
  border-bottom: 1px solid var(--stroke-hair);
}
.terminal-titlebar .dot {
  width: 9px; height: 9px;
  flex: none;
  border-radius: 50%;
  background: var(--ink-4);
  opacity: .6;
}
.terminal-titlebar .dot.green { background: var(--ok); opacity: .85; }
.terminal-title { font: 400 11.5px/1 var(--mono); color: var(--ink-3); }
.log-controls {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-left: auto;
  font: 400 11.5px/1.4 var(--mono);
  color: var(--ink-3);
}
.log-controls .check { font: inherit; color: var(--ink-3); }
.log-controls .muted { color: var(--ink-4); }
.log-download {
  color: var(--ink-3);
  border-bottom: 1px solid transparent;
  transition: color var(--fast) var(--ease), border-color var(--fast) var(--ease);
}
.log-download:hover {
  color: var(--ink);
  border-bottom-color: var(--stroke-strong);
  text-decoration: none;
}

pre#log {
  margin: 0;
  padding: 14px 0 16px;
  min-height: 240px;
  max-height: min(58vh, 560px);
  overflow: auto;
  overscroll-behavior: contain;
  font: 400 12px/1.72 var(--mono);
  font-variant-numeric: tabular-nums slashed-zero;
  color: var(--ink-2);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  scrollbar-width: thin;
  scrollbar-color: rgba(255, 255, 255, .2) transparent;
  /* the gutter rule; `local` so it spans the full scroll height */
  background-image: linear-gradient(to right,
    transparent 0 56px, var(--stroke-hair) 56px 57px, transparent 57px);
  background-attachment: local;
  background-repeat: no-repeat;
}
pre#log::-webkit-scrollbar { width: 10px; height: 10px; }
pre#log::-webkit-scrollbar-track { background: transparent; }
pre#log::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, .16);
  border-radius: 99px;
  border: 3px solid transparent;
  background-clip: content-box;
}
pre#log > div {
  position: relative;
  padding: 0 16px 0 70px;
  transition: background-color 110ms var(--ease);
}
pre#log > div::before {
  /* NOT counter(): the log is a trimmed window, so a CSS counter would
     renumber from 1 whenever a line drops off the top. */
  content: attr(data-n);
  position: absolute;
  left: 8px;
  width: 6ch;
  text-align: right;
  font-size: 10.5px;
  color: var(--ink-4);
  user-select: none;
  -webkit-user-select: none;
}
pre#log > div:last-child { color: var(--ink); }
pre#log > div:hover { background: rgba(255, 255, 255, .04); }

.log-foot {
  display: flex;
  justify-content: flex-end;
  padding: 8px 14px 9px;
  border-top: 1px solid var(--stroke-hair);
  font: 400 11px/1.4 var(--mono);
  color: var(--ink-4);
}


/* ══ FILTER BAR + PAGER ══════════════════════════════════════════════════ */

.filters {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 16px;
}
.filters label { margin: 0; }
.filters input[type="search"], .filters select {
  margin-top: 0;
  padding: 8px 13px;
  font-size: 12.5px;
  border-radius: 999px;
}
.filters select { padding-right: 32px; }
.filter-search input { width: clamp(170px, 26vw, 280px); }

.pager { display: inline-flex; align-items: center; gap: 10px; }
.pager button {
  padding: 6px 12px;
  font: 500 12px/1 var(--sans);
  color: var(--ink-3);
  background: none;
  border: 1px solid transparent;
}
.pager button:hover:not(:disabled) {
  color: var(--ink);
  background: var(--glass-well);
  border-color: var(--stroke-hair);
}
.pager button:disabled { color: var(--ink-4); background: none; border-color: transparent; }


/* ══ FOLLOW-UP BADGES ════════════════════════════════════════════════════ */

.fu-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 10px 3px 8px;
  border-radius: 999px;
  font: 500 11px/1.45 var(--mono);
  white-space: nowrap;
}
.fu-badge::before { content: ""; width: 5px; height: 5px; border-radius: 50%; flex: none; }
.fu-replied {
  color: var(--ok);
  background: color-mix(in srgb, var(--ok) 12%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--ok) 32%, transparent);
}
.fu-replied::before { background: var(--ok); }
.fu-missing {
  color: var(--ink-3);
  background: transparent;
  box-shadow: inset 0 0 0 1px var(--stroke);
}
.fu-missing::before { background: var(--ink-4); }

/* The count classes are applied to the <td> ITSELF on the follow-ups table,
   so they must strip the badge's pill treatment without touching padding —
   the cell owns that, and zeroing it lifts the number off the row baseline. */
.fu-count { font: 500 13px/1.55 var(--mono); font-variant-numeric: tabular-nums; }
td.fu-count, td.fu-count.fu-replied, td.fu-count.fu-missing {
  background: none;
  box-shadow: none;
}
.fu-count.fu-replied { color: var(--ok); }
.fu-count.fu-missing { color: var(--ink-3); }
.fu-count::before { display: none; }

.drip-indicator {
  padding: 5px 12px;
  border-radius: 999px;
  color: var(--info);
  background: color-mix(in srgb, var(--info) 11%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--info) 30%, transparent);
  font: 400 11.5px/1 var(--mono);
  white-space: nowrap;
}


/* ══ LOGIN ═══════════════════════════════════════════════════════════════ */

/* Photograph layer + scrim, behind the slip. The image URL is injected by
   login.html so it can carry a cache-buster. */
body:has(.auth-card)::before {
  content: "";
  position: fixed;
  inset: -30px;
  z-index: -2;
  background: #14100D center / cover no-repeat;
  /* Only a light softening: the slip on top is already a blurred glass
     panel, so the photograph itself can stay legible as a photograph. */
  filter: blur(7px) saturate(1.02);
  transform: scale(1.05);
}
body:has(.auth-card)::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(110% 80% at 50% 34%, rgba(8, 8, 10, .32) 0%, rgba(8, 8, 10, 0) 72%),
    linear-gradient(190deg, rgba(10, 10, 13, .32) 0%, rgba(10, 10, 13, .46) 50%, rgba(10, 10, 13, .68) 100%);
}

.auth-card {
  width: 100%;
  max-width: 392px;
  margin: 12vh auto 0;
  padding: 32px 32px 34px;
  background: rgba(18, 20, 24, .62);
  backdrop-filter: blur(26px) saturate(170%);
  -webkit-backdrop-filter: blur(26px) saturate(170%);
  border: 1px solid var(--stroke-strong);
  border-radius: 22px;
  box-shadow: var(--sheen), 0 34px 70px -24px rgba(0, 0, 0, .78);
}
.auth-mark { width: 26px; height: 26px; color: var(--ink); opacity: .9; display: block; }
.auth-card h1 { margin: 18px 0 22px; font-size: 25px; letter-spacing: -0.03em; }
.auth-card button.primary { width: 100%; margin-top: 4px; padding: 12px; }
.recovery-toggle { margin-top: 10px; }
.recovery-toggle summary { font-size: 12px; }


/* ══ SETTINGS ════════════════════════════════════════════════════════════ */

.two-col-forms {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 18px;
  margin-top: 14px;
}
.two-col-forms > form,
.two-col-forms > .bg-slot {
  padding: 18px;
  background: var(--glass-well);
  border: 1px solid var(--stroke-hair);
  border-radius: var(--r-sm);
}
@media (max-width: 780px) { .two-col-forms { grid-template-columns: 1fr; } }

.totp-enroll {
  display: grid;
  grid-template-columns: minmax(170px, 210px) 1fr;
  gap: 22px;
  align-items: start;
  margin-top: 14px;
}
.totp-qr {
  padding: 12px;
  background: #FFFFFF;   /* a QR needs a white ground to scan reliably */
  border-radius: var(--r-sm);
}
.totp-qr svg { display: block; width: 100%; height: auto; max-width: 190px; margin: 0 auto; }
.totp-manual input { font-family: var(--mono); font-size: 11.5px; }
@media (max-width: 640px) { .totp-enroll { grid-template-columns: 1fr; } }

.recovery-codes {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(148px, 1fr));
  gap: 9px 18px;
  margin: 14px 0 6px;
  padding: 16px 18px;
  list-style: none;
  background: var(--glass-well);
  border: 1px dashed var(--stroke-strong);
  border-radius: var(--r-sm);
  counter-reset: rc;
}
.recovery-codes li {
  counter-increment: rc;
  font: 400 13px/1.4 var(--mono);
  letter-spacing: .04em;
  color: var(--ink);
}
.recovery-codes li::before {
  content: counter(rc, decimal-leading-zero) "  ";
  color: var(--ink-4);
  font-variant-numeric: tabular-nums;
}
.recovery-codes code {
  padding: 0;
  background: none;
  border: 0;
  font: inherit;
  color: inherit;
  user-select: all;
}

.bg-preview {
  margin: 4px 0 12px;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border: 1px solid var(--stroke-hair);
  border-radius: var(--r-sm);
  background: var(--glass-well);
}
.bg-preview img, .bg-preview video {
  display: block;
  width: 100%; height: 100%;
  object-fit: cover;
}
.bg-mode-tabs { margin-bottom: 14px; }

/* colour swatch pills */
.liquid-swatch-row {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  align-items: center;
  margin: 0 0 16px;
}
.liquid-swatch {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 13px 8px 10px;
  margin: 0;
  background: var(--glass-well);
  border: 1px solid var(--stroke);
  border-radius: 999px;
  cursor: pointer;
  line-height: 1;
  transition: background-color var(--fast) var(--ease), border-color var(--fast) var(--ease);
}
.liquid-swatch:hover { background: var(--glass-hover); border-color: var(--stroke-strong); }
.liquid-swatch:focus-within { outline: 2px solid rgba(255, 255, 255, .55); outline-offset: 2px; }
/* The native colour input is the control; it renders differently in every
   engine, so it is made invisible and the dot + hex do the talking. */
.liquid-swatch .sw-input {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  margin: 0; padding: 0;
  border: 0;
  opacity: 0;
  cursor: pointer;
}
.liquid-swatch .sw-dot {
  width: 13px; height: 13px;
  flex: none;
  border-radius: 50%;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .28);
}
.liquid-swatch .sw-name { font: 500 12px/1 var(--sans); color: var(--ink); }
.liquid-swatch .sw-hex  { font: 400 11px/1 var(--mono); color: var(--ink-4); letter-spacing: .02em; }

.sw-reset { padding: 8px 15px; font: 500 12px/1 var(--sans); border-radius: 999px; }


/* ══ BACKGROUND LAYERS ═══════════════════════════════════════════════════ */

/* Uploaded image */
body.has-site-bg::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -2;
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}
.site-bg-video {
  position: fixed;
  inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  z-index: -2;
  pointer-events: none;
}
/* Photographs have unpredictable luminance so they keep a firm scrim. */
body.has-site-bg.site-bg-file::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: linear-gradient(180deg, rgba(10, 11, 14, .52) 0%, rgba(10, 11, 14, .62) 100%);
}
/* The shader gets a much lighter one, weighted to the top: the page title
   and the nav sit directly on the background with nothing behind them, and
   a bright ridge drifting under white text is otherwise unreadable. The
   middle of the frame stays open so the effect is still the effect. */
body.has-site-bg.site-bg-liquid::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: linear-gradient(180deg,
    rgba(8, 9, 12, .58) 0%,
    rgba(8, 9, 12, .30) 22%,
    rgba(8, 9, 12, .20) 55%,
    rgba(8, 9, 12, .34) 100%);
}

/* WebGL liquid — static/liquid.js paints the canvas. The container's inline
   background-color is the no-WebGL fallback. */
.liquid-bg {
  position: fixed;
  inset: 0;
  z-index: -2;
  overflow: hidden;
}
.liquid-canvas { display: block; width: 100%; height: 100%; }

.liquid-preview {
  position: relative;
  inset: auto;
  z-index: 0;
  height: 168px;
  margin-bottom: 14px;
  border: 1px solid var(--stroke-hair);
  border-radius: var(--r-sm);
}


/* ══ RESPONSIVE ══════════════════════════════════════════════════════════ */

/* ── HEADER ON SMALL SCREENS ────────────────────────────────────────────────
   The pill wraps to two rows here. Left alone, the nav row inherits the
   desktop's tight 13px/8px sizing and reads as a thin strip of grey text
   under the wordmark. Below it becomes a proper segmented control: the row
   gets its own well, the links share the width evenly, and the touch target
   grows to something a thumb can actually hit.                              */
@media (max-width: 900px) {
  header { padding: 10px 0 4px; }
  .header {
    flex-wrap: wrap;
    gap: 10px;
    padding: 12px 14px 13px;
    border-radius: 22px;
  }
  .brand { font-size: 14.5px; }
  .brand svg { width: 19px; height: 19px; }

  .main-nav {
    order: 3;
    flex: 1 1 100%;
    margin-left: 0;
    gap: 3px;
    padding: 4px;
    background: var(--glass-well);
    border: 1px solid var(--stroke-hair);
    border-radius: 999px;
  }
  .nav-link {
    flex: 1 1 0;
    justify-content: center;
    display: inline-flex;
    align-items: center;
    padding: 12px 8px;
    font-size: 13px;
    text-align: center;
  }
  /* Log out stays on the top row, opposite the wordmark. */
  header form { order: 2; margin-left: auto; }
  header .link { padding: 8px 12px; font-size: 12.5px; }
}

@media (max-width: 640px) {
  :root { --pad: 18px; --r: 15px; }
  .container { padding: 0 14px; }
  h1 { font-size: 27px; margin-bottom: 20px; }
  .row { flex-direction: column; align-items: stretch; gap: 12px; }
  /* Stacked, the horizontal flex-basis becomes a minimum HEIGHT and the form
     grows enormous empty gaps. Basis auto, no grow. */
  .row > label, .row .grow, .row .port { flex: 0 0 auto; }
  button.primary.big { width: 100%; }
  .filters { gap: 9px; }
  .filter-search { flex: 1 1 100%; }
  .filter-search input { width: 100%; }
  .filters .push { display: none; }
  .pager { margin-left: auto; }
  .auth-card { margin-top: 7vh; padding: 26px 22px 28px; }
  .input-tabs, .bg-mode-tabs { display: flex; width: 100%; }
  .tab-choice { flex: 1 1 auto; justify-content: center; padding: 8px 10px; }

  /* The jobs table stops being a table: seven columns cannot be read on a
     phone, and a sideways scroller hides the numbers you opened the page
     for. Labels come from nth-child, so the markup stays untouched. */
  table.jobs { display: block; min-width: 0; }
  table.jobs thead { display: none; }
  table.jobs tbody { display: block; }
  table.jobs tr {
    display: grid;
    grid-template-columns: 1fr auto;
    align-items: baseline;
    padding: 16px 0 14px 12px;
    border-bottom: 1px solid var(--stroke-hair);
  }
  table.jobs tr:last-child { border-bottom: 0; }
  table.jobs td { padding: 0; border: 0; white-space: normal; }
  table.jobs tbody tr:last-child td { border-bottom: 0; }
  table.jobs td:first-child { font-size: 15px; color: var(--ink); }
  table.jobs td:first-child::before { content: "Job "; color: var(--ink-4); }
  table.jobs td:nth-child(2) { grid-row: 1; grid-column: 2; justify-self: end; }
  table.jobs td:nth-child(n+3):nth-child(-n+6) {
    grid-column: 1 / -1;
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 16px;
    margin-top: 9px;
    padding-bottom: 9px;
    border-bottom: 1px solid var(--stroke-hair);
  }
  table.jobs td:nth-child(n+3):nth-child(-n+6)::before {
    font: 600 10px/1 var(--sans);
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--ink-4);
  }
  table.jobs td:nth-child(3)::before { content: "Total"; }
  table.jobs td:nth-child(4)::before { content: "Done"; }
  table.jobs td:nth-child(5)::before { content: "Success"; }
  table.jobs td:nth-child(6)::before { content: "Started"; }
  table.jobs td:nth-child(6) { border-bottom: 0; }
  table.jobs td:nth-child(7) { grid-column: 1 / -1; justify-self: end; margin-top: 12px; }
  /* the row tick moves off the narrow first cell onto the whole entry */
  table.jobs tbody tr td:first-child { box-shadow: none; }
  table.jobs tbody tr:has(.status-running) { box-shadow: inset 3px 0 0 var(--info); background: none; }
  table.jobs tbody tr:has(.status-failed)  { box-shadow: inset 3px 0 0 var(--bad); }
  table.jobs tbody tr:has(.status-stopped) { box-shadow: inset 3px 0 0 var(--ink-3); }

  pre#log > div { padding-left: 64px; }
  pre#log { background-image: linear-gradient(to right,
    transparent 0 51px, var(--stroke-hair) 51px 52px, transparent 52px); }
  pre#log > div::before { left: 5px; }
  .terminal-title { display: none; }
  .log-controls { gap: 12px; }
}

/* Touch devices never get hover, so nothing may be hover-only. */
@media (hover: none) {
  .preset-list button.link.danger { color: #FFB3A8; }
}


/* ══ MOTION DISCIPLINE ═══════════════════════════════════════════════════ */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  .site-bg-video { display: none; }
}
