:root {
  --bg: #fbfaf8; --card: #fff; --ink: #1c1b19; --muted: #6b6862;
  --line: #e4e0d9; --accent: #2f4f86; --accent-wash: #eaf0fa;
  --warn: #fdf6e3; --warn-line: #e8d9a8; --danger: #a3302a;
  /* Ships with macOS and iOS as New York — a real display face, no webfont. */
  --display: ui-serif, "New York", "Iowan Old Style", Palatino, Georgia, serif;
}
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #171614; --card: #201f1c; --ink: #f0ede8; --muted: #a29d94;
    --line: #34322d; --accent: #8fb0e8; --accent-wash: #1e2632;
    --warn: #2a2418; --warn-line: #574a2c; --danger: #eb8a83;
  }
}

* { box-sizing: border-box; }
/* Author `display` beats the browser's `[hidden] { display: none }`, so any
   element we lay out and then hide from JS needs this to actually disappear. */
[hidden] { display: none !important; }
body {
  margin: 0; background: var(--bg); color: var(--ink);
  /* Installed to the home screen the page runs edge to edge, so the notch and the
     home indicator have to be paid for here rather than by Safari's chrome. */
  padding: env(safe-area-inset-top) calc(1rem + env(safe-area-inset-right))
           calc(4rem + env(safe-area-inset-bottom)) calc(1rem + env(safe-area-inset-left));
  font: 16px/1.5 ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  max-width: 44rem; margin-inline: auto;
}
h1 { font-family: var(--display); font-size: 1.4rem; font-weight: 600; letter-spacing: -.01em; margin: 0; }
h2 { font-size: .8rem; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); margin: 1.5rem 0 .5rem; }
a { color: var(--accent); }

.topbar { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: 1rem 0; flex-wrap: wrap; }
.topbar nav { display: flex; align-items: center; gap: .75rem; }

.linkish { background: none; border: 0; padding: 0; color: var(--accent); font: inherit; cursor: pointer; text-decoration: underline; }
.primary {
  display: inline-block; background: var(--accent); color: var(--bg); border: 0;
  border-radius: .5rem; padding: .5rem .9rem; font: inherit; font-weight: 600; cursor: pointer; text-decoration: none;
}

.chips { display: flex; align-items: center; gap: .4rem; flex-wrap: wrap; margin: .25rem 0 1rem; }
.chips-label { font-size: .78rem; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); margin-right: .2rem; }
.chip {
  border: 1px solid var(--line); border-radius: 999px; padding: .25rem .7rem;
  font-size: .82rem; color: var(--muted); text-decoration: none; background: var(--card);
}
.chip.on { background: var(--accent); border-color: var(--accent); color: var(--bg); font-weight: 600; }

.danger {
  border: 0; background: none; color: var(--muted); font: inherit; font-size: .78rem;
  padding: .2rem .3rem; cursor: pointer; text-decoration: underline; align-self: flex-end;
}
.danger:hover, .danger:focus-visible { color: var(--danger); }

.bulk { display: flex; align-items: center; gap: .75rem; flex-wrap: wrap; padding: .75rem; background: var(--card); border: 1px solid var(--line); border-radius: .75rem; }
.bulk label { display: flex; align-items: center; gap: .3rem; }
.bulk small { color: var(--muted); flex-basis: 100%; }
.bulk .danger { align-self: auto; margin-left: auto; }

.filters { display: flex; gap: .5rem; align-items: center; flex-wrap: wrap; margin-bottom: .75rem; }
.filters input, .filters select {
  padding: .45rem .6rem; font: inherit; border: 1px solid var(--line);
  border-radius: .5rem; background: var(--card); color: var(--ink);
}
.filters input { flex: 1; min-width: 10rem; }
.filter-empty { color: var(--muted); font-size: .88rem; flex-basis: 100%; }

.event {
  display: flex; gap: .75rem; align-items: flex-start;
  background: var(--card); border: 1px solid var(--line);
  border-radius: .75rem; padding: .75rem; margin-bottom: .5rem;
}
/* Unclaimed is the signal the whole page exists to surface. The class sits on
   .detail, which is what a claim swaps in, so the row recolours with it. */
