/* Setmore Watcher UI.
 *
 * Plain CSS, no build step and no framework: this is a handful of server
 * rendered pages, and a toolchain would be more moving parts than the styling
 * it produces. Respects the system colour scheme.
 */

:root {
  color-scheme: light dark;
  --bg: #f6f7f9;
  --surface: #ffffff;
  --border: #e2e5ea;
  --text: #14181f;
  --muted: #667085;
  --accent: #0b6bcb;
  --ok: #16794c;
  --ok-bg: #e7f6ee;
  --warn: #92400e;
  --warn-bg: #fdf4e3;
  --bad: #b42318;
  --bad-bg: #fdeceb;
  --radius: 10px;
  /* Inputs sit a shade below their card so a form reads as a set of fields
     rather than as text loose on a panel. */
  --field: #fbfcfd;
  --border-strong: #c3c9d4;
  --accent-ring: rgba(11, 107, 203, 0.18);
  --chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2 4.5 6 8.5 10 4.5' fill='none' stroke='%23667085' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #12151a;
    --surface: #1a1f27;
    --border: #2a3039;
    --text: #e8ecf2;
    --muted: #98a2b3;
    --accent: #5aa8f0;
    --ok: #6ee7b7; --ok-bg: #10281f;
    --warn: #fcd34d; --warn-bg: #2b2109;
    --bad: #fca5a5; --bad-bg: #2a1414;
    --field: #151a21;
    --border-strong: #3d4655;
    --accent-ring: rgba(90, 168, 240, 0.22);
    --chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2 4.5 6 8.5 10 4.5' fill='none' stroke='%2398a2b3' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  }
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 15px/1.55 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}

/* --- chrome ------------------------------------------------------------ */

.topbar {
  display: flex; align-items: center; gap: 24px;
  padding: 14px 24px;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}
.brand { font-weight: 650; text-decoration: none; color: var(--text); }
.topbar nav { display: flex; gap: 18px; margin-left: auto; }
.topbar nav a { color: var(--muted); text-decoration: none; font-size: 14px; }
.topbar nav a:hover, .topbar nav a.active { color: var(--accent); }

/* Sign-out is a POST (a GET would be CSRF-able), but should still read as a
   nav link rather than a button. */
.signout { display: inline; margin: 0; }
button.linklike {
  background: none; border: none; padding: 0;
  font: inherit; font-size: 14px; color: var(--muted); cursor: pointer;
}
button.linklike:hover { color: var(--accent); filter: none; }

main { max-width: 940px; margin: 0 auto; padding: 28px 24px 64px; }
footer {
  max-width: 940px; margin: 0 auto; padding: 0 24px 40px;
  color: var(--muted); font-size: 13px;
}

h1 { font-size: 21px; margin: 0 0 6px; }
h2 { font-size: 16px; margin: 0 0 12px; }
a { color: var(--accent); }
code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 13px; }
pre { background: var(--bg); border: 1px solid var(--border); border-radius: 8px;
      padding: 12px; overflow-x: auto; }

/* --- surfaces ---------------------------------------------------------- */

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 20px;
  margin-bottom: 20px;
}
.narrow { max-width: 380px; width: 100%; }
.centred { display: flex; justify-content: center; padding-top: 40px; }

.banner { border-radius: var(--radius); padding: 14px 16px; margin-bottom: 20px;
          border: 1px solid transparent; }
.banner p { margin: 4px 0 0; }
.banner-ok { background: var(--ok-bg); border-color: var(--ok); color: var(--ok); }
.banner-stale { background: var(--warn-bg); border-color: var(--warn); color: var(--warn); }
.banner-bad { background: var(--bad-bg); border-color: var(--bad); color: var(--bad); }

.flash { border-radius: 8px; padding: 10px 14px; margin-bottom: 16px; font-size: 14px; }
.flash-error { background: var(--bad-bg); color: var(--bad); }
.flash-ok { background: var(--ok-bg); color: var(--ok); }

.hint { color: var(--muted); font-size: 13px; margin: 6px 0; }
.muted { color: var(--muted); }
.empty { text-align: center; padding: 48px 0; color: var(--muted); }
.empty-inline { color: var(--muted); font-size: 14px; }

/* --- slots ------------------------------------------------------------- */

