/* Dark, dense, no framework. Phone-friendly. */
:root, :root[data-theme="dark"] {
  --bg: #0c0c0e;
  --panel: #16171a;
  --panel-2: #1d1f23;
  --border: #2a2c31;
  --fg: #e8e8ea;
  --muted: #8a8d94;
  --accent: #6ea8fe;
  --ok: #4ade80;
  --warn: #fbbf24;
  --err: #ef4444;
  --idle: #6b7280;
}
:root[data-theme="light"] {
  --bg: #f5f5f7;        /* cool, soft light-grey base — not stark white */
  --panel: #ffffff;     /* cards stay white but stand out vs the bg */
  --panel-2: #ece9f7;   /* soft lavender for highlights / selected rows */
  --border: #e6e6ea;    /* almost-invisible dividers */
  --fg: #1f1f22;        /* near-black, slightly warm */
  --muted: #8e8e94;     /* mid-grey secondary text */
  --accent: #7c5cff;    /* Roon-style violet */
  --ok: #16a34a;
  --warn: #d97706;
  --err: #dc2626;
  --idle: #b8b8be;
}
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; background: var(--bg); color: var(--fg); }
body {
  font: 15px/1.45 -apple-system, BlinkMacSystemFont, "SF Pro Text", system-ui, sans-serif;
  -webkit-font-smoothing: antialiased;
  padding: max(12px, env(safe-area-inset-top)) max(12px, env(safe-area-inset-right))
           max(12px, env(safe-area-inset-bottom)) max(12px, env(safe-area-inset-left));
}
header {
  display: flex; align-items: center; justify-content: space-between;
  padding-bottom: 10px; margin-bottom: 16px; border-bottom: 1px solid var(--border);
  flex-wrap: wrap; gap: 8px;
}
h1 { margin: 0; font-size: 20px; font-weight: 600; letter-spacing: -0.01em; }
.tabs { display: flex; gap: 4px; flex-wrap: wrap; }
.tab {
  background: transparent; color: var(--muted); border: none;
  padding: 8px 14px; border-radius: 6px; cursor: pointer;
  /* "greens.fyi" is the page brand, so it gets the larger size of the
     pair (the UPCOMING DATES h2 picks up the smaller end below). */
  font: inherit; font-size: 16px; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.06em;
}

/* ── Calendar tab ─────────────────────────────────────────────────
   Monthly grid: 7-column CSS grid for weekday headers + 6 weeks of
   day cells. Today's cell gets an accent background and a pill on
   the day number; days from adjacent months are dimmed; days with
   events stack colored chips under the day number. */
.cal-section { margin-top: 16px; }
.cal-head {
  display: flex; align-items: center; gap: 12px;
  margin-bottom: 12px;
}
.cal-month-label {
  margin: 0; flex: 1;
  font-size: 18px; font-weight: 600; color: var(--fg);
  letter-spacing: 0.01em; text-transform: none;
}
.cal-nav {
  background: transparent; color: var(--muted);
  border: 1px solid var(--border); border-radius: 6px;
  width: 32px; height: 32px;
  font-size: 18px; font-weight: 500;
  cursor: pointer; display: inline-flex;
  align-items: center; justify-content: center;
  transition: color 120ms ease, border-color 120ms ease;
}
.cal-nav:hover { color: var(--accent); border-color: var(--accent); }
.cal-today-btn {
  background: transparent; color: var(--muted);
  border: 1px solid var(--border); border-radius: 6px;
  padding: 6px 12px; font-size: 12px; font-weight: 500;
  letter-spacing: 0.04em; text-transform: uppercase;
  cursor: pointer;
  transition: color 120ms ease, border-color 120ms ease;
}
.cal-today-btn:hover { color: var(--accent); border-color: var(--accent); }
.cal-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 1px;
  background: var(--border);
  border: 1px solid var(--border);
  border-radius: 8px;
  overflow: hidden;
}
.cal-cell {
  background: var(--panel);
  min-height: 96px;
  padding: 6px 8px;
  display: flex; flex-direction: column; gap: 3px;
  font-size: 12px;
}
.cal-cell.cal-weekday-header {
  min-height: auto; padding: 8px 8px 7px;
  background: var(--bg);
  color: var(--muted);
  font-size: 11px; font-weight: 600;
  letter-spacing: 0.08em; text-transform: uppercase;
  text-align: center;
  align-items: center;
}
.cal-day-num {
  font-size: 13px; color: var(--muted); font-weight: 500;
  font-variant-numeric: tabular-nums;
}
.cal-cell.cal-other-month {
  opacity: 0.45;
  background: var(--bg);
}
.cal-cell.cal-today {
  background: color-mix(in oklab, var(--accent) 14%, var(--panel));
}
.cal-cell.cal-today .cal-day-num {
  /* Today's number renders as a filled accent pill so it stays
     unmistakable even at a glance. */
  background: var(--accent); color: #fff;
  border-radius: 999px;
  padding: 1px 8px;
  align-self: flex-start;
}
.cal-event {
  font-size: 11px; line-height: 1.25;
  padding: 2px 6px;
  border-radius: 4px;
  background: color-mix(in oklab, var(--accent) 18%, var(--panel));
  color: var(--fg);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  cursor: default;
}
@media (max-width: 720px) {
  /* Tight phone cells; event names truncate but stay tappable via title */
  .cal-cell { min-height: 56px; padding: 4px; }
  .cal-day-num { font-size: 12px; }
  .cal-event { font-size: 10px; padding: 1px 4px; }
  .cal-cell.cal-weekday-header { font-size: 9px; padding: 6px 2px; }
  .cal-month-label { font-size: 15px; }
}

/* ── Header info strip — same row as the "greens.fyi" tab ────────────
   Compact inline date / time / weather row that sits between the tab
   nav (left) and the meta buttons (right) in the page header. */
.header-info {
  display: flex; gap: 18px; align-items: baseline;
  font-size: 13px; color: var(--muted);
  flex: 1 1 auto; min-width: 0; flex-wrap: wrap;
  margin: 0 16px;
}
.topbar-date  { color: var(--fg); font-weight: 600; }
.topbar-clock { font-variant-numeric: tabular-nums; }
.weather-cell {
  display: inline-flex; gap: 6px; align-items: baseline;
}
.weather-cell .weather-icon  { font-size: 14px; }
.weather-cell .weather-loc   { font-size: 12px; opacity: 0.8; }
.weather-cell .weather-temp  { color: var(--fg); font-weight: 600;
                               font-variant-numeric: tabular-nums; }
.weather-cell .weather-range { opacity: 0.75;
                               font-variant-numeric: tabular-nums; }
@media (max-width: 720px) {
  /* Drop weather on narrow viewports — keeps the header from wrapping
     into three lines. Date + clock still show. */
  .header-info .weather-cell { display: none; }
}

/* Footer row beneath the task board — +Add panel + History as twin
   right-aligned chips. Same chip rule lives further down. */
.board-footer {
  display: flex; gap: 8px; justify-content: flex-end;
  margin-top: 12px;
}
.tab:hover { color: var(--fg); background: var(--panel); }
.tab.active { color: var(--fg); background: var(--panel-2); }
.tab-pane { display: none; }
.tab-pane.active { display: block; }

/* Public-domain (todo.markpytlik.com): only Life/Work/Career are exposed. */
html[data-public] .tab[data-tab="para"],
html[data-public] .tab[data-tab="inbox"],
html[data-public] .tab[data-tab="backups"],
html[data-public] .tab[data-tab="code"],
html[data-public] .tab-pane[data-pane="para"],
html[data-public] .tab-pane[data-pane="inbox"],
html[data-public] .tab-pane[data-pane="backups"],
html[data-public] .tab-pane[data-pane="code"] {
  display: none !important;
}
h2 { font-size: 13px; text-transform: uppercase; letter-spacing: 0.08em;
     color: var(--muted); margin: 24px 0 10px; font-weight: 600; }
.meta { display: flex; gap: 12px; align-items: center; color: var(--muted); font-size: 13px; }
button {
  background: var(--panel-2); color: var(--fg); border: 1px solid var(--border);
  padding: 6px 12px; border-radius: 6px; cursor: pointer; font: inherit; font-size: 13px;
}
button:hover { background: var(--border); }
button:disabled { opacity: 0.5; cursor: wait; }
#theme-toggle {
  width: 32px; padding: 6px 0; text-align: center;
  font-size: 16px; line-height: 1;
}