.event:has(> .detail.unclaimed) { background: var(--warn); border-color: var(--warn-line); }
.event .select { margin-top: .35rem; width: 1.1rem; height: 1.1rem; flex: none; }
.event .detail { display: flex; flex-direction: column; gap: .15rem; flex: 1; min-width: 0; }
.event .when { font-variant-numeric: tabular-nums; font-size: .82rem; color: var(--muted); }
.event .summary { font-weight: 600; overflow-wrap: anywhere; }
.event .where, .event .owner { font-size: .82rem; color: var(--muted); }
.event .toggles { display: flex; flex-direction: column; gap: .35rem; flex: none; }
.event .toggles .toggle-form { margin: 0; }

.toggle {
  width: 100%; border: 1px solid var(--line); background: transparent; color: var(--muted);
  border-radius: 999px; padding: .3rem .7rem; font: inherit; font-size: .82rem; cursor: pointer; white-space: nowrap;
}
.toggle.on { background: var(--accent); border-color: var(--accent); color: var(--bg); font-weight: 600; }
/* Optimistic: what you asked for, held at arm's length until Google confirms. */
.toggle.saving { opacity: .55; animation: pulse 1.1s ease-in-out infinite; }
@keyframes pulse { 50% { opacity: .3; } }

/* The unclaimed count, and the digest's per-person line. Same voice both places:
   a quiet sentence, not a badge. */
.tally {
  margin: 0 0 1rem; padding: .5rem .75rem; font-size: .88rem; color: var(--muted);
  background: var(--warn); border: 1px solid var(--warn-line); border-radius: .5rem;
}
.tally strong { color: var(--ink); font-variant-numeric: tabular-nums; }

.week h3 {
  font-size: .82rem; font-weight: 600; color: var(--muted); margin: 0 0 .3rem;
}
.week .dday { margin-bottom: .9rem; }
.week .empty { color: var(--muted); font-size: .9rem; }
/* Three columns on a laptop, stacked on a phone — the time is the anchor either
   way, so it leads and keeps its own width. */
.drow {
  /* Wide enough for the longest range the time format can produce
     ("10:00 am – 11:00 am"); a fixed track any narrower spills into the title. */
  display: grid; grid-template-columns: 9rem 1fr auto; gap: .1rem .75rem; align-items: baseline;
  padding: .45rem .6rem; border-bottom: 1px solid var(--line);
}
.drow:last-child { border-bottom: 0; }
.drow.unclaimed { background: var(--warn); border-radius: .4rem; border-bottom-color: transparent; }
.drow .when { font-variant-numeric: tabular-nums; font-size: .82rem; color: var(--muted); white-space: nowrap; }
.drow .summary { overflow-wrap: anywhere; }
.drow .owner { font-size: .82rem; color: var(--muted); white-space: nowrap; }
@media (max-width: 32rem) {
  .drow { grid-template-columns: 1fr auto; }
  .drow .when { grid-column: 1 / -1; }
}

.settings { display: flex; flex-direction: column; gap: .5rem; }
.settings small { color: var(--muted); font-size: .8rem; }
/* Scoped to the real fields: a bare `.settings input` also matches the submit
   button and outranks .primary, which quietly un-styles it. */
.settings .field input, .settings .field select {
  padding: .55rem .6rem; font: inherit; border: 1px solid var(--line);
  border-radius: .5rem; background: var(--card); color: var(--ink); width: 100%;
}
.settings .primary { align-self: start; margin-top: .5rem; padding: .6rem 1.4rem; }

/* The preview is the point of this page: the markers exist to produce these. */
.preview { background: var(--card); border: 1px solid var(--line); border-radius: .75rem; padding: 1rem 1.1rem; }
.preview-caption { margin: 0 0 .7rem; font-size: .78rem; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); }
.preview-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .45rem; }
.preview-list li { font-family: var(--display); font-size: 1.05rem; display: flex; gap: .5rem; align-items: baseline; }
.preview-mark { font-family: initial; min-width: 1.5em; }

.markers { display: grid; grid-template-columns: repeat(2, 1fr); gap: .5rem; margin-top: 1rem; padding-top: 1rem; border-top: 1px solid var(--line); }
.preview-foot { margin: .9rem 0 0; font-size: .8rem; color: var(--muted); }

.fields { display: grid; grid-template-columns: 1fr; gap: .75rem; }
.field { display: flex; flex-direction: column; gap: .25rem; }

.connection { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.status { font-size: .78rem; font-weight: 600; border-radius: 999px; padding: .2rem .6rem; }
.status-on { background: var(--accent-wash); color: var(--accent); }
.status-off { background: var(--warn); color: var(--ink); border: 1px solid var(--warn-line); }

:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) { * { transition: none !important; animation: none !important; } }