.watch { margin-bottom: 32px; }
.meta { color: var(--muted); font-size: 13px; margin: 0 0 16px; }

.days { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 14px; }
.day {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 14px;
}
.day h2 { font-size: 13px; text-transform: uppercase; letter-spacing: .04em;
          color: var(--muted); margin: 0 0 10px; }
.times { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 6px; }
.times li {
  background: var(--bg); border: 1px solid var(--border); border-radius: 6px;
  padding: 4px 9px; font-size: 14px; font-variant-numeric: tabular-nums;
}

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

table { width: 100%; border-collapse: collapse; font-size: 14px; }
th, td { text-align: left; padding: 9px 10px; border-bottom: 1px solid var(--border); }
th { color: var(--muted); font-weight: 550; font-size: 12px;
     text-transform: uppercase; letter-spacing: .04em; }
tr.selected { background: var(--ok-bg); }
td.wrap { max-width: 320px; word-break: break-word; color: var(--muted); font-size: 13px; }

.tag { display: inline-block; padding: 2px 8px; border-radius: 999px; font-size: 12px; }
.tag-on { background: var(--ok-bg); color: var(--ok); }
.tag-off { background: var(--bad-bg); color: var(--bad); }
.tag-new { background: var(--warn-bg); color: var(--warn); }

.stats { display: flex; gap: 40px; }
.stats .stat { display: block; font-size: 22px; font-weight: 600; }
.stats .label { color: var(--muted); font-size: 13px; }

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

form.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 14px;
            align-items: end; }
form.grid .span, form.grid fieldset.span { grid-column: 1 / -1; }
/* A submit button stretched to a 220px grid column reads as another field.
   Its own row, at its own width, ends the form instead. */
form.grid > button[type="submit"] { grid-column: 1 / -1; justify-self: start; }
/* Matches the div that wraps several single-button POST forms as well as a
   form that is itself one row - each of those forms is a block, so without
   this they stack and overlap the grid form above them. */