/* ── Activity log modal ─────────────────────────────────────── */
.modal-backdrop {
  position: fixed; inset: 0; z-index: 200;
  background: rgba(0, 0, 0, 0.55);
  display: flex; align-items: center; justify-content: center;
  padding: 24px;
}
.modal {
  background: var(--panel); border: 1px solid var(--border);
  border-radius: 12px; padding: 20px 24px;
  max-width: 640px; width: 100%;
  max-height: 80vh; display: flex; flex-direction: column;
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.4);
}
.modal-head {
  display: flex; justify-content: space-between; align-items: center;
  margin-bottom: 14px; padding-bottom: 10px;
  border-bottom: 1px solid var(--border);
}
.modal-head h2 { margin: 0; font-size: 15px; font-weight: 600; color: var(--fg); }
.modal-close {
  background: transparent; border: none; color: var(--muted);
  cursor: pointer; padding: 4px 8px; font-size: 14px; line-height: 1;
}
.modal-close:hover { color: var(--err); background: transparent; }
.modal-body { overflow: auto; flex: 1; }

/* ── Add Section modal ─────────────────────────────────────── */
.add-section-body {
  display: flex; flex-direction: column; gap: 8px;
}
.field-label {
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--muted); font-weight: 600; margin-top: 6px;
}
.section-title-in {
  width: 100%; padding: 10px 12px;
  background: var(--bg); color: var(--fg);
  border: 1px solid var(--border); border-radius: 8px;
  font-size: 15px; outline: none;
  transition: border-color 120ms ease;
}
.section-title-in:focus { border-color: var(--accent); }
.toggle-row {
  display: flex; gap: 8px;
}
.toggle-btn {
  flex: 1; padding: 10px 14px;
  background: var(--bg); color: var(--muted);
  border: 1px solid var(--border); border-radius: 8px;
  font-size: 13px; font-weight: 500; cursor: pointer;
  transition: all 120ms ease;
}
.toggle-btn:hover { color: var(--fg); border-color: var(--muted); }
.toggle-btn.active {
  background: var(--accent); color: #0a0a0a;
  border-color: var(--accent);
}
.field-help {
  margin: 4px 0 0; font-size: 12px; color: var(--muted); line-height: 1.4;
}
.modal-error {
  color: var(--err, #ef4444); font-size: 12px; min-height: 0;
}
.modal-error:not(:empty) { padding: 4px 0; }
.modal-actions {
  display: flex; gap: 8px; justify-content: flex-end;
  padding-top: 12px; margin-top: 8px;
  border-top: 1px solid var(--border);
}
.btn-primary, .btn-secondary {
  padding: 9px 18px; border-radius: 7px; font-size: 13px; font-weight: 600;
  cursor: pointer; border: 1px solid transparent;
  transition: all 120ms ease;
}
.btn-primary {
  background: var(--accent); color: #0a0a0a; border-color: var(--accent);
}
.btn-primary:hover { filter: brightness(1.1); }
.btn-secondary {
  background: transparent; color: var(--muted); border-color: var(--border);
}
.btn-secondary:hover { color: var(--fg); border-color: var(--muted); }
.activity-list {
  list-style: none; padding: 0; margin: 0;
  font-size: 13px; display: flex; flex-direction: column; gap: 4px;
}
.activity-list li {
  display: flex; gap: 10px; align-items: baseline; color: var(--fg);
  padding: 4px 0; border-bottom: 1px solid var(--border);
}
.activity-list li:last-child { border-bottom: none; }
.activity-list .when {
  color: var(--muted); font-size: 11px; min-width: 130px;
  font-variant-numeric: tabular-nums;
}
.activity-list .ev   { width: 16px; flex-shrink: 0; text-align: center; font-weight: 600; }
.activity-list .ev.completed { color: var(--ok); }
.activity-list .ev.uncompleted { color: var(--warn); }
.activity-list .ev.created { color: var(--accent); }
.activity-list .ev.deleted { color: var(--err); }
.activity-list .ev.moved { color: var(--muted); }
.activity-list .name { color: var(--fg); }

.grid {
  display: grid; gap: 10px;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
}
/* Watcher tiles get full width so long filenames in recent-files / log
   tails are readable without truncation. */
.grid.wide {
  grid-template-columns: 1fr;
}
.row { display: flex; gap: 8px; flex-wrap: wrap; }

/* Script cards (Run a Script section) */
#scripts {
  display: flex; flex-direction: column; gap: 8px;
}
.script-card {
  background: var(--panel); border: 1px solid var(--border);
  border-radius: 8px; padding: 10px 12px;
}
.script-card .top {
  display: flex; justify-content: space-between; align-items: center;
  gap: 12px;
}
.script-card .name { font-weight: 600; color: var(--fg); font-size: 14px; }
.script-card .desc {
  margin: 6px 0 0; color: var(--muted); font-size: 12px; line-height: 1.5;
}
.script-card .run-btn {
  flex-shrink: 0; padding: 5px 12px; font-size: 12px;
}

.card {
  background: var(--panel); border: 1px solid var(--border); border-radius: 8px;
  padding: 14px 16px;
}
.card .top {
  display: flex; align-items: center; justify-content: space-between;
  gap: 8px; margin-bottom: 6px;
}
.card .name { font-weight: 600; }
.card .sub { color: var(--muted); font-size: 12px; }
.card a { color: var(--accent); text-decoration: none; }
.card a:hover { text-decoration: underline; }
/* Download cards (the whole card IS an <a>) — accent the name to match
   site-card links; keep size/date muted. */
a.card { color: var(--fg); text-decoration: none; }
a.card .name { color: var(--accent); }
a.card .sub { color: var(--muted); }
a.card:hover .name { text-decoration: underline; }

/* ── INBOX Sorter (own tab) ────────────────────────────────── */
.inbox-controls {
  display: flex; gap: 8px; align-items: center;
  margin-bottom: 12px;
}
.inbox-search-input {
  flex: 1;
  padding: 8px 12px; font: inherit; font-size: 14px;
  background: var(--bg); color: var(--fg);
  border: 1px solid var(--border); border-radius: 6px;
  outline: none;
}
.inbox-search-input:focus { border-color: var(--accent); }

/* Undo bar — small pills under the search */
.undo-bar {
  display: flex; flex-wrap: wrap; gap: 6px; align-items: center;
  margin-bottom: 12px; padding: 8px 10px;
  background: var(--panel-2); border: 1px solid var(--border);
  border-radius: 6px;
}
.undo-bar .undo-label {
  color: var(--muted); font-size: 11px;
  text-transform: uppercase; letter-spacing: 0.06em; margin-right: 4px;
}
.undo-pill {
  background: transparent; color: var(--fg);
  border: 1px solid var(--border); border-radius: 4px;
  padding: 4px 10px; font-size: 12px; cursor: pointer;
}
.undo-pill:hover { background: var(--accent); color: var(--bg); border-color: var(--accent); }

/* Make the destination dropdown use a monospace font so the indented
   nested-folder labels line up cleanly. */
.dest-select {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
}

/* (existing inbox styles continue below) */
.inbox-summary {
  display: flex; justify-content: space-between; align-items: baseline;
  margin-bottom: 10px;
}
.inbox-summary .count { font-size: 13px; color: var(--muted); }
.inbox-refresh {
  font-size: 12px; padding: 4px 10px;
  background: transparent; border: 1px solid var(--border);
  color: var(--muted); cursor: pointer; border-radius: 4px;
}
.inbox-refresh:hover { color: var(--accent); border-color: var(--accent); }

.inbox-group { padding: 10px 14px; margin-bottom: 6px; }
.inbox-group.collapsed { padding: 8px 14px; }
.inbox-group.collapsed .inbox-group-header {
  border-bottom: none; padding-bottom: 0; margin-bottom: 0;
}
.inbox-group-header {
  display: flex; align-items: center; gap: 10px;
  padding-bottom: 8px; border-bottom: 1px solid var(--border);
  margin-bottom: 6px;
  cursor: pointer; user-select: none;
}
.inbox-group-header:hover .group-key { color: var(--fg); }
.inbox-group-header .group-caret {
  color: var(--muted); font-size: 11px; width: 10px; text-align: center;
  transition: transform 120ms ease;
}
.inbox-group-header .all-cb { accent-color: var(--accent); cursor: pointer; }
.inbox-group-header .group-key {
  font-weight: 600; font-size: 14px; color: var(--accent);
  flex: 1;
  transition: color 120ms ease;
}
.inbox-group-header .group-count { color: var(--muted); font-size: 12px; }

.inbox-files {
  max-height: 320px; overflow-y: auto;
  display: flex; flex-direction: column; gap: 2px;
  margin-bottom: 10px;
}
.inbox-file {
  display: flex; align-items: center; gap: 10px;
  padding: 4px 6px; border-radius: 4px;
  font-size: 13px;
}
.inbox-file:hover { background: var(--panel-2); }
.inbox-file .file-cb { accent-color: var(--accent); cursor: pointer; }
.inbox-file .file-name {
  flex: 1; min-width: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  color: var(--fg);
}
.inbox-file .file-meta { color: var(--idle); font-size: 11px; flex-shrink: 0; }

