/* One stylesheet, no framework. Four screens do not need a build step. */

:root {
  --bg: #0f1115;
  --panel: #171a21;
  --line: #262b36;
  --ink: #e7e9ee;
  --muted: #939aab;
  --accent: #6ea8fe;
  --live: #ff5c5c;
  --good: #57d9a3;
  --radius: 10px;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: 16px/1.55 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
        "Helvetica Neue", Arial, sans-serif;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

main {
  width: 100%;
  max-width: 46rem;
  margin: 0 auto;
  padding: 2rem 1.25rem 4rem;
  flex: 1;
}

/* 46rem is a comfortable measure for reading, which is why it is the
   default. The settings matrix is not read left to right, it is scanned, and
   squeezing it into a prose column is what forced a scrollbar. */
main.page-settings { max-width: 68rem; }

/* --- bar --- */

.bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.9rem 1.25rem;
  border-bottom: 1px solid var(--line);
  background: var(--panel);
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  color: var(--ink);
  text-decoration: none;
  font-weight: 600;
  letter-spacing: -0.01em;
}

.dot {
  width: 0.6rem;
  height: 0.6rem;
  border-radius: 50%;
  background: var(--live);
  box-shadow: 0 0 0 4px rgba(255, 92, 92, 0.15);
}

nav { display: flex; align-items: center; gap: 1.1rem; }
nav a { color: var(--muted); text-decoration: none; }
nav a:hover, nav a.here { color: var(--ink); }

/* --- type --- */

h1 { font-size: 1.6rem; letter-spacing: -0.02em; margin: 0 0 0.6rem; }
h2 { font-size: 1.15rem; letter-spacing: -0.01em; margin: 2.5rem 0 0.8rem; }
section + section { margin-top: 1rem; }