@media (min-width: 34rem) {
  .markers { grid-template-columns: repeat(4, 1fr); }
  .fields { grid-template-columns: 1fr 8rem; align-items: start; }
  .field-wide { grid-column: 1; }
}

.notice { background: var(--warn); border: 1px solid var(--warn-line); border-radius: .75rem; padding: 1rem; }
.empty { color: var(--muted); }
.flash { padding: .5rem .8rem; border-radius: 999px; font-size: .85rem; background: var(--accent-wash); color: var(--accent); border: 0; margin: .75rem 0 0; display: inline-block; }
.flash-alert { background: var(--warn); color: var(--ink); border: 1px solid var(--warn-line); }

@media (max-width: 30rem) {
  .event { flex-wrap: wrap; }
  .event .toggles { flex-direction: row; width: 100%; }
  .toggle { flex: 1; }
}

/* ---- Emoji field ------------------------------------------------------- */
/* A <details> disclosure: the grid is closed until you want it, so four of these
   don't bury the rest of a form. */
.emoji-field { display: flex; flex-direction: column; gap: .25rem; min-width: 0; }
.emoji-label { font-size: .82rem; color: var(--muted); }
.emoji-disclosure { position: relative; }
.emoji-summary {
  display: flex; align-items: center; gap: .5rem; cursor: pointer;
  border: 1px solid var(--line); border-radius: .5rem; padding: .45rem .6rem;
  background: var(--card); list-style: none;
}
.emoji-summary::-webkit-details-marker { display: none; }
.emoji-disclosure[open] .emoji-summary { border-color: var(--accent); background: var(--accent-wash); }
.emoji-current { font-size: 1.5rem; line-height: 1; min-width: 1.4em; }
.emoji-change { font-size: .78rem; color: var(--accent); text-decoration: underline; }

.emoji-panel {
  position: absolute; z-index: 20; left: 0; margin-top: .35rem;
  background: var(--card); border: 1px solid var(--line); border-radius: .75rem;
  padding: .7rem; box-shadow: 0 8px 28px rgb(0 0 0 / .16);
  max-height: 17rem; overflow-y: auto; width: 18rem; max-width: 88vw;
}
/* The right-hand marker on Settings would open off the edge of a phone. Hang it
   from its own right edge instead. */
.markers .emoji-field:last-child .emoji-panel { left: auto; right: 0; }
.emoji-group { margin: .5rem 0 .3rem; font-size: .7rem; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); }
.emoji-group:first-child { margin-top: 0; }
.emoji-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(2.2rem, 1fr)); gap: .15rem; }
.emoji-choice {
  border: 0; background: none; border-radius: .4rem; cursor: pointer;
  /* 44px: the thumb target, not the glyph. */
  min-height: 2.6rem; font-size: 1.4rem; line-height: 1; padding: 0;
}
.emoji-choice:hover, .emoji-choice:focus-visible { background: var(--accent-wash); }
.emoji-custom { display: flex; flex-direction: column; gap: .25rem; margin-top: .7rem; padding-top: .7rem; border-top: 1px solid var(--line); font-size: .78rem; color: var(--muted); }
.emoji-input { font: inherit; font-size: 1.2rem; padding: .35rem .5rem; border: 1px solid var(--line); border-radius: .4rem; background: var(--bg); color: var(--ink); }

/* ---- People ------------------------------------------------------------ */
.lede { color: var(--muted); font-size: .9rem; margin: 0 0 1.25rem; max-width: 34rem; }

.person {
  background: var(--card); border: 1px solid var(--line); border-radius: .75rem;
  padding: 1rem 1.1rem; margin-bottom: 1rem;
}
.person-form { display: flex; flex-direction: column; gap: .75rem; }
.fold > .person-form { margin-bottom: 1rem; }
.person-head { display: flex; gap: .75rem; align-items: flex-end; flex-wrap: wrap; }
.field-grow { flex: 1; min-width: 10rem; }
.person .field { display: flex; flex-direction: column; gap: .25rem; }
.person .field label { font-size: .82rem; color: var(--muted); }
.person .field input {
  font: inherit; padding: .5rem .6rem; border: 1px solid var(--line);
  border-radius: .5rem; background: var(--bg); color: var(--ink); width: 100%;
}
.person small { color: var(--muted); font-size: .78rem; }
.person .primary { align-self: start; }

.person-sub { font-size: .78rem; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); margin: 1.4rem 0 .5rem; }