.inbox-group-actions {
  display: flex; gap: 8px; align-items: center;
  padding-top: 6px; border-top: 1px solid var(--border);
}
.dest-picker {
  flex: 1; display: flex; flex-direction: column; gap: 4px;
}
.dest-picker .dest-filter {
  padding: 5px 8px; font: inherit; font-size: 12px;
  background: var(--bg); color: var(--fg);
  border: 1px solid var(--border); border-radius: 4px;
  outline: none;
}
.dest-picker .dest-filter:focus { border-color: var(--accent); }
.dest-select {
  width: 100%; padding: 6px 8px; font: inherit; font-size: 13px;
  background: var(--bg); color: var(--fg);
  border: 1px solid var(--border); border-radius: 4px;
}
.inbox-move-btn {
  background: var(--accent); color: white;
  border: none; padding: 6px 14px; border-radius: 4px;
  font-weight: 600; font-size: 13px; cursor: pointer;
  flex-shrink: 0;
}
.inbox-move-btn:hover { filter: brightness(1.1); }
.inbox-move-btn:disabled { opacity: 0.5; cursor: wait; }

.term-creds {
  display: flex; flex-direction: column; gap: 4px;
  font-size: 12px;
}
.term-creds .creds-row { display: none; gap: 8px; align-items: baseline; }
.term-creds.revealed .creds-row { display: flex; }
.term-creds .creds-row .k { color: var(--muted); width: 70px; }
.term-creds .creds-row code {
  background: var(--bg); border: 1px solid var(--border);
  padding: 2px 6px; border-radius: 3px;
  font: 12px ui-monospace, "SF Mono", Menlo, monospace;
  color: var(--fg);
}
.creds-reveal {
  background: transparent; color: var(--muted); border: none;
  padding: 4px 0; font-size: 12px; cursor: pointer; text-align: left;
}
.creds-reveal:hover { color: var(--accent); background: transparent; }