.lede { color: var(--muted); font-size: 1.05rem; margin: 0 0 1.6rem; }
.fine { color: var(--muted); font-size: 0.85rem; margin: 0.6rem 0 0; }
.empty { color: var(--muted); }
code { background: #0b0d11; padding: 0.1rem 0.35rem; border-radius: 4px; font-size: 0.85em; }

/* --- forms --- */

.card {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.25rem;
}

label {
  display: block;
  font-size: 0.88rem;
  color: var(--muted);
  margin: 0 0 0.35rem;
}

label.check {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  color: var(--ink);
  font-size: 0.95rem;
  margin: 1rem 0 0;
}

input[type="email"], input[type="text"], input[type="number"], input:not([type]), select,
textarea {
  width: 100%;
  padding: 0.6rem 0.7rem;
  background: #0b0d11;
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: 8px;
  font: inherit;
}

/* A textarea is inline by default, which put the passphrase box and its
   button side by side on one cramped line. Every other field here is its own
   block and this one is no different. Horizontal dragging is disallowed
   because widening it past the card is never what somebody meant. */
textarea {
  display: block;
  resize: vertical;
}

input:focus, select:focus, textarea:focus, button:focus {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

label + .fine { margin-top: -0.1rem; }
input + label, select + .fine + label, .fine + label { margin-top: 1rem; }

button {
  margin-top: 1rem;
  padding: 0.6rem 1rem;
  background: var(--accent);
  color: #0b0d11;
  border: 0;
  border-radius: 8px;
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}

button:hover { filter: brightness(1.08); }

button.link {
  margin: 0;
  padding: 0;
  background: none;
  color: var(--muted);
  font-weight: 400;
  cursor: pointer;
}
button.link:hover { color: var(--ink); text-decoration: underline; }
button.quiet { font-size: 0.85rem; }

form.inline { display: inline; }
form.inline.right { margin-left: auto; }

.signin, .add { max-width: 30rem; }
.row.static { display: flex; gap: 0.75rem; margin: 0 0 1rem; }
.row.static .label { color: var(--muted); font-size: 0.88rem; }

/* --- notices --- */

.notice {
  padding: 0.7rem 0.9rem;
  border-radius: 8px;
  border: 1px solid var(--line);
  margin: 0 0 1.25rem;
}
.notice.bad { border-color: #63323a; background: #2a1a1d; }
.notice.good { border-color: #2f5f4c; background: #16261f; color: var(--good); }

/* --- streams --- */

.streams, .creators { list-style: none; margin: 0; padding: 0; }

.stream {
  display: flex;
  gap: 1rem;
  align-items: baseline;
  padding: 0.85rem 0;
  border-bottom: 1px solid var(--line);
}

.stream .when { flex: 0 0 8.5rem; }

.badge {
  display: inline-block;
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  padding: 0.2rem 0.5rem;
  border-radius: 999px;
  border: 1px solid var(--line);
  color: var(--muted);
  white-space: nowrap;
}

.badge.live {
  border-color: transparent;
  background: var(--live);
  color: #fff;
  font-weight: 700;
}

.what { display: flex; flex-direction: column; }
.title { color: var(--ink); text-decoration: none; font-weight: 500; }
.title:hover { text-decoration: underline; }
.creator { color: var(--muted); font-size: 0.88rem; }

/* A card each, rather than rows divided by hairlines. A followed creator is
   a thing with a picture, a name and its own settings tucked underneath, and
   a bottom border made all of that read as one undifferentiated table. */
/* Wider gaps than a list of plain rows would need: each of these is now a
   block with its own artwork, and 0.6rem made two of them read as one. */
.creators { display: flex; flex-direction: column; gap: 1rem; margin-top: 1rem; }
.creators li {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.85rem 1rem;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  /* The banner is positioned against this and clipped by it, so the image
     cannot square off the card's rounded corners. */
  position: relative;
  overflow: hidden;
}
.creators li:hover { border-color: #333a49; }

/* --- the channel banner --- */

/* Sized in the flow rather than absolutely, so the header below it is pushed
   down instead of sitting on top of an image that may be any aspect ratio.
   YouTube banners are very wide and very short; 8rem shows the middle band
   without the card becoming a poster. */
.banner {
  margin: -0.85rem -1rem 0.75rem;
  height: 8rem;
  overflow: hidden;
  background: #0b0d11;
  position: relative;
}
.banner img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Banners put the interesting part in the middle horizontally and are
     letterboxed by the safe area vertically, so centre is the right crop. */
  object-position: center;
  display: block;
}
/* A wash at the bottom, so the name below never has to compete with whatever
   the channel put in the lower edge of its artwork. */
.banner::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 3.5rem;
  background: linear-gradient(to bottom, transparent, var(--panel));
}

.blurb {
  color: var(--muted);
  font-size: 0.9rem;
  line-height: 1.45;
  margin: 0.5rem 0 0;
}
.creators a { color: var(--ink); text-decoration: none; }
.creators a:hover { text-decoration: underline; }
.handle { color: var(--muted); font-size: 0.85rem; }

/* Fixed size and `flex: none` so a long channel name cannot squeeze the
   picture into an ellipse -- the usual way avatars in a flex row go wrong. */
.face {
  flex: none;
  width: 80px;
  height: 80px;
  border-radius: 50%;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #0b0d11;
  border: 1px solid var(--line);
}
.face:hover { text-decoration: none; }
/* Overlapping the banner is what makes this read as a channel header rather
   than as an image with a row under it. Only when there is a banner to
   overlap -- otherwise it would sit too high in a plain card.

   `align-self` is load-bearing and not obvious. The row is `align-items:
   center`, and centring works on the *margin* box: a negative top margin
   there just makes the box shorter and leaves the picture where it was.
   Aligning this one item to the start pins its margin box to the top of the
   row, and the negative margin then genuinely lifts the border box out of
   the row and over the banner. */
.banner + .who .face {
  align-self: flex-start;
  margin-top: -2.6rem;
  border-width: 3px;
  border-color: var(--panel);
  background: var(--panel);
}
.face img { width: 100%; height: 100%; object-fit: cover; display: block; }
.face .initials {
  color: var(--muted);
  font-size: 1.25rem;
  font-weight: 600;
  letter-spacing: 0.02em;
}

/* The name column takes the slack, and `min-width: 0` is what lets a very
   long channel name ellipsize instead of pushing Unfollow off the card. */
.named { display: flex; flex-direction: column; gap: 0.15rem; min-width: 0; }
.named .cname { font-weight: 600; }
.named .cname, .named .handle { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* --- footer --- */

footer {
  border-top: 1px solid var(--line);
  padding: 1.25rem;
  text-align: center;
}
footer p { margin: 0; color: var(--muted); font-size: 0.85rem; }

@media (max-width: 34rem) {
  .stream { flex-direction: column; gap: 0.3rem; }
  .stream .when { flex: none; }
}

/* --- google --- */

.google {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  padding: 0.65rem 1rem;
  background: #fff;
  color: #1f1f1f;
  border-radius: 8px;
  text-decoration: none;
  font-weight: 500;
}
.google:hover { filter: brightness(0.95); }

.or {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  color: var(--muted);
  font-size: 0.8rem;
  margin: 1.1rem 0 0;
}
.or::before, .or::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--line);
}

/* --- a passphrase account --- */

/* Shown once, and usually copied out by hand onto paper. Monospace so that
   the words are unambiguous, large enough to read across a desk, and
   selectable as one block so a double-click does not take a single word. */
.passphrase .secret {
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Menlo, Consolas, monospace;
  font-size: 1.25rem;
  line-height: 1.7;
  letter-spacing: 0.01em;
  word-spacing: 0.35em;
  margin: 0 0 0.75rem;
  padding: 0.9rem 1rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--sunken, rgba(127, 127, 127, 0.08));
  user-select: all;
  overflow-wrap: break-word;
}

/* Monospace here for the same reason as the block above: this is where six
   words get typed back in off a piece of paper, and l/1 and O/0 have to be
   possible to tell apart. Tall enough for two lines, because a passphrase
   wrapped by a mail client is exactly the case the textarea exists for. */
#passphrase {
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Menlo, Consolas, monospace;
  font-size: 0.95rem;
  min-height: 3.6rem;
}