.device {
  display: flex; align-items: center; gap: .6rem; flex-wrap: wrap;
  padding: .55rem .7rem; border: 1px solid var(--line); border-radius: .6rem;
  margin-bottom: .4rem;
}
/* A link nobody has opened is unfinished business, same as an unclaimed event. */
.device-detail { display: flex; flex-direction: column; gap: .1rem; flex: 1; min-width: 8rem; }
.device-label { font-weight: 600; font-size: .9rem; }
.device-when { font-size: .78rem; color: var(--muted); }
.device-this { font-size: .7rem; font-weight: 600; text-transform: uppercase; letter-spacing: .05em; color: var(--accent); background: var(--accent-wash); border-radius: 999px; padding: .1rem .45rem; margin-left: .3rem; }
.device-link {
  flex-basis: 100%; font: inherit; font-size: .78rem; font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  padding: .4rem .5rem; border: 1px solid var(--warn-line); border-radius: .4rem;
  background: var(--card); color: var(--ink); overflow-x: auto;
}
.device-form { margin: 0; }
.device .danger { align-self: center; }

.issue { display: flex; gap: .5rem; align-items: center; flex-wrap: wrap; margin-top: .6rem; }
.issue input[type="text"] {
  font: inherit; padding: .5rem .6rem; border: 1px solid var(--line);
  border-radius: .5rem; background: var(--bg); color: var(--ink); flex: 1; min-width: 9rem;
}
.person-remove { margin-top: 1rem; }

/* ---- Sync -------------------------------------------------------------- */
/* The source forms live in .person cards, which never needed a select before. */
.person .field select {
  font: inherit; padding: .5rem .6rem; border: 1px solid var(--line);
  border-radius: .5rem; background: var(--bg); color: var(--ink); width: 100%;
}
.mirror {
  display: flex; align-items: center; gap: .6rem; flex-wrap: wrap;
  padding: .55rem .7rem; border: 1px solid var(--line); border-radius: .6rem;
  background: var(--card); margin-bottom: .4rem;
}
.mirror-detail { display: flex; flex-direction: column; gap: .1rem; flex: 1; min-width: 11rem; }
.mirror-route { font-weight: 600; font-size: .9rem; overflow-wrap: anywhere; }
.mirror-when { font-size: .78rem; color: var(--muted); }
/* The last error is the only thing on this page you have to act on. */
.mirror-error { font-size: .78rem; color: var(--danger); overflow-wrap: anywhere; }
.mirror-form { margin: 0; }
.mirror .toggle { width: auto; }

/* The busy title is only ever read by a busy-only mirror, so it has no business
   on screen once you have picked Titles or Everything. :has() rather than a
   Stimulus controller: no JS to ship, and a browser that ignores it just leaves
   the field visible — which is exactly where it started. Applies to both forms
   that pick a detail level, hence the class rather than an id. */
.detail-form:not(:has(select[name$="[detail]"] option[value="busy"]:checked)) .busy-only {
  display: none;
}

/* The Edit panel is the row's second line. .mirror already wraps, so a
   full-basis flex item lands under everything else in it — no positioning, and
   nothing overlaps the row below. */
.mirror-panel {
  flex: 1 0 100%;
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: .6rem;
  margin: .55rem 0 0; padding-top: .6rem; border-top: 1px solid var(--line);
}
.mirror-panel .field { display: flex; flex-direction: column; gap: .25rem; flex: 1 1 11rem; }
.mirror-panel .field label { font-size: .82rem; color: var(--muted); }
.mirror-panel input[type="text"], .mirror-panel select {
  font: inherit; padding: .5rem .6rem; border: 1px solid var(--line);
  border-radius: .5rem; background: var(--bg); color: var(--ink); width: 100%;
}
.mirror-panel .primary { width: auto; }
.mirror-panel small { flex: 1 0 100%; font-size: .78rem; color: var(--muted); }

/* Setup is one-time; mirrors are the page. <details> rather than a Stimulus
   controller, same reasoning as the busy-only field above. */
.fold summary {
  cursor: pointer; list-style: none;
  font-size: .8rem; text-transform: uppercase; letter-spacing: .06em; color: var(--muted);
  margin: 1.5rem 0 .5rem; display: flex; align-items: center; gap: .4rem;
}
.fold summary::-webkit-details-marker { display: none; }
.fold summary::before { content: "▸"; font-size: .7rem; }
.fold[open] summary::before { content: "▾"; }
.sources-count { font-weight: 400; letter-spacing: normal; text-transform: none; }
.sources-count::before { content: "· "; }