/* ── Mobile responsive pass ─────────────────────────────────── */
@media (max-width: 720px) {
  body { padding: 10px; font-size: 14px; }
  /* Header stack: tabs above, meta below — gives tabs full row */
  header {
    flex-direction: column; align-items: stretch; gap: 10px;
    padding-bottom: 8px;
  }
  .meta { justify-content: flex-end; gap: 8px; font-size: 12px; }
  /* Tabs: horizontal scroll if too many to fit, slightly bigger tap target */
  .tabs {
    overflow-x: auto; flex-wrap: nowrap;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  .tabs::-webkit-scrollbar { display: none; }
  .tab {
    flex-shrink: 0; padding: 10px 12px; font-size: 12px;
    letter-spacing: 0.04em;
  }
  /* Section headings — smaller margins, slightly smaller type */
  h2 { margin: 18px 0 8px; font-size: 12px; }

  /* Watchers go to single column on mobile */
  .grid.wide { grid-template-columns: 1fr; }

  /* Modal — fill the screen, smaller padding */
  .modal-backdrop { padding: 10px; }
  .modal { padding: 14px 16px; max-height: 90vh; border-radius: 10px; }
  .modal-head h2 { font-size: 14px; }

  /* Undo toast — wider, sits flush at the bottom */
  .undo-toast {
    bottom: 14px; left: 14px; right: 14px;
    transform: translateY(20px);
    width: auto; max-width: none;
  }
  .undo-toast.visible { transform: translateY(0); }

  /* Recent files grid — stack each row vertically (when | orig→neu) so
     long filenames don't force horizontal scroll */
  .recent {
    grid-template-columns: 1fr;
    font-size: 10px;
  }
  .recent .recent-row { display: block; padding: 4px 0; border-bottom: 1px solid var(--border); }
  .recent .recent-row:last-child { border-bottom: none; }
  .recent .when { display: block; color: var(--idle); margin-bottom: 2px; }
  .recent .arrow { display: none; }   /* implicit by line break */
  .recent .orig, .recent .neu { display: inline-block; max-width: 100%; }

  /* Site cards stack 1-up (already do via .grid breakpoint, just ensure) */
  .grid { grid-template-columns: 1fr; }

  /* Day Summary table — pad less */
  .cross-summary { padding: 10px 12px; }
  .cross-summary table td { padding: 3px 4px; font-size: 12px; }

  /* Word of the Day stack on mobile */
  .word-of-day { flex-direction: column; align-items: flex-start; padding: 10px 12px; }

  /* Terminal section — stack button + creds */
  .term-actions { flex-direction: column; gap: 10px; }
  .term-open-btn { width: 100%; }
}

/* Extra-small phones (≤375): tighten further */
@media (max-width: 380px) {
  body { padding: 8px; }
  h1 { font-size: 18px; }
  .tab { padding: 9px 10px; font-size: 11px; }
  .task-totals { font-size: 11px; }
}
.card .watch-line {
  font: 13px/1.4 ui-monospace, "SF Mono", Menlo, monospace;
  color: var(--accent);
  margin: 4px 0 8px;
  word-break: break-all;
}
.card .watch-line a { color: var(--accent); }
.card .desc-para {
  color: var(--muted); font-size: 12.5px; line-height: 1.5;
  margin: 6px 0 0;
}
.card .site-name {
  display: flex; align-items: center; gap: 8px;
  font-weight: 600; font-size: 14px;
}
.card .favicon {
  width: 16px; height: 16px; border-radius: 3px;
  background: var(--panel-2); flex-shrink: 0; object-fit: cover;
}
.card .site-meta {
  display: grid; grid-template-columns: auto 1fr; gap: 4px 12px;
  font-size: 12px; color: var(--muted); margin-top: 8px;
}
.card .site-meta .k { color: var(--idle); }
.card .site-meta .v { color: var(--fg); }
/* Cloudflare analytics rows: same grid as .site-meta but with a top border
   and slightly muted color so it reads as a separate "live stats" section. */
.card .site-analytics {
  margin-top: 6px; padding-top: 6px;
  border-top: 1px dashed var(--border);
}
.card .site-analytics .v { color: var(--accent); font-variant-numeric: tabular-nums; }
/* When the period labels are links (the site has an analytics_url), style
   them like regular .k but with an underline-on-hover so it's discoverable
   without making them shout. */
.card .site-analytics a.analytics-link {
  text-decoration: none;
  cursor: pointer;
  transition: color 120ms ease;
}
.card .site-analytics a.analytics-link:hover {
  color: var(--accent);
  text-decoration: underline; text-underline-offset: 2px;
}
.card .site-links {
  margin-top: 8px; padding-top: 8px;
  border-top: 1px solid var(--border);
  display: flex; flex-wrap: wrap;
  /* No gap: separator pseudo-elements provide the visual breathing room. */
  font-size: 12px;
}
.card .site-links a {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  color: var(--accent);
  padding: 0 10px;
}
.card .site-links a:first-child { padding-left: 0; }
.card .site-links a:last-child  { padding-right: 0; }
/* Vertical bar between adjacent links — only between, never trailing. */
.card .site-links a + a {
  border-left: 1px solid var(--border);
}
/* Script-trigger links: small refresh glyph distinguishes "fires a server
   action" from "navigates somewhere else". */
.card .site-links a.script-link::before {
  content: "↻ "; opacity: 0.7;
}
.card .site-links a.script-link {
  cursor: pointer;
}
.card .site-links a.script-link:hover {
  filter: brightness(1.2);
}
.up-dot { background: var(--ok); }
.down-dot { background: var(--err); }

.dot {
  display: inline-block; width: 8px; height: 8px; border-radius: 50%;
  background: var(--idle); flex-shrink: 0;
}
.dot.running  { background: var(--ok); box-shadow: 0 0 6px var(--ok); }
.dot.idle     { background: var(--idle); }
.dot.error    { background: var(--err); }
.dot.unloaded { background: var(--warn); }
.dot.toggleable { cursor: pointer; transition: transform 0.15s ease; }
.dot.toggleable:hover { transform: scale(1.6); }
.dot.toggling { opacity: 0.4; cursor: wait; }
.host-suffix { color: var(--idle); font-weight: 500;
               text-transform: none; letter-spacing: normal;
               margin-left: 6px; font-size: 11px; }
.two-col {
  display: grid; gap: 24px;
  grid-template-columns: 1fr 1fr;
}
@media (max-width: 720px) {
  .two-col { grid-template-columns: 1fr; }
}

/* Downloads row sits directly under script pills as a continuation of the
   same section, not a separate stacked block. Small top margin keeps it
   visually grouped while still distinguishable. */
.downloads-row { margin-top: 8px; }
.downloads-row:empty { margin-top: 0; }

/* ── Collapsible panels (Run a Script, Legacy Scripts) ─────────────── */
.scripts-section, .legacy-section { margin-top: 16px; }
.legacy-section { margin-top: 24px; }
.scripts-section details, .legacy-section details {
  border: 1px solid var(--border); border-radius: 8px;
  background: var(--panel);
  padding: 4px 16px 4px 16px;
  transition: padding 120ms ease;
}
.scripts-section details[open], .legacy-section details[open] {
  padding-bottom: 16px;
}
.scripts-section summary, .legacy-section summary {
  /* Mimic the h2 elsewhere — same size/weight — but with a disclosure caret
     and clickable affordance. */
  list-style: none;
  cursor: pointer; user-select: none;
  padding: 12px 0;
  font-size: 15px; font-weight: 600; color: var(--fg);
  display: flex; align-items: center; gap: 10px;
}
.scripts-section summary::-webkit-details-marker,
.legacy-section summary::-webkit-details-marker { display: none; }
.scripts-section summary::before, .legacy-section summary::before {
  /* Arrow 150% larger than the previous 11px — now 17px so it reads as a
     proper disclosure control rather than a tiny dot. */
  content: "▸";
  color: var(--muted); font-size: 17px;
  transition: transform 120ms ease;
  display: inline-block;
  line-height: 1; width: 12px;
}
.scripts-section details[open] > summary::before,
.legacy-section details[open] > summary::before {
  transform: rotate(90deg);
}
.scripts-section summary:hover, .legacy-section summary:hover { color: var(--accent); }
.scripts-section summary:hover::before, .legacy-section summary:hover::before {
  color: var(--accent);
}
.legacy-section .desc-para {
  margin: 0 0 12px; color: var(--muted); font-size: 12px;
}

/* ── Top Pages panel ───────────────────────────────────────────────── */
.top-pages-section h2 .top-pages-window {
  margin-left: 8px; font-size: 11px; font-weight: 500;
  color: var(--muted); letter-spacing: 0.04em; text-transform: uppercase;
}
.top-pages-block { margin-bottom: 10px; }
.top-pages-block:last-child { margin-bottom: 0; }
.top-pages-site {
  font-size: 12px; font-weight: 600; color: var(--accent);
  margin-bottom: 4px;
}
.top-pages-list {
  list-style: decimal; padding-left: 26px;
  margin: 0; color: var(--fg); font-size: 13px;
  display: flex; flex-direction: column; gap: 2px;
}
.top-pages-list li {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px; padding: 3px 0;
  border-bottom: 1px solid var(--border);
}
.top-pages-list li:last-child { border-bottom: none; }
.top-pages-list .page-path {
  flex: 1; min-width: 0;
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  color: var(--accent); text-decoration: none;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.top-pages-list a.page-path:hover { text-decoration: underline; }
.top-pages-list .page-count {
  color: var(--muted); font-size: 12px; flex-shrink: 0;
  font-variant-numeric: tabular-nums;
}

/* ── Loading skeletons (shown until first /api/status returns) ─
   Uses a "shimmer" gradient that slides across each bar — far more
   visibly animated than an opacity pulse. */
.card.skeleton { pointer-events: none; }
.skel-bar {
  height: 12px; border-radius: 4px; margin: 8px 0;
  background: linear-gradient(
    90deg,
    var(--border) 0%,
    var(--panel-2) 50%,
    var(--border) 100%
  );
  background-size: 200% 100%;
  animation: skel-shimmer 1.3s linear infinite;
}
.skel-bar.w70 { width: 70%; }
.skel-bar.w50 { width: 50%; }
.skel-bar.w35 { width: 35%; }
@keyframes skel-shimmer {
  0%   { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}
/* Respect reduced-motion users — fall back to gentle opacity pulse */
@media (prefers-reduced-motion: reduce) {
  .skel-bar {
    background: var(--border);
    animation: skel-pulse 2s ease-in-out infinite;
  }
  @keyframes skel-pulse {
    0%, 100% { opacity: 0.5; }
    50%      { opacity: 0.9; }
  }
}

/* ── Tasks board ─────────────────────────────────────────────── */
.tasks-board {
  display: grid; gap: 12px;
  /* Fixed 4 columns. `minmax(0, 1fr)` (not bare `1fr`) is required so that
     wide content inside a column — like a long task name being typed into
     the add-row input — doesn't push the track wider than its share. With
     bare `1fr` the implicit `min-width: auto` lets intrinsic content win.
     Narrower viewports collapse to 2, then 1. */
  grid-template-columns: repeat(4, minmax(0, 1fr));
}
@media (max-width: 1100px) {
  .tasks-board { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 600px) {
  .tasks-board { grid-template-columns: minmax(0, 1fr); }
}
.tasks-col {
  background: var(--panel); border: 1px solid var(--border); border-radius: 8px;
  padding: 12px; display: flex; flex-direction: column; gap: 4px;
  min-height: 280px;
}
.tasks-col.drop-target { background: var(--panel-2); border-color: var(--accent); }
/* Wide column — spans two grid tracks (~2× the width of a normal column).
   Set on custom columns via `wide: true` in their _columns metadata. At
   narrower viewports the grid template collapses to fewer columns, so
   span 2 naturally degrades (capped at the row width). */
.tasks-col.wide { grid-column: span 2; }
@media (max-width: 600px) {
  /* At single-column layout, span 2 would extend the implicit grid;
     unset so it just takes the one available column. */
  .tasks-col.wide { grid-column: auto; }
}
.tasks-col h3 {
  margin: 0 0 6px; font-size: 12px; text-transform: uppercase;
  letter-spacing: 0.06em; color: var(--accent); font-weight: 600;
}
/* Custom-column header row: editable title + small delete button. */
.col-head-row {
  display: flex; align-items: center; gap: 6px; margin-bottom: 6px;
}
.col-head-row h3 { margin: 0; flex: 1; min-width: 0; }
.tasks-col h3.editable {
  outline: none; padding: 2px 4px; border-radius: 4px;
  cursor: text; transition: background 120ms ease, box-shadow 120ms ease;
}
.tasks-col h3.editable:hover { background: var(--panel-2); }
.tasks-col h3.editable:focus {
  background: var(--panel-2); cursor: text;
  box-shadow: inset 0 0 0 1px var(--accent);
}
.col-delete {
  flex-shrink: 0;
  width: 22px; height: 22px;
  background: transparent; color: var(--idle);
  border: none; border-radius: 4px;
  cursor: pointer; font-size: 18px; line-height: 1;
  display: inline-flex; align-items: center; justify-content: center;
  opacity: 0; transition: opacity 120ms ease, background 120ms ease, color 120ms ease;
}
.tasks-col:hover .col-delete { opacity: 1; }
.col-delete:hover { background: var(--panel-2); color: var(--error); }

/* Forces user-defined custom columns onto a fresh grid row, so they always
   appear "below" the built-in 4 regardless of how wide the viewport is. */
.board-row-break {
  grid-column: 1 / -1;
  height: 0; padding: 0; margin: 0; border: 0;
}

/* "+ Add panel" + "History" — twin chips in the board-footer row.
   Both use the unified chip style rule further down. No extra margin
   here since the .board-footer parent positions them. */
.add-section-btn { width: fit-content; }
/* (Mobile UX used to hide this chip — kept visible now that the unified
   columns model means adding a panel just appends a new row, which is
   perfectly usable on phones too. The greens.fyi mobile pass at the
   bottom of this file tightens its padding for touch.) */
.task {
  display: flex; align-items: center; gap: 8px;
  padding: 6px 6px; border-radius: 5px;
  background: var(--bg); border: 1px solid transparent;
  font-size: 13px;
}
.task:hover { border-color: var(--border); }
/* Live drag feedback — animated transitions so panels and tasks visibly
   shift to make room as you drag over them, instead of jumping to a
   final position only on drop. */
.task {
  transition:
    margin-top    160ms ease,
    margin-bottom 160ms ease,
    opacity       140ms ease,
    transform     140ms ease;
}
.task.dragging {
  opacity: 0.4;
  transform: scale(0.97);
}
/* Drop slot: instead of just a thin line, ANIMATE a gap that opens up
   above/below the hovered task — the dragged item will land in that
   gap. A faint colored bar reinforces the position. */
.task.drop-before {
  margin-top: 38px;
  box-shadow: 0 -34px 0 -30px var(--accent);   /* a 4px bar at -32px */
}
.task.drop-after {
  margin-bottom: 38px;
  box-shadow: 0 34px 0 -30px var(--accent);
}
.task.done .name, .task.done .min { text-decoration: line-through; color: var(--idle); }

/* dual_state status pill — small inline label that toggles between two
   labels ("to apply" / "applied"). Goes between checkbox and name. */
.task .dual-state-pill {
  flex-shrink: 0;
  padding: 1px 7px; border-radius: 10px;
  font-size: 10px; font-weight: 600;
  letter-spacing: 0.04em; text-transform: uppercase;
  white-space: nowrap;
}
.task .dual-state-pill.off {
  /* Bright amber — same visual weight as the green "applied" pill, so the
     two states feel like equal-rank statuses rather than "default vs. done". */
  color: #0a0a0a;
  background: var(--warn);
  border: 1px solid var(--warn);
}
.task .dual-state-pill.on {
  color: #0a0a0a;
  background: var(--accent);
  border: 1px solid var(--accent);
}
/* When the column is in "hide done" mode, completed tasks disappear */
.tasks-col.hide-done .task.done { display: none; }

/* Click-to-highlight: subtle accent border + tinted background for the
   currently-highlighted task. Cursor stays "default" on inputs (still
   editable as normal) but turns "pointer" on the row's empty space. */
.task { cursor: pointer; }
.task input, .task button { cursor: auto; }
.task.highlighted {
  border-color: var(--accent);
  background: var(--panel-2);
  box-shadow: inset 3px 0 0 0 var(--accent);
}
.to-here-badge {
  padding: 2px 8px;
  font-size: 11px; font-weight: 600; color: var(--accent);
  background: var(--bg); border: 1px solid var(--accent);
  border-radius: 10px; white-space: nowrap;
  flex-shrink: 0;
}
.completed-toggle {
  /* Footer divider: a 1px line above to visually separate the done-toggle
     from the live task list (and from the totals box, when present). */
  margin-top: 8px; padding: 8px 6px 0;
  border-top: 1px solid var(--border);
  background: transparent; border-left: none; border-right: none; border-bottom: none;
  color: var(--muted); font-size: 11px;
  cursor: pointer; text-align: left;
  display: flex; align-items: center; gap: 6px;
  letter-spacing: 0.04em;
}
.completed-toggle:hover { color: var(--accent); }
.completed-toggle .check { color: var(--ok); font-weight: 600; }
.task .grip {
  cursor: grab; color: var(--idle); padding: 0 2px; user-select: none;
  font-size: 16px; line-height: 1;
}
.task .grip:active { cursor: grabbing; }
/* Round task checkboxes. Unchecked: hollow ring in the column's accent
   color. Checked: filled with that same accent + a soft glow. The
   transitions use a slight overshoot easing so clicking gets a tactile
   "pop." `:active` scales down a little for the press, then the curve
   bounces back past 1.0 on release. */
.task input[type="checkbox"] {
  appearance: none; -webkit-appearance: none;
  width: 14px; height: 14px; border-radius: 50%;
  background: transparent;
  border: 2px solid var(--col-accent, var(--idle));
  margin: 0; cursor: pointer; flex-shrink: 0;
  transition:
    transform 180ms cubic-bezier(0.34, 1.56, 0.64, 1),
    background 140ms ease,
    box-shadow 140ms ease;
}
.task input[type="checkbox"]:hover  { transform: scale(1.15); }
.task input[type="checkbox"]:active { transform: scale(0.85); }
.task input[type="checkbox"]:checked {
  background: var(--col-accent, var(--ok));
  border-color: var(--col-accent, var(--ok));
  box-shadow: 0 0 8px color-mix(in oklab, var(--col-accent, var(--ok)) 55%, transparent);
}
/* When the user clicks a previously-unchecked checkbox, it transitions to
   :checked AND has the keyframe applied — gives a one-shot pop animation
   independent of the active state. */
@keyframes _check-pop {
  0%   { transform: scale(1);   }
  30%  { transform: scale(1.35);}
  60%  { transform: scale(0.92);}
  100% { transform: scale(1);   }
}
.task input[type="checkbox"]:checked { animation: _check-pop 600ms ease-out; }

/* When a task is marked done, the whole row glides out in sync with
   the checkbox pop. JS sets .task-completing right before the timeout
   that triggers renderBoard, so this animation has time to play before
   the DOM is rebuilt and the row disappears via .hide-done. The
   timings are deliberately slow so the completion feels celebratory
   rather than abrupt. */
@keyframes _task-out {
  0%   { transform: scale(1);    opacity: 1; }
  20%  { transform: scale(1.03); opacity: 1; }
  60%  { transform: scale(1);    opacity: 0.7; }
  100% { transform: scale(0.92); opacity: 0; }
}
.task.task-completing {
  animation: _task-out 700ms ease-out forwards;
  pointer-events: none;
}
/* Strip the up/down spinners from minute inputs — manual entry only */
.task .min, .task-add .min-in {
  -moz-appearance: textfield; appearance: textfield;
}
.task .min::-webkit-inner-spin-button,
.task .min::-webkit-outer-spin-button,
.task-add .min-in::-webkit-inner-spin-button,
.task-add .min-in::-webkit-outer-spin-button {
  -webkit-appearance: none; margin: 0;
}
.task .name, .task .min {
  background: transparent; color: var(--fg);
  border: none; outline: none; font: inherit;
  padding: 2px 4px; border-radius: 3px;
  cursor: text;
  transition: background 0.1s ease, box-shadow 0.1s ease;
}
/* `field-sizing: content` (Chrome 123, Firefox 122, Safari 17.4) makes the
   <input> shrink to fit its text. Combined with `margin-right: auto`, name
   anchors to the left and min/delete/badge are pushed to the right edge,
   leaving a big middle stretch that's the click target for the highlight
   feature (which was being eaten by the input's old flex:1 width).
   Browsers without field-sizing fall back to the default size — still
   usable, the row just looks a bit fuller. */
.task .name {
  field-sizing: content;
  flex: 0 1 auto;
  min-width: 6ch;
  max-width: calc(100% - 100px);  /* reserve room for min + delete + gaps */
  margin-right: auto;              /* shove everything after it to the right */
}
/* Wide-column name uses a <textarea> so long text wraps to multiple lines
   instead of being clipped horizontally. field-sizing: content makes it
   auto-grow vertically with the content. No resize handle, no scrollbar. */
.task .name-textarea {
  flex: 1 1 auto;
  max-width: calc(100% - 40px);   /* reserve room for the delete button */
  resize: none;
  overflow: hidden;
  white-space: pre-wrap; word-break: break-word;
  line-height: 1.4;
  font: inherit;
}
/* When a textarea name grows to multiple lines, top-align the row's other
   controls so the checkbox/pill/grip sit on the first line of text. */
.tasks-col.wide .task { align-items: flex-start; }
.tasks-col.wide .task .grip,
.tasks-col.wide .task input[type="checkbox"],
.tasks-col.wide .task .dual-state-pill,
.tasks-col.wide .task .delete,
.tasks-col.wide .task .task-link { margin-top: 2px; }
.task .min { width: 48px; text-align: right; color: var(--muted); flex: 0 0 auto; }
/* Subtle hover hint that fields are editable */
.task .name:hover, .task .min:hover {
  background: var(--panel-2);
}
.task .name:focus, .task .min:focus {
  background: var(--panel-2); color: var(--fg);
  box-shadow: inset 0 -1px 0 var(--accent);
}
.task .delete {
  background: transparent; border: none; color: var(--idle);
  cursor: pointer; padding: 0 4px; font-size: 14px;
  visibility: hidden;
}
.task:hover .delete { visibility: visible; }
.task .delete:hover { color: var(--err); }
/* Tiny "open URL in new tab" chip for URL-aware columns (jobs etc.) */
.task .task-link {
  color: var(--accent); padding: 0 4px; font-size: 13px;
  text-decoration: none; flex-shrink: 0;
}
.task .task-link:hover { text-decoration: underline; }
.task-add {
  display: flex; align-items: center; gap: 8px; margin-top: 4px;
  padding: 6px; border-radius: 5px;
}
.task-add input {
  background: var(--bg); border: 1px solid var(--border); border-radius: 4px;
  color: var(--fg); padding: 4px 8px; font: inherit; font-size: 13px;
  outline: none;
}
.task-add input:focus { border-color: var(--accent); }
.task-add .name-in { flex: 1; min-width: 0; }
.task-add .min-in { width: 56px; text-align: right; }
.task-totals {
  margin-top: auto; padding-top: 10px; border-top: 1px solid var(--border);
  font-size: 12px; color: var(--muted);
}
.task-totals .row {
  display: flex; justify-content: space-between; padding: 2px 0;
}
.task-totals .row .v { color: var(--fg); font-variant-numeric: tabular-nums; }
.task-totals .finish { font-weight: 600; }
.task-totals .finish .v { color: var(--accent); }

/* ── Cross-list summary panel ───────────────────────────────── */
.cross-summary {
  margin-top: 16px; background: var(--panel);
  border: 1px solid var(--border); border-radius: 8px;
  padding: 12px 16px;
}
.cross-summary .heading {
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--accent); margin-bottom: 8px; font-weight: 600;
  display: flex; justify-content: space-between; align-items: baseline;
}
.cross-summary .activity-link {
  color: var(--muted); font-weight: 400;
  text-transform: none; letter-spacing: normal;
  font-size: 12px; text-decoration: none;
}
.cross-summary .activity-link:hover { color: var(--accent); }
.cross-summary table {
  width: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums;
}
.cross-summary td {
  padding: 4px 8px; font-size: 13px; color: var(--muted);
}
.cross-summary td:first-child { color: var(--fg); font-weight: 500; }
.cross-summary td:last-child { text-align: right; color: var(--accent); font-weight: 600; }
.cross-summary .combined td { border-top: 1px solid var(--border); padding-top: 8px; }

/* ── Links to Check panel (Career tab) ───────────────────────── */
.links-panel {
  margin-top: 16px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 12px 16px;
}
.links-panel .links-heading {
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--accent); margin-bottom: 8px; font-weight: 600;
}
.links-list { display: flex; flex-direction: column; gap: 2px; }
.link-row {
  display: flex; justify-content: space-between; align-items: center;
  padding: 4px 6px; border-radius: 4px;
  font-size: 13px;
}
.link-row:hover { background: var(--panel-2); }
.link-name {
  flex: 1; min-width: 0;
  color: var(--accent); text-decoration: none;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.link-row .link-name:hover { text-decoration: underline; }
.link-row .delete {
  background: transparent; border: none; color: var(--idle);
  cursor: pointer; padding: 0 6px; font-size: 13px;
  visibility: hidden;
}
.link-row:hover .delete { visibility: visible; }
.link-row .delete:hover { color: var(--err); background: transparent; }
.link-add { margin-top: 8px; }
.link-add-in {
  width: 100%; box-sizing: border-box;
  background: var(--bg); border: 1px solid var(--border);
  border-radius: 4px; padding: 6px 8px;
  font: inherit; font-size: 13px; color: var(--fg); outline: none;
}
.link-add-in:focus { border-color: var(--accent); }

/* ── Word of the Day panel ───────────────────────────────────── */
.word-of-day {
  margin-top: 16px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 14px 18px;
  display: flex; align-items: baseline; gap: 14px;
  flex-wrap: wrap;
}
.word-of-day .label {
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--idle); flex-shrink: 0;
}
.word-of-day .word {
  font-size: 18px; font-weight: 600; color: var(--accent);
  font-family: 'Instrument Sans', "SF Pro Display", system-ui, sans-serif;
  letter-spacing: -0.01em;
}
.word-of-day .def {
  color: var(--muted); font-size: 14px; line-height: 1.5;
  flex: 1; min-width: 200px;
}
.wod-refresh {
  background: transparent; border: 1px solid var(--border); color: var(--muted);
  border-radius: 5px; padding: 3px 8px; cursor: pointer;
  font: inherit; font-size: 13px; flex-shrink: 0;
  transition: color 0.15s ease, border-color 0.15s ease, transform 0.4s ease;
}
.wod-refresh:hover {
  color: var(--accent); border-color: var(--accent); transform: rotate(180deg);
}

/* ── Terminal commands ───────────────────────────────────────── */
.term-cmd {
  background: var(--panel); border: 1px solid var(--border);
  border-radius: 8px; padding: 12px 14px; margin-bottom: 10px;
}
.term-cmd .top {
  display: flex; justify-content: space-between; align-items: baseline;
  margin-bottom: 4px;
}
.term-cmd .name { font-weight: 600; color: var(--fg); }
.term-cmd .desc {
  color: var(--muted); font-size: 12px; line-height: 1.5;
  margin-bottom: 8px;
}
.term-cmd .cmd-row {
  display: flex; gap: 8px; align-items: stretch;
}
.term-cmd code {
  flex: 1; background: var(--bg);
  border: 1px solid var(--border); border-radius: 4px;
  padding: 8px 10px; overflow-x: auto;
  font: 12px/1.4 ui-monospace, "SF Mono", Menlo, monospace;
  color: var(--fg); white-space: pre;
}
.term-cmd .copy-btn {
  background: var(--panel-2); color: var(--fg);
  border: 1px solid var(--border); border-radius: 4px;
  padding: 0 12px; cursor: pointer; font-size: 12px;
  font: inherit; flex-shrink: 0;
}
.term-cmd .copy-btn:hover { background: var(--accent); color: var(--bg); }
.term-cmd .copy-btn.copied { background: var(--ok); color: var(--bg); border-color: var(--ok); }
.term-cmd .cmd-variant { margin-top: 8px; }
.term-cmd .cmd-variant:first-of-type { margin-top: 4px; }
.term-cmd .variant-label {
  font-size: 11px; color: var(--muted); margin-bottom: 4px;
  text-transform: uppercase; letter-spacing: 0.05em;
}

/* ── Undo toast ──────────────────────────────────────────────── */
.undo-toast {
  position: fixed; bottom: 24px; left: 50%;
  transform: translateX(-50%) translateY(20px);
  background: var(--panel-2); border: 1px solid var(--border);
  border-radius: 8px; padding: 10px 14px;
  display: flex; align-items: center; gap: 14px;
  font-size: 13px; color: var(--fg);
  box-shadow: 0 8px 24px rgba(0,0,0,0.4);
  opacity: 0; pointer-events: none;
  transition: opacity 0.2s ease, transform 0.2s ease;
  z-index: 1000;
}
.undo-toast.visible {
  opacity: 1; transform: translateX(-50%) translateY(0);
  pointer-events: auto;
}
.undo-toast .undo-btn {
  background: transparent; border: 1px solid var(--accent); color: var(--accent);
  border-radius: 5px; padding: 4px 10px; font: inherit; font-size: 12px;
  cursor: pointer; font-weight: 600;
}
.undo-toast .undo-btn:hover { background: var(--accent); color: var(--bg); }

.log {
  margin-top: 8px; background: var(--bg); border: 1px solid var(--border); border-radius: 4px;
  padding: 6px 8px; font: 11px/1.35 ui-monospace, "SF Mono", Menlo, monospace;
  color: var(--muted); white-space: pre-wrap; word-break: break-all;
  max-height: 100px; overflow: auto;
}
.desc {
  margin-top: 6px; color: var(--muted); font-size: 12px; line-height: 1.4;
}
.recent {
  margin-top: 8px; background: var(--bg); border: 1px solid var(--border);
  border-radius: 4px; padding: 6px 8px; font-size: 11px;
  /* Single grid for ALL rows so columns align across the list:
     when | orig | → | neu */
  display: grid;
  grid-template-columns: max-content max-content max-content 1fr;
  gap: 2px 10px;
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
}
.recent .recent-row {
  display: contents;  /* row's children participate in parent grid */
  color: var(--muted);
}
.recent .recent-row > span {
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  min-width: 0;
}
.recent .when { color: var(--idle); }
.recent .orig { color: var(--muted); }
.recent .arrow { color: var(--idle); padding: 0 2px; }
.recent .neu { color: var(--fg); }
/* When there's no original (e.g. for tasks with only a "neu"), span
   the orig + arrow + neu cells so the row doesn't leave gaps. */
.recent .recent-row .neu.full-span { grid-column: 2 / -1; }
.card-foot {
  display: flex; justify-content: space-between; align-items: center;
  margin-top: 8px; font-size: 11px;
}
.view-log {
  color: var(--accent); text-decoration: none; font-size: 12px;
}
.view-log:hover { text-decoration: underline; }
.log-page {
  font: 12px/1.45 ui-monospace, "SF Mono", Menlo, monospace;
  background: var(--panel); border: 1px solid var(--border);
  border-radius: 6px; padding: 12px; white-space: pre-wrap;
  max-height: 80vh; overflow: auto; word-break: break-all;
}
.tm-progress {
  margin-top: 10px; height: 8px; background: var(--bg);
  border: 1px solid var(--border); border-radius: 4px; overflow: hidden;
}
.tm-progress > div {
  height: 100%; background: var(--accent);
  transition: width 0.4s ease;
}
.tm-stats {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 10px 16px; margin-top: 10px; font-size: 12px; color: var(--muted);
}
.tm-stats .label { color: var(--idle); display: block; font-size: 11px;
                   text-transform: uppercase; letter-spacing: 0.05em; }
.tm-stats .value { color: var(--fg); font-size: 13px; }

#output {
  margin-top: 12px; background: var(--panel); border: 1px solid var(--border);
  border-radius: 6px; padding: 12px; font: 12px/1.4 ui-monospace, "SF Mono", Menlo, monospace;
  color: var(--fg); white-space: pre-wrap; max-height: 50vh; overflow: auto;
}
#output[data-status="ok"]    { border-left: 3px solid var(--ok); }
#output[data-status="error"] { border-left: 3px solid var(--err); }

@media (max-width: 480px) {
  .grid { grid-template-columns: 1fr; }
}

/* ── Upcoming Dates panel ──────────────────────────────────────────── */
/* Sits at the bottom of the To Do page on Jess's dashboard and at the
   bottom of the Life tab on Mark's. Server-side filtering already drops
   past dates; client just renders + adds. */
.upcoming-dates-section {
  /* Tightened gap below the task board — the "+ Add panel" chip and
     the section's H2 each contribute their own spacing, so an extra
     24px here was reading as a lot of dead air. */
  margin-top: 4px;
  /* Leave breathing room beneath the whole panel so the add-row and
     history button don't crowd whatever follows. */
  margin-bottom: 48px;
}
/* H2 inside the dates section: also tighten the top margin so the
   "UPCOMING DATES" label sits close to the task board. (The page-wide
   h2 rule sets 24px / 32px in the ADHD override — too much here.) */
.upcoming-dates-section h2 { margin-top: 12px; }
/* Add-row is BELOW the list and history button; margin-top creates the
   visual separation, no margin-bottom needed since the section's own
   margin-bottom handles below-the-row spacing. */
.dates-add-row {
  display: flex; gap: 8px; align-items: center;
  margin-top: 24px;
}
.dates-add-input {
  flex: 1; min-width: 0;
  padding: 10px 12px; font-size: 14px;
  background: var(--bg); color: var(--fg);
  border: 1px solid var(--border); border-radius: 8px;
  outline: none; transition: border-color 120ms ease;
}
.dates-add-input:focus { border-color: var(--accent); }
.dates-add-btn {
  padding: 9px 16px; font-size: 13px; font-weight: 600;
  background: var(--ok); color: #fff;
  border: none; border-radius: 8px; cursor: pointer;
}
.dates-add-btn:hover { filter: brightness(1.1); }
.dates-error {
  margin-left: 4px; color: var(--err, #ef4444);
  font-size: 12px; min-height: 1em;
}
.dates-list {
  list-style: none; margin: 0; padding: 0;
  /* The LIST owns the grid template, not each row — so column tracks
     are SHARED across all rows. Each .dates-item uses `subgrid` to
     inherit those tracks, which is what actually makes the columns
     line up. (Previously each item was its own grid container, so a
     row with a wider day text widened its OWN day column, pushing
     that row's event later than the others.) */
  display: grid;
  grid-template-columns: auto auto 1fr auto;
  column-gap: 56px;
  background: var(--panel); border: 1px solid var(--border); border-radius: 8px;
  overflow: hidden;
}
.dates-item {
  display: grid;
  grid-template-columns: subgrid;
  grid-column: 1 / -1;
  align-items: baseline;
  padding: 10px 14px;
  border-bottom: 1px solid var(--border);
  font-size: 14px; color: var(--fg);
}
.dates-item:last-child { border-bottom: none; }
.dates-prefix {
  color: var(--accent); font-weight: 700;
  white-space: nowrap; text-align: left;
}
.dates-day {
  color: var(--muted);
  white-space: nowrap; text-align: left;
}
/* Event name carries the weight — bold so it stands out. min-width: 0
   keeps it truncatable inside the 1fr cell. */
.dates-name { min-width: 0; font-weight: 600; text-align: left; }
/* Legacy inline `·` separators retired in favour of the grid. Hide any
   stragglers in case a cached client is still rendering them. */
.dates-sep { display: none; }
.dates-del {
  background: transparent; border: none;
  color: var(--idle); cursor: pointer;
  font-size: 14px; padding: 0 4px;
  /* No margin-left: auto — the trailing `auto` track in the grid template
     already anchors the button to the right side. */
}
.dates-del:hover { color: var(--err, #ef4444); }
.dates-empty {
  padding: 12px 14px; color: var(--muted); font-style: italic;
  grid-column: 1 / -1;   /* span all four tracks when there are no rows */
}

/* Single 4-column board (Today | Tomorrow | Annie | House). The inherited
   4-track grid already fits — these media queries collapse it cleanly at
   tablet/phone widths so columns don't get unreadably narrow. */
@media (max-width: 1100px) {
  .tasks-board { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 600px) {
  .tasks-board { grid-template-columns: 1fr; }
}

/* Click-to-edit affordance + edit-mode row styling (mirrors Mark's). */
.dates-list .dates-clickable {
  cursor: text;
  border-radius: 3px;
  padding: 0 2px;
  transition: background 100ms ease;
}
.dates-list .dates-clickable:hover { background: var(--panel-2); }
.dates-list .dates-item-editing { padding: 6px 12px; }
/* Edit input spans the three text-column tracks of the subgrid so it
   stays where the row was — no more jamming into column 1 ("the left"). */
.dates-list .dates-edit-input {
  grid-column: 1 / span 3;
  min-width: 0;
  width: 100%;
}
.dates-list .dates-edit-input.dates-edit-error {
  border-color: var(--err, #ef4444);
  background: rgba(239, 68, 68, 0.08);
}

/* History button + Undo styling (mirrors Mark's). */
/* History sits directly under the dates list. Add-row appears further
   below the history with its own margin-top, leaving a clean visual gap
   between "view past" and "add new". */
.dates-history-row { display: flex; justify-content: flex-end; margin-top: 8px; }
/* Shared chip style for the three utility buttons on the page:
   - +Add panel (top, under the board)
   - Board history (top, beside +Add panel)
   - Dates history (bottom right, under the dates list)
   Identical visuals keep the page from feeling cluttered. */
.dates-history-btn,
.board-history-btn,
.add-section-btn {
  background: transparent; color: var(--muted);
  border: 1px solid var(--border); border-radius: 6px;
  padding: 4px 10px; font-size: 11px; font-weight: 500;
  letter-spacing: 0.04em; text-transform: uppercase;
  cursor: pointer;
  transition: color 120ms ease, border-color 120ms ease;
}
.dates-history-btn:hover,
.board-history-btn:hover,
.add-section-btn:hover { color: var(--accent); border-color: var(--accent); }
.activity-list .undo-btn {
  margin-left: auto;
  background: transparent; color: var(--accent);
  border: 1px solid var(--accent); border-radius: 4px;
  padding: 1px 8px; font-size: 11px; cursor: pointer;
  font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase;
  transition: background 120ms ease;
}
.activity-list .undo-btn:hover { background: var(--accent); color: var(--bg); }
.activity-list .undo-btn:disabled { opacity: 0.5; cursor: wait; }

/* ── ADHD-friendly overrides (Jess's dashboard only) ─────────────────
   Goals: easy to scan, easy to tap, low cognitive load.
   - Bigger type + spacing so items don't visually merge
   - Color-coded column headers so the eye lands on the right list
     without reading the label
   - Larger touch targets (checkboxes, delete, add row)
   - Higher contrast task names
   - Subtle per-column background tints so each column reads as its own
     zone. Plain, no decoration — just enough separation. */

body { font-size: 17px; line-height: 1.5; }
h2 {
  /* Smaller now: "UPCOMING DATES" is the quieter sibling of the
     "greens.fyi" tab title (which moved up to 16px). */
  font-size: 13px;
  color: var(--muted);
  margin: 32px 0 14px;
  letter-spacing: 0.04em;
}

/* Column headers: larger, weight 700, color-coded per column. The colors
   pick from the existing theme tokens so dark/light both look correct. */
.tasks-col {
  padding: 18px 16px;
  min-height: 320px;
  gap: 8px;
  background: var(--panel);
  border-radius: 12px;
}
.tasks-col h3 {
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0.08em;
  margin-bottom: 14px;
  padding-bottom: 10px;
  border-bottom: 2px solid var(--border);
}
/* Per-column accent — each column sets `--col-accent: <hex>` inline (see
   renderColumn in app.js). Built-ins get a fixed palette by default;
   custom sections pull the next unused color from the palette. Users can
   reorder freely since color is data-driven, not key-driven. */
.tasks-col {
  --col-accent: #888;   /* fallback; columns set this inline */
  background: color-mix(in oklab, var(--col-accent) 8%, var(--panel));
  border-left: 4px solid var(--col-accent);
}
.tasks-col h3 {
  color: var(--col-accent);
  border-bottom-color: var(--col-accent);
}

/* Column drag handle (the ⠿ grip in the header). Quiet by default, more
   visible on column hover so the user knows where to grab. */
.tasks-col .col-grip {
  cursor: grab;
  color: var(--muted);
  opacity: 0.5;
  font-size: 14px;
  user-select: none;
  padding: 0 4px;
  margin-right: 4px;
}
.tasks-col:hover .col-grip { opacity: 1; }
.tasks-col .col-grip:active { cursor: grabbing; }
/* Column drag visuals.
   - .col-dragging: source column dims + shrinks slightly so you can
     still SEE where it came from (lets you drop it back). Keeping it in
     the layout also means dragover events on adjacent columns have
     stable bounding rects throughout the drag.
   - .col-drop-before / .col-drop-after: a CLEAR full-height vertical bar
     between the target's edge and its neighbor, outside the column
     (via outset box-shadow) so it visibly lives in the gutter where the
     incoming column will slot in. Plus a subtle scale on the target so
     the drop site reads as "active". */
.tasks-col {
  transition: transform 140ms ease, opacity 140ms ease, box-shadow 100ms ease;
}
.tasks-col.col-dragging {
  opacity: 0.35;
  transform: scale(0.94);
  pointer-events: none;   /* let dragover pass through to other columns */
}
.tasks-col.col-drop-before {
  /* 6px-wide accent bar sitting OUTSIDE the left edge, in the gutter. */
  box-shadow: -10px 0 0 -2px var(--col-accent);
  transform: scale(1.02);
}
.tasks-col.col-drop-after {
  box-shadow: 10px 0 0 -2px var(--col-accent);
  transform: scale(1.02);
}

/* Task rows: roomier, easier to scan and tap. */
.task {
  padding: 11px 10px;
  font-size: 16px;
  min-height: 44px;            /* iOS-friendly tap target */
  border-radius: 8px;
}
.task .name {
  font-size: 16px;
  color: var(--fg);
  font-weight: 500;
}
.task input[type="checkbox"] {
  width: 24px; height: 24px;
  cursor: pointer;
  flex-shrink: 0;
}
.task .delete {
  font-size: 18px;
  padding: 4px 8px;
  min-width: 32px;
}
.task .grip { opacity: 0.35; font-size: 18px; }

/* + Add task row at the bottom of each column — bigger so it's an obvious
   action target rather than something to scroll past. */
.task-add { margin-top: 10px; }
.task-add .name-in {
  padding: 12px 14px;
  font-size: 15px;
  border-radius: 8px;
  background: var(--bg);
}

/* "N done — show/hide" toggle: tone it down so done tasks don't dominate
   the visual landscape, but stay reachable. */
.completed-toggle { padding: 8px 6px 0; font-size: 12px; }

/* Upcoming Dates panel — same readability boost. The "In N days · day ·
   event name" prefix gets bolder so the urgency reads at a glance. */
.dates-list {
  border-radius: 10px;
  /* Wider column-gap now belongs on the LIST (which owns the grid),
     not the items. Otherwise it had no effect — the items' own grid
     was the one being styled. */
  column-gap: 72px;
}
.dates-item {
  padding: 14px 16px;
  font-size: 16px;
}
.dates-prefix {
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.02em;
}
.dates-day { font-size: 15px; }
/* Event name: bigger AND bold so it dominates the row. */
.dates-name { font-size: 16px; font-weight: 700; }
.dates-add-input { padding: 13px 14px; font-size: 15px; border-radius: 8px; }
.dates-add-btn   { padding: 12px 20px; font-size: 15px; border-radius: 8px; }

/* Bigger meta strip (top of page) so date/time + buttons don't look fiddly. */
header { gap: 12px; }
.meta { gap: 14px; font-size: 14px; }
.meta button { padding: 8px 14px; font-size: 14px; }

/* ──────────────────────────────────────────────────────────────────
   Greens.fyi mobile pass
   The general mobile pass earlier (~line 410) handles header stacking
   and shared utilities. This block focuses on greens.fyi-specific
   layouts: the task board, the dates panel card layout, and tap
   targets that need to feel comfortable on a phone.
   ────────────────────────────────────────────────────────────────── */
@media (max-width: 720px) {
  /* Don't pad the page on phones — every horizontal pixel counts. */
  body { padding: 6px; }

  /* Two-row header on phones:
       Row 1: [GREENS.FYI] [CALENDAR] ... [Sign out]
       Row 2: Sunday, May 17  ·  8:45 PM
     The "updated X" timestamp duplicates the clock on the next line,
     so hide it. Theme + Refresh hidden too — phone users rarely
     bother. */
  header {
    flex-direction: row !important;
    flex-wrap: wrap;
    align-items: center;
    padding: 6px 8px;
    gap: 8px;
  }
  .tabs { flex: 1 1 auto; min-width: 0; }
  .header-info {
    order: 99;                /* always at the end → bottom row */
    flex: 1 0 100%;
    margin: 0;
    font-size: 12px;
    gap: 10px;
  }
  .meta #theme-toggle,
  .meta #refresh,
  .meta #updated      { display: none; }
  .meta #signout      { padding: 6px 10px; font-size: 12px; }
  .meta { gap: 6px; font-size: 12px; }

  /* Tab "GREENS.FYI": full size, but tap-friendly padding. */
  .tab { padding: 8px 12px; font-size: 15px; }

  /* Task board: 1-up, shorter columns, larger title + tasks. */
  .tasks-col {
    min-height: auto;
    padding: 12px 12px;
  }
  .tasks-col h3 {
    font-size: 15px;
    margin-bottom: 8px;
    padding-bottom: 6px;
  }
  .task { padding: 10px 8px; }
  .task .name { font-size: 15px; }
  .task .grip { display: none; }    /* the row itself is draggable on touch */
  /* Column grip (⠿) hidden too — column reorder is a desktop affordance. */
  .col-grip { display: none; }

  /* Dates panel: each row becomes a small CARD with the event name as
     the headline and prefix + day stacked as secondary info. The grid
     /subgrid model from desktop is dropped here because side-by-side
     cells get unreadably narrow on a phone. */
  .dates-list {
    display: block;
    column-gap: 0;
  }
  .dates-item {
    display: grid;
    grid-template-columns: 1fr auto;
    grid-template-areas:
      "prefix delete"
      "name   delete"
      "day    delete";
    grid-template-rows: auto;
    column-gap: 12px;
    row-gap: 2px;
    padding: 12px 14px;
    align-items: baseline;
  }
  .dates-prefix {
    grid-area: prefix;
    font-size: 12px;
    border-right: none;
    padding-right: 0;
    margin-right: 0;
  }
  .dates-name {
    grid-area: name;
    font-size: 16px;
    line-height: 1.3;
  }
  .dates-day {
    grid-area: day;
    font-size: 12px;
    border-right: none;
    padding-right: 0;
    margin-right: 0;
  }
  .dates-del {
    grid-area: delete;
    align-self: center;
    font-size: 18px;
    padding: 8px 10px;       /* ≥44px tap target */
    min-width: 44px;
    min-height: 44px;
    display: inline-flex; align-items: center; justify-content: center;
    opacity: 0.5;            /* always visible (no hover on touch) */
  }
  .dates-list .dates-edit-input {
    /* Edit field spans the text column only (not the delete column) */
    grid-column: 1 / 2;
    width: 100%;
  }
  /* Dates add-row: stack so the input gets full width, button below */
  .dates-add-row {
    flex-direction: column;
    gap: 6px;
    margin-top: 14px;
    align-items: stretch;
  }
  .dates-add-btn { width: 100%; padding: 14px 16px; }
  .dates-add-input { padding: 12px 14px; }

  /* Footer chips (+Add panel + History): smaller and full-width */
  .board-footer {
    margin-top: 8px;
    flex-wrap: wrap;
  }
  .add-section-btn, .board-history-btn { padding: 6px 10px; font-size: 11px; }

  /* Upcoming Dates section heading: tighter top margin */
  .upcoming-dates-section { margin-top: 0; margin-bottom: 24px; }
  .upcoming-dates-section h2 { margin: 12px 0 6px; }

  /* Modal: pad less + bigger touch buttons inside */
  .modal-actions button { padding: 12px 18px; font-size: 15px; }
}

/* Extra-small phones (≤390): squeeze a bit more */
@media (max-width: 390px) {
  .tab { font-size: 14px; padding: 7px 10px; }
  .header-info { font-size: 11px; gap: 8px; }
  .dates-name { font-size: 15px; }
  .tasks-col h3 { font-size: 14px; }
  .task .name { font-size: 14px; }
}