.anon h2 {
  font-size: 1rem;
  margin: 0 0 0.4rem;
}

button.secondary {
  background: transparent;
  color: inherit;
  border: 1px solid var(--line);
}
button.secondary:hover { filter: brightness(0.97); }

/* --- watch state --- */

.watching {
  color: var(--muted);
  font-size: 0.85rem;
  margin: 0 0 0.5rem;
}
.watching.partial { color: #e0b341; }

.watch {
  font-size: 0.72rem;
  letter-spacing: 0.04em;
  padding: 0.15rem 0.45rem;
  border-radius: 999px;
  border: 1px solid #63563a;
  background: #241f14;
  color: #e0b341;
  white-space: nowrap;
  cursor: help;
}

/* --- notification settings --- */

/* Each channel is a block inside the one form, spaced far enough apart that
   nobody mistakes the Discord webhook box for part of the email block. */
.channel {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.4rem 1.25rem 1.5rem;
  margin: 0 0 1.75rem;
}

.channel legend {
  padding: 0 0.5rem;
  margin-left: -0.5rem;
  font-size: 1.05rem;
  font-weight: 600;
  letter-spacing: -0.01em;
}

.channel .sent-to { color: var(--muted); font-size: 0.88rem; margin: 0 0 1rem; }
.fine.intro { margin: 0 0 1.25rem; }

.setting { padding: 1.1rem 0 0; }
.setting + .setting { margin-top: 1.1rem; border-top: 1px solid var(--line); }
.setting .ask { margin: 0 0 0.6rem; font-size: 0.95rem; }

.opts { display: flex; gap: 0.6rem; flex-wrap: wrap; }

/* A radio you can actually hit: the whole pill is the target. */
.opt {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0;
  padding: 0.45rem 0.85rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: #0b0d11;
  color: var(--ink);
  font-size: 0.9rem;
  cursor: pointer;
}
.opt:hover { border-color: var(--muted); }
.opt.on { border-color: var(--accent); background: rgba(110, 168, 254, 0.12); }
/* The .on class is what the server rendered; :has is what keeps the pill
   right after a click, since there is no JavaScript to move the class. */
.opt:has(input:checked) { border-color: var(--accent); background: rgba(110, 168, 254, 0.12); }
.opt:not(:has(input:checked)) { border-color: var(--line); background: #0b0d11; }
.opt input { accent-color: var(--accent); margin: 0; }
.opt em { color: var(--muted); font-style: normal; font-size: 0.85em; }

.countdown {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin-top: 0.9rem;
}
.countdown .lead { color: var(--muted); font-size: 0.9rem; }
.countdown select { width: auto; min-width: 8rem; }

.save { display: flex; align-items: center; gap: 0.9rem; }
.save .fine { margin: 1rem 0 0; }

/* --- per-creator settings --- */

.creators li { flex-direction: column; align-items: stretch; gap: 0.55rem; }
.creators li.muted .named .cname { color: var(--muted); }
.creators li.muted .face { opacity: 0.55; }

.who { display: flex; align-items: center; gap: 0.8rem; }

.per-creator > summary {
  color: var(--muted);
  font-size: 0.85rem;
  cursor: pointer;
  padding: 0.15rem 0;
  list-style-position: outside;
}
.per-creator > summary:hover { color: var(--ink); }
.per-creator .summary { color: var(--ink); }

.creator-settings {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: #0b0d11;
  padding: 1rem 1.1rem 1.2rem;
  margin: 0.6rem 0 0.4rem;
}

.field {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: wrap;
  padding: 0.4rem 0;
}
.field .ask { color: var(--muted); font-size: 0.9rem; flex: 1 1 12rem; }
.field select { width: auto; min-width: 10rem; }

button.small { margin-top: 0.9rem; padding: 0.4rem 0.9rem; font-size: 0.9rem; }

@media (max-width: 34rem) {
  .field { flex-direction: column; align-items: stretch; gap: 0.35rem; }
  .field select { width: 100%; }
  .countdown select { width: 100%; }
}

/* --- the settings matrix --- */

/* This used to sit in an `overflow-x: auto` wrapper, on the reasoning that
   narrow screens should scroll rather than crush the columns. The reasoning
   held when there were eight columns; there are eleven now, and the table
   overflowed its container at *every* width -- so the page always ended in a
   horizontal scrollbar and a column cut in half, on a desktop monitor.
   Sideways scrolling inside a page is unpleasant even when it is deliberate,
   and this was not.

   Two changes instead. The settings page is allowed to be wider than the
   reading column the rest of the site uses, because a matrix is not prose.
   And below the width where eleven columns genuinely cannot fit, each row
   becomes a stack of labelled lines -- the labels come from `data-label` in
   the template, so there is exactly one copy of the markup. Nothing scrolls
   sideways at any width. */

.matrix {
  width: 100%;
  border-collapse: collapse;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
}

.matrix th, .matrix td {
  padding: 0.55rem 0.4rem;
  text-align: left;
  border-bottom: 1px solid var(--line);
  vertical-align: middle;
}
.matrix tbody tr:last-child th, .matrix tbody tr:last-child td { border-bottom: 0; }

.matrix thead th { font-size: 0.8rem; }
.matrix thead th {
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  color: var(--muted);
  text-transform: uppercase;
  white-space: nowrap;
}

.matrix .channel-name {
  font-weight: 600;
  white-space: nowrap;
  color: var(--ink);
}
.matrix .channel-name label { display: inline; color: var(--muted); font-weight: 400; }
.matrix .to { display: block; color: var(--muted); font-size: 0.8rem; font-weight: 400; }
/* Eleven of these sit side by side, so every millimetre of minimum width is
   multiplied by eleven. 5.5rem each was what pushed the table past its
   container; the widest option any of them holds is "10 min". */
.matrix select { width: auto; min-width: 4.4rem; padding: 0.4rem 0.35rem; font-size: 0.92rem; }
.matrix .total { color: var(--muted); font-size: 0.88rem; white-space: nowrap; }
.matrix .pick { text-align: center; }
.matrix .try { text-align: center; white-space: nowrap; }
.matrix .try button { margin: 0; padding: 0.35rem 0.6rem; font-size: 0.85rem; }
.matrix .pick input { accent-color: var(--accent); }

/* The "send to" line spans the row under the channel it belongs to. */

/* Below this, eleven columns cannot fit honestly, so stop pretending they
   are columns. Each row becomes a labelled stack. `display: block` on table
   parts drops their table semantics, so the headings that were conveying
   meaning visually are restored per cell from data-label. */
@media (max-width: 70rem) {
  .matrix, .matrix thead, .matrix tbody, .matrix tr, .matrix th, .matrix td {
    display: block;
    width: auto;
  }

  /* The header row is the one thing with no place in a stacked layout: its
     labels now live on each cell. Hidden rather than removed so screen
     readers keep the association. */
  .matrix thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }

  .matrix { border: 0; background: none; }

  .matrix tbody tr {
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: 0.4rem 0.9rem 0.7rem;
    margin: 0 0 0.7rem;
  }

  .matrix th, .matrix td { border: 0; padding: 0.45rem 0; }

  .matrix .channel-name {
    font-size: 1rem;
    padding-top: 0.6rem;
    border-bottom: 1px solid var(--line);
    margin-bottom: 0.3rem;
  }

  /* Label left, control right, on one line each. */
  .matrix td[data-label] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
  }
  .matrix td[data-label]::before {
    content: attr(data-label);
    color: var(--muted);
    font-size: 0.88rem;
  }
  .matrix .pick { justify-content: space-between; }

  /* The destination is a URL and needs the whole width, so it is the one
     cell that stacks its label above rather than beside. */
  .matrix tr.where td {
    display: block;
    padding-top: 0.2rem;
  }
  .matrix tr.where td::before { content: none; }
}