.row { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.card form.grid + .row { margin-top: 18px; padding-top: 18px;
                         border-top: 1px solid var(--border); }
.row > form { margin: 0; }
.grow { flex: 1; min-width: 240px; }

label { display: block; font-size: 13px; color: var(--muted); }
label.inline { display: inline-flex; align-items: center; gap: 5px; margin-right: 14px; color: var(--text); }

input, select {
  width: 100%; margin-top: 4px; padding: 9px 11px;
  border: 1px solid var(--border); border-radius: 8px;
  background: var(--field); color: var(--text); font-size: 14px;
  transition: border-color .12s ease, background .12s ease, box-shadow .12s ease;
}
input:hover:not(:disabled), select:hover:not(:disabled) { border-color: var(--border-strong); }
input:focus, select:focus {
  outline: none; border-color: var(--accent);
  background: var(--surface);
  box-shadow: 0 0 0 3px var(--accent-ring);
}
input:disabled, select:disabled { color: var(--muted); cursor: not-allowed; opacity: .7; }
input::placeholder { color: var(--muted); }

/* Native select chrome is a different control on every platform and looks
   pasted in next to the text inputs. Stripping it and drawing one chevron
   keeps the row visually level; `appearance: none` is what removes the arrow,
   so the background image below is the only one the user ever sees. */
select {
  appearance: none;
  padding-right: 34px;
  background-image: var(--chevron);
  background-repeat: no-repeat;
  background-position: right 11px center;
  background-size: 12px;
  cursor: pointer;
}
/* The dropdown list itself is drawn by the OS and inherits almost nothing, so
   these two are the whole of what can be said about it. Without them a dark
   theme gets black text on a black list in Chrome. */
select option { background: var(--surface); color: var(--text); }
select optgroup { background: var(--surface); color: var(--muted); font-style: normal; }

/* Time dropdowns hold 96 identically shaped values; tabular figures stop the
   column from shivering as the selection changes. */
select[name="time_from"], select[name="time_to"],
select[name="anchor_date"] { font-variant-numeric: tabular-nums; }

input[type="checkbox"] {
  width: 16px; height: 16px; margin: 0;
  accent-color: var(--accent); cursor: pointer;
}

fieldset { border: 1px solid var(--border); border-radius: 10px; padding: 10px 12px 12px;
           margin: 0; min-width: 0; }
legend { color: var(--muted); font-size: 12px; padding: 0 6px; }

/* --- weekday chips ------------------------------------------------------ */
/* Seven checkboxes in a row read as a list to skim; the same seven as chips
   read as a week to click. The checkbox stays in the DOM and keeps its name
   and value, so the form posts exactly what it did before and the control
   still works from the keyboard. */
.chip-row { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.chip {
  position: relative;
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 52px; padding: 6px 12px;
  border: 1px solid var(--border); border-radius: 999px;
  background: var(--field); color: var(--muted);
  font-size: 13px; cursor: pointer; user-select: none;
  transition: background .12s ease, color .12s ease, border-color .12s ease;
}
.chip:hover { border-color: var(--border-strong); color: var(--text); }
.chip input { position: absolute; opacity: 0; width: 0; height: 0; }
.chip:has(input:checked) {
  background: var(--accent); border-color: var(--accent);
  color: #fff; font-weight: 550;
}
/* Focus lives on the hidden input, so the ring has to be drawn by the label. */
.chip:has(input:focus-visible) { box-shadow: 0 0 0 3px var(--accent-ring); }
.chips .chip-all { margin-left: auto; align-self: center; }

button {
  padding: 8px 16px; border-radius: 7px; border: 1px solid var(--accent);
  background: var(--accent); color: #fff; font-size: 14px; cursor: pointer;
}
button:hover { filter: brightness(1.08); }
/* Row actions are outlined chips, not filled buttons: they sit inside a
   table and a row of solid accent blocks would out-shout the data. Edit
   and Delete share the same geometry so they line up as a pair. */
button.danger, button.quiet {
  background: transparent; border-color: var(--border);
  padding: 4px 10px; line-height: 1.4;
}
button.danger { color: var(--bad); }
button.quiet { color: var(--muted); }
button.quiet:hover { color: var(--accent); border-color: var(--accent); filter: none; }
button.danger:hover { border-color: var(--bad); filter: none; }

details { margin-top: 16px; }
summary { cursor: pointer; color: var(--accent); font-size: 14px; margin-bottom: 12px; }
.discovered { margin-top: 16px; }

/* --- inline editors ----------------------------------------------------- */
/* An edit form lives in a row of the table it edits, so the fields sit
   directly under the values they change. Hidden rows use the `hidden`
   attribute, which the toggle script flips. */
tr.editor > td { background: var(--card-alt, rgba(127, 127, 127, 0.06)); }
tr.editor form.grid { margin: 4px 0; }
/* The actions cell stays a real table cell. `display: flex` would take it out
   of the table's layout — the row no longer stretches it, so the buttons ride
   at the top instead of on the row's centre line with the values. On a desktop
   every row is one line tall and that is invisible; on a phone the columns wrap
   and the pair visibly floats above everything else in the row. Inline-block
   buttons in a plain cell inherit the same vertical centring as the rest. */
/* Right-aligned, because the actions column is the table's last and takes
   whatever width the data columns leave over — which differs per table. Left
   aligned, the pair starts at that arbitrary edge: on the config page the
   watches' buttons stop ~50px short of the card while the rules' nearly touch
   it, so two tables one above the other disagree about where a row ends.
   Anchoring to the right edge is the one reference every table shares. */
td.actions { white-space: nowrap; text-align: right; }
/* The delete button is wrapped in a POST form; without this the form
   is a block and its button drops out of line with Edit. */
td.actions form { display: contents; }
/* Sits with the values rather than on their baseline, so an Edit/Delete pair
   stays centred next to a cell that has wrapped onto several lines. */
td.actions button { vertical-align: middle; }
/* The gap the flex row used to provide, less the collapsed whitespace the
   markup already puts between the two buttons. */
td.actions form > button { margin-left: 6px; }


/* --- mobile ------------------------------------------------------------ */
/* Phones get their own information hierarchy rather than a squeezed desktop
   layout. Everything here is breakpoint-scoped so the desktop UI above stays
   byte-for-byte the same in the cascade. */
@media (max-width: 680px) {
  body { font-size: 16px; }

  .topbar {
    display: block;
    padding: 12px 0 0;
    overflow: hidden;
  }
  .brand {
    display: block;
    padding: 0 16px 10px;
    font-size: 17px;
  }
  .topbar nav {
    gap: 4px;
    margin: 0;
    padding: 0 12px 10px;
    overflow-x: auto;
    overscroll-behavior-inline: contain;
    scrollbar-width: none;
    scroll-snap-type: x proximity;
  }
  .topbar nav::-webkit-scrollbar { display: none; }
  .topbar nav a, .topbar button.linklike {
    flex: 0 0 auto;
    min-height: 0;
    padding: 7px 9px;
    border-radius: 999px;
    scroll-snap-align: start;
  }
  .topbar nav a.active { background: var(--accent-ring); }
  .signout { flex: 0 0 auto; }

  main { padding: 20px 12px 48px; }
  footer { padding: 0 16px 32px; }
  .centred { padding-top: 20px; }

  .card {
    padding: 16px;
    margin-bottom: 14px;
    border-radius: 12px;
  }
  .banner { padding: 12px 14px; margin-bottom: 14px; }
  .empty { padding: 32px 8px; }

  .watch { margin-bottom: 24px; }
  .days { grid-template-columns: 1fr; gap: 10px; }
  .day { padding: 12px; }
  .times { gap: 8px; }
  .times li { padding: 7px 11px; }

  .stats {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 18px 12px;
  }
  .stats .stat { font-size: 21px; }

  form.grid { grid-template-columns: minmax(0, 1fr); gap: 12px; }
  form.grid > button[type="submit"] { width: 100%; }
  .row { align-items: stretch; }
  .grow { flex-basis: 100%; min-width: 0; width: 100%; }
  form.row > button, .row > form, .row > form button { width: 100%; }
  input:not([type="checkbox"]), select, button { min-height: 44px; }
  input:not([type="checkbox"]), select { font-size: 16px; }
  label.inline { min-height: 44px; margin-right: 0; }
  details { margin-top: 20px; }
  summary { padding: 8px 0; }

  .chip-row {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 8px;
  }
  .chip { min-width: 0; padding: 8px 4px; }
  .chips .chip-all { width: 100%; margin-left: 0; }

  /* Data tables become labeled records. Horizontal scrolling is a poor fit
     for short, related values and makes row actions easy to lose off-screen. */
  .responsive-table,
  .responsive-table tbody,
  .responsive-table tr,
  .responsive-table td {
    display: block;
    width: 100%;
  }
  .responsive-table thead {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
  }
  .responsive-table tbody {
    display: grid;
    gap: 12px;
  }
  .responsive-table tr {
    padding: 10px 12px;
    border: 1px solid var(--border);
    border-radius: 10px;
    background: var(--surface);
  }
  .responsive-table tr[hidden] { display: none; }
  .responsive-table td {
    display: grid;
    grid-template-columns: minmax(82px, .8fr) minmax(0, 1.4fr);
    gap: 12px;
    max-width: none;
    padding: 7px 0;
    border-bottom: 1px solid var(--border);
    text-align: right;
    white-space: normal;
    overflow-wrap: anywhere;
  }
  .responsive-table td::before {
    content: attr(data-label);
    color: var(--muted);
    font-size: 11px;
    font-weight: 550;
    letter-spacing: .04em;
    text-align: left;
    text-transform: uppercase;
  }
  .responsive-table td:last-child { border-bottom: 0; }
  /* Actions are the final labeled field of the record, not a footer between
     records. That keeps the controls visibly inside the rule they modify. */
  .responsive-table td.actions {
    display: grid;
    grid-template-columns: minmax(82px, .8fr) minmax(0, 1.4fr);
    gap: 12px;
    margin: 0;
    padding: 7px 0 0;
    background: none;
    text-align: right;
  }
  .responsive-table td.actions::before { display: block; }
  .responsive-table .action-buttons {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    min-width: 0;
  }
  .responsive-table td.actions button { flex: 1; min-width: 0; max-width: 110px; }
  .responsive-table td.actions form > button { margin-left: 0; }
  .responsive-table tr.editor {
    margin-top: -12px;
    padding: 0;
    border-top: 0;
    border-radius: 0 0 10px 10px;
  }
  .responsive-table tr.editor > td {
    display: block;
    padding: 14px;
    text-align: left;
  }
  .responsive-table tr.editor > td::before { display: none; }
  code { overflow-wrap: anywhere; }
}