.matrix tr.where td { padding-top: 0; }
.matrix tr.where .fine { margin-top: 0.4rem; }

.tag {
  margin-left: 0.4rem;
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  padding: 0.1rem 0.4rem;
  border-radius: 999px;
  background: rgba(110, 168, 254, 0.15);
  color: var(--accent);
}

.row-actions {
  margin: 1.5rem 0 0;
  padding: 1rem 1.1rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--panel);
}
.row-actions select { width: auto; min-width: 16rem; }

/* --- previously: a grid of past broadcasts --- */

.grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
  gap: 1.25rem 1rem;
}

.tile { display: flex; flex-direction: column; gap: 0.25rem; min-width: 0; }

.tile .shot {
  position: relative;
  display: block;
  aspect-ratio: 16 / 9;
  border-radius: 8px;
  overflow: hidden;
  background: #0b0d11;
  border: 1px solid var(--line);
}
.tile .shot img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Platforms whose stills cannot be derived from an id get a mark rather than
   a broken image icon. */
.tile .noshot {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  color: var(--line);
  font-size: 2rem;
}

.tile .length {
  position: absolute;
  right: 0.35rem;
  bottom: 0.35rem;
  padding: 0.1rem 0.35rem;
  border-radius: 4px;
  background: rgba(0, 0, 0, 0.78);
  color: #fff;
  font-size: 0.72rem;
  font-variant-numeric: tabular-nums;
}

.tile .title {
  margin-top: 0.35rem;
  font-size: 0.92rem;
  line-height: 1.3;
  /* Two lines, then ellipsis: ragged tile heights make a grid look broken. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.tile .creator { color: var(--muted); font-size: 0.85rem; text-decoration: none; }
.tile .creator:hover { color: var(--ink); text-decoration: underline; }
.tile .when { margin: 0; }

.pager {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-top: 2rem;
  padding-top: 1rem;
  border-top: 1px solid var(--line);
}
.pager a { color: var(--accent); text-decoration: none; }
.pager a:hover { text-decoration: underline; }
.pager .spent { color: var(--line); }
.pager .fine { margin: 0; }

/* --- deleting an account --- */

/* Muted until opened. This is not a thing to draw the eye on a page people
   visit to change a reminder interval. */
.danger { margin-top: 3rem; }
.danger > details > summary {
  color: var(--muted);
  font-size: 0.9rem;
  cursor: pointer;
  padding: 0.3rem 0;
}
.danger > details > summary:hover { color: var(--live); }
.danger > details[open] > summary { color: var(--live); margin-bottom: 0.75rem; }
.danger .card { border-color: #4a2530; max-width: 34rem; }

button.destructive {
  background: var(--live);
  color: #12070a;
}
