/* Mobile-first. Tokens first; layout follows.
 * Theme: Forest Deep + Bronze.
 */

:root {
  /* Structural tokens — same across both palettes */
  --radius: 14px;
  --radius-sm: 10px;
  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
}

/* Light palette is the default — also kicks in if the inline theme script
 * couldn't read localStorage (rare; private browsing on some devices). */
:root,
:root[data-theme="light"] {
  --bg: #f0ebdd;
  --surface: #ffffff;
  --surface-2: #e6dfca;
  --fg: #1f2620;
  --fg-soft: #2f3a32;
  --muted: #6e7468;
  --border: #cdc4ac;
  --hover-bg: #e1d9c3;

  --accent: #2d8a4d;
  --accent-strong: #1f6635;
  --accent-2: #4cb574;
  --accent-title-mid: #2d8a4d;
  --accent-glow: rgba(45, 138, 77, 0.22);

  /* Primary button — saturated emerald + cream text */
  --btn-bg: #15a04a;
  --btn-bg-hover: #0e8a3e;
  --btn-border: #0e8a3e;
  --btn-border-hover: #0a6f31;
  --btn-text: #fbf2db;

  --warm: #a86a3c;
  --warm-soft: rgba(168, 106, 60, 0.14);

  --danger: #a8412e;
  --danger-soft: rgba(168, 65, 46, 0.12);

  --shadow: 0 1px 2px rgba(31, 38, 32, 0.06);
  --shadow-lg: 0 10px 30px rgba(31, 38, 32, 0.10);
}

:root[data-theme="dark"] {
  --bg: #0f1410;
  --surface: #1a2018;
  --surface-2: #232a21;
  --fg: #e0dccf;
  --fg-soft: #c4bfae;
  --muted: #858a7d;
  --border: #2e352b;
  --hover-bg: #262c23;

  --accent: #4ea66d;
  --accent-strong: #6bbf85;
  --accent-2: #a0d8b0;
  --accent-title-mid: #6bbf85;
  --accent-glow: rgba(107, 191, 133, 0.22);

  --btn-bg: #1ab358;
  --btn-bg-hover: #14953f;
  --btn-border: #14953f;
  --btn-border-hover: #0f7530;
  --btn-text: #fbf2db;

  --warm: #c98856;
  --warm-soft: rgba(201, 136, 86, 0.14);

  --danger: #e07a64;
  --danger-soft: rgba(224, 122, 100, 0.16);

  --shadow: 0 1px 2px rgba(0, 0, 0, 0.45);
  --shadow-lg: 0 10px 30px rgba(0, 0, 0, 0.6);
}

/* ===================== Base layout ===================== */
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
html { -webkit-text-size-adjust: 100%; }
/* Kill the elastic rubber-band overscroll on iOS Safari PWAs so pulling
 * down at the top of the page doesn't shove the sticky header along
 * with the document. Makes the PWA feel native instead of web-y.
 * Supported on iOS 16+, ignored gracefully on older. */
html, body { overscroll-behavior: none; }
body {
  font-family: var(--font);
  background: var(--bg);
  color: var(--fg);
  font-size: 15px;
  line-height: 1.45;
  min-height: 100vh;
  transition: background 200ms ease, color 200ms ease;
}

/* ---------- header ---------- */
header {
  display: flex; align-items: center; gap: 0.5rem;
  padding: 1rem;
  border-bottom: 1px solid var(--border);
  background: var(--surface);
  position: sticky; top: 0; z-index: 100;
}
.menu-wrapper { flex: 0 0 auto; }
.header-title {
  display: flex; align-items: center;
  flex: 1; min-width: 0;
}
header h1 {
  margin: 0;
  font-size: 1.3rem; font-weight: 700; letter-spacing: -0.01em;
  line-height: 1.2;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  background: linear-gradient(90deg, var(--accent) 0%, var(--accent-title-mid) 50%, var(--accent-2) 100%);
  -webkit-background-clip: text; background-clip: text; color: transparent;
  cursor: pointer;
  user-select: none;
}
header h1:focus-visible {
  outline: 2px solid var(--accent-strong); outline-offset: 4px;
  border-radius: 4px;
}
.header-right { flex: 0 0 auto; }

.icon-btn {
  background: transparent; border: 1px solid transparent;
  color: var(--fg-soft);
  width: 46px; height: 46px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 999px;
  font-size: 1.45rem; cursor: pointer;
  transition: background 120ms ease, color 120ms ease, border-color 120ms ease, transform 120ms ease;
}
@media (hover: hover) and (pointer: fine) {
  .icon-btn:hover { background: var(--hover-bg); color: var(--fg); border-color: var(--accent-strong); }
}
.icon-btn:active { transform: scale(0.96); border-color: var(--accent-strong); background: var(--hover-bg); }
.icon-btn:focus-visible { outline: 2px solid var(--accent-strong); outline-offset: 2px; }
#menu-btn svg { width: 22px; height: 22px; display: block; }

.initials-btn {
  background: var(--surface-2);
  border: 1px solid var(--border);
  color: var(--fg);
  font: inherit; font-weight: 600; font-size: 0.85rem;
  letter-spacing: 0.02em;
  width: 40px; height: 40px;
  border-radius: 999px;
  display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer;
  transition: background 120ms ease, border-color 120ms ease, transform 120ms ease;
}
@media (hover: hover) and (pointer: fine) {
  .initials-btn:hover { border-color: var(--accent); background: var(--hover-bg); }
}
.initials-btn:active { transform: scale(0.96); }
.initials-btn:focus-visible { outline: 2px solid var(--accent-strong); outline-offset: 2px; }
.initials-btn[hidden] { display: none; }

@media (max-width: 480px) {
  header { padding: 0.8rem 1rem; gap: 0.15rem; }
  header h1 { font-size: 1.33rem; }
  .icon-btn { width: 40px; height: 40px; font-size: 1.2rem; }
  #menu-btn { width: 41px; height: 41px; }
  #menu-btn svg { width: 30px; height: 30px; }
  .initials-btn { width: 34px; height: 34px; font-size: 0.78rem; }
}

/* ---------- drawer (opens from LEFT) ---------- */
.menu-dropdown {
  position: fixed; top: 0; left: 0; bottom: 0;
  width: min(280px, 82vw);
  background: var(--surface);
  border-right: 1px solid var(--border);
  box-shadow: 4px 0 20px rgba(0, 0, 0, 0.18);
  /* padding-top is 0 on purpose — the brand element below mirrors the
     header's own padding so its border-bottom lines up exactly with
     the page header's border-bottom when the drawer is open. */
  padding: 0 0.85rem 2.5rem;
  z-index: 200;
  display: flex; flex-direction: column; gap: 0.35rem;
  transform: translateX(-100%);
  transition: transform 0.22s ease;
  pointer-events: none;
}
.menu-dropdown.is-open { transform: translateX(0); pointer-events: auto; }

.menu-backdrop {
  position: fixed; inset: 0;
  background: rgba(0, 0, 0, 0.5);
  z-index: 150;
  opacity: 0; pointer-events: none;
  transition: opacity 0.22s ease;
}
.menu-backdrop.is-open { opacity: 1; pointer-events: auto; }

.menu-brand {
  /* Match the page <header>'s ACTUAL height, not the h1's line-box.
     The header is a flex row containing the burger button (46×46) +
     h1, so the burger dominates: header height = 2 × 1rem padding +
     46px burger = 78px. Setting min-height + flex centering here
     gives the brand the same box height as the header, so the
     border-bottom lines up across the drawer/page boundary. */
  min-height: 78px;
  display: flex; align-items: center;
  padding: 0 0.85rem;
  margin-bottom: 0.5rem;
  font-size: 1.3rem; font-weight: 700; letter-spacing: -0.01em;
  line-height: 1.2;
  background: linear-gradient(90deg, var(--accent) 0%, var(--accent-title-mid) 50%, var(--accent-2) 100%);
  -webkit-background-clip: text; background-clip: text; color: transparent;
  border-bottom: 1px solid var(--border);
}
@media (max-width: 480px) {
  /* Mobile header: 2 × 0.8rem padding + 41px burger = 66.6px. */
  .menu-brand { min-height: 66.6px; font-size: 1.33rem; }
}

.menu-item {
  display: flex; align-items: center; gap: 0.6rem;
  width: 100%;
  background: transparent; border: none;
  padding: 0.65rem 0.85rem;
  color: var(--fg-soft);
  font: inherit; font-size: 0.95rem;
  text-align: left; cursor: pointer;
  border-radius: var(--radius-sm);
  transition: background 100ms ease, color 100ms ease;
}
@media (hover: hover) and (pointer: fine) {
  .menu-item:hover:not(.menu-item-disabled) { background: var(--hover-bg); color: var(--fg); }
}
.menu-item:focus-visible { outline: 2px solid var(--accent-strong); outline-offset: -2px; }
.menu-item-disabled { opacity: 0.5; cursor: default; }
.menu-item[hidden] { display: none; }
.menu-soon {
  margin-left: auto; font-size: 0.7rem; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.05em;
  color: var(--muted);
  padding: 2px 7px; border-radius: 999px;
  background: var(--surface-2);
}
.menu-divider {
  margin: 0.5rem 0 0;
  border: none; border-top: 1px solid var(--border);
  opacity: 0.6;
}
.menu-divider[hidden] { display: none; }
.menu-account-info {
  padding: 0.55rem 0.85rem 0.25rem;
  color: var(--muted);
  font-size: 0.8rem;
  word-break: break-word;
  line-height: 1.35;
}
.menu-account-info[hidden] { display: none; }
.menu-footer {
  margin-top: auto; padding: 0.5rem 0.85rem 0;
}
.online-pill { font-size: 0.78rem; color: var(--accent); }
.online-pill.offline { color: var(--muted); }
.menu-footer-credit {
  /* Sits in the flex flow directly below .menu-footer (online pill).
     padding-bottom uses env(safe-area-inset-bottom) so the iPhone PWA
     home-indicator / screen curvature doesn't clip the text. */
  margin-top: 0.4rem;
  padding: 0 0.85rem env(safe-area-inset-bottom, 0px);
  font-size: 0.65rem; letter-spacing: 0.03em;
  color: var(--muted); opacity: 0.55;
  text-align: left;
}

/* ---------- main + cards ---------- */
main { max-width: 720px; margin: 0 auto; padding: 1rem 1rem 2rem; }

.card {
  margin: 0 0 1rem; padding: 1.1rem 1.1rem 1.25rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.card h2 {
  margin: 0 0 0.85rem 0;
  font-size: 0.72rem; font-weight: 700;
  color: var(--muted);
  text-transform: uppercase; letter-spacing: 0.08em;
}
.muted { color: var(--muted); }
.muted-tiny { color: var(--muted); font-size: 0.78rem; }

a { color: var(--accent-strong); text-decoration: none; }
a:hover { text-decoration: underline; }

/* ---------- buttons ---------- */
.btn,
.btn-primary,
.btn-neutral {
  font: inherit; font-weight: 500;
  cursor: pointer;
  padding: 0.55rem 1rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--fg);
  display: inline-flex; align-items: center; justify-content: center;
  gap: 0.4rem;
  transition: background 140ms ease, border-color 140ms ease, transform 80ms ease, color 140ms ease, box-shadow 140ms ease, filter 140ms ease;
  white-space: nowrap;
}
@media (hover: hover) and (pointer: fine) {
  .btn:hover { background: var(--hover-bg); border-color: var(--accent-strong); }
  .btn-neutral:hover { background: var(--hover-bg); border-color: var(--accent-strong); }
}
/* Tap-flash on touch devices — quick accent border that fades back via the
 * existing 120ms border-color transition on release. */
.btn:active:not(.btn-primary):not(.btn-danger),
.btn-neutral:active {
  border-color: var(--accent-strong);
  background: var(--hover-bg);
}
.btn:active, .btn-primary:active, .btn-neutral:active, .btn-danger:active { transform: scale(0.98); }
.btn:focus-visible, .btn-primary:focus-visible, .btn-neutral:focus-visible {
  outline: 2px solid var(--accent-strong); outline-offset: 2px;
}

.btn-primary {
  background: var(--btn-bg);
  color: var(--btn-text);
  border: 1px solid var(--btn-border);
  font-weight: 600;
  box-shadow: none;
}
@media (hover: hover) and (pointer: fine) {
  .btn-primary:hover { background: var(--btn-bg-hover); border-color: var(--btn-border-hover); }
}
.btn-primary:disabled,
.btn-primary[disabled] {
  background: var(--surface-2);
  color: var(--muted);
  border-color: var(--border);
  box-shadow: none;
  cursor: not-allowed;
  filter: none;
}
.btn-neutral {
  background: var(--surface-2);
  color: var(--fg);
  border-color: var(--border);
}

/* Danger variant — neutral at rest, red only on hover.
 * Wife sees "Reject" / "Mark dead" as calm grey buttons that go red on
 * intent (mouse hover), not aggressive crimson on first paint. */
.btn-danger {
  font: inherit; font-weight: 500;
  cursor: pointer;
  padding: 0.55rem 1rem;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  color: var(--fg);
  border: 1px solid var(--border);
  transition: background 120ms ease, border-color 120ms ease, color 120ms ease;
  white-space: nowrap;
}
@media (hover: hover) and (pointer: fine) {
  .btn-danger:hover {
    background: #5a2222;
    border-color: #a04545;
    color: #ffd9d9;
  }
}
.btn-danger:active { transform: scale(0.98); }
.btn-danger:focus-visible {
  outline: 2px solid #a04545; outline-offset: 2px;
}

@media (max-width: 599px) {
  .btn, .btn-primary, .btn-neutral, .btn-danger {
    padding: 0.42rem 0.85rem;
    font-size: 0.88rem;
  }
}

/* ---------- forms ---------- */
.field { display: flex; flex-direction: column; gap: 0.3rem; margin-bottom: 0.85rem; }
.field label { font-size: 0.78rem; color: var(--muted); }
/* Text-like inputs only — checkboxes / radios are handled by their own rules
 * below and must not pick up width:100% / min-height:40px from here. */
.field input:not([type="checkbox"]):not([type="radio"]),
.field textarea {
  font: inherit; font-size: 0.95rem;
  padding: 0.6rem 0.75rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--fg);
  width: 100%;
  min-height: 40px;
  transition: border-color 120ms ease, box-shadow 120ms ease;
}
/* Default to vertical-only resize — free horizontal resize lets the
 * textarea expand past its parent card and pushes the rest of the page
 * sideways. Vertical-only matches the chat-form pattern below. */
.field textarea { resize: vertical; }
.field input:not([type="checkbox"]):not([type="radio"]):focus,
.field textarea:focus {
  outline: none; border-color: var(--accent-strong);
  box-shadow: 0 0 0 3px var(--accent-glow);
}
.field input[disabled] { opacity: 0.7; cursor: not-allowed; background: var(--surface-2); }

/* ---------- segmented control (radios-as-pills, lifted from net-tracker) ----
 * A single .seg-indicator behind the buttons slides to the active one via
 * transform + width. JS (shared/seg.js) positions it on render and on each
 * click. */
.seg-group {
  position: relative;
  display: flex; flex-wrap: wrap;
  width: 100%;
  padding: 4px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 10px;
  gap: 4px;
}
.seg-indicator {
  position: absolute;
  top: 4px; bottom: 4px;
  left: 0; width: 0;
  /* Use the solid primary-button color we settled on, not a forest gradient. */
  background: var(--btn-bg);
  border-radius: 7px;
  transform: translateX(0);
  transition: transform 320ms cubic-bezier(0.4, 0, 0.2, 1),
              width 320ms cubic-bezier(0.4, 0, 0.2, 1);
  pointer-events: none;
  z-index: 0;
  opacity: 0;
}
.seg-indicator.is-ready { opacity: 1; }
.seg-group button {
  position: relative;
  z-index: 1;
  flex: 1 1 auto;
  background: transparent; border: 0;
  color: var(--muted);
  font: inherit; font-size: 0.9rem; font-weight: 500;
  padding: 0.5rem 0.85rem;
  border-radius: 7px;
  cursor: pointer;
  white-space: nowrap;
  min-height: 32px;
  -webkit-tap-highlight-color: transparent;
  transition: color 280ms cubic-bezier(0.4, 0, 0.2, 1);
}
.seg-group button:hover { color: var(--fg-soft); }
.seg-group button.active { color: var(--btn-text); }
.seg-group.seg-pill { border-radius: 999px; }
.seg-group.seg-pill button { border-radius: 999px; }
.seg-group.seg-pill .seg-indicator { border-radius: 999px; }

@media (max-width: 599px) {
  .seg-group button {
    padding: 0.42rem 0.7rem;
    font-size: 0.85rem;
    min-height: 30px;
  }
}

/* ---------- themed checkbox (.tk-checkbox, lifted from net-tracker) ----
 * Opt-in via class so we don't accidentally restyle 3rd-party form inputs. */
input[type="checkbox"].tk-checkbox {
  appearance: none;
  -webkit-appearance: none;
  width: 18px;
  height: 18px;
  border: 1.5px solid var(--border);
  border-radius: 5px;
  background: var(--surface-2);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  margin: 0;
  position: relative;
  transition: border-color 120ms ease, background 120ms ease, box-shadow 120ms ease;
}
@media (hover: hover) and (pointer: fine) {
  input[type="checkbox"].tk-checkbox:hover { border-color: var(--accent); }
}
input[type="checkbox"].tk-checkbox:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px var(--accent-glow);
  border-color: var(--accent);
}
input[type="checkbox"].tk-checkbox:checked {
  background: var(--btn-bg);
  border-color: var(--btn-border);
}
input[type="checkbox"].tk-checkbox:checked::after {
  content: "";
  width: 5px;
  height: 9px;
  border: solid var(--btn-text);
  border-width: 0 2px 2px 0;
  transform: rotate(45deg) translate(-1px, -1px);
}
input[type="checkbox"].tk-checkbox:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

@media (max-width: 599px) {
  .field input:not([type="checkbox"]):not([type="radio"]),
  .field textarea {
    min-height: 36px;
    padding: 0.5rem 0.7rem;
    font-size: 16px;
  }
}

[hidden] { display: none !important; }

/* ---------- spinner ---------- */
.view-loading {
  display: grid; place-items: center; padding: 48px 0; color: var(--muted);
}
.spinner {
  width: 24px; height: 24px; border-radius: 50%;
  border: 3px solid var(--border); border-top-color: var(--accent-strong);
  animation: spin 0.9s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ---------- dialogs ---------- */
dialog {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface); color: var(--fg);
  max-width: 440px; width: 92%;
  padding: 1.1rem 1.1rem 0.9rem;
  box-shadow: var(--shadow-lg);
}
dialog::backdrop { background: rgba(0, 0, 0, 0.55); }
/* The custom date picker inside this dialog uses position:absolute for its
 * popup; default dialog overflow:auto clips it and adds a scrollbar instead.
 * Set overflow:visible so the calendar pops out cleanly. */
#edit-obs-dialog { overflow: visible; }
dialog h3 { margin-top: 0; margin-bottom: 0.6rem; font-size: 1.05rem; }
dialog form { margin: 0; }
dialog menu {
  display: flex; gap: 0.5rem; justify-content: flex-end;
  padding: 0; margin: 1rem 0 0;
}
dialog menu button {
  font: inherit; font-weight: 500;
  padding: 0.55rem 0.95rem; border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--surface); color: var(--fg);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background 120ms ease, border-color 120ms ease, filter 120ms ease;
}
dialog menu button:focus { outline: none; }
dialog menu button:focus-visible {
  outline: 2px solid var(--accent-strong); outline-offset: 2px;
}
dialog menu button[value="save"] {
  background: var(--btn-bg);
  color: var(--btn-text);
  border-color: var(--btn-border);
  font-weight: 600;
}
dialog menu button[value="save"].dialog-danger-confirm {
  background: linear-gradient(180deg, #c1543f 0%, #a8412e 100%);
  color: #fff;
  border-color: #872d1e;
}
@media (hover: hover) and (pointer: fine) {
  dialog menu button:hover { background: var(--hover-bg); border-color: var(--accent-strong); }
  dialog menu button[value="save"]:hover {
    background: var(--btn-bg-hover); border-color: var(--btn-border-hover);
  }
  dialog menu button[value="save"].dialog-danger-confirm:hover {
    /* Stay red on hover — the [value="save"]:hover rule above otherwise
     * paints the affirmative-green hover background over the danger gradient. */
    background: linear-gradient(180deg, #c1543f 0%, #a8412e 100%);
    border-color: #872d1e;
    filter: brightness(1.07);
  }
}
/* Tap-flash for dialog Cancel-style buttons. */
dialog menu button:not([value="save"]):active {
  background: var(--hover-bg); border-color: var(--accent-strong);
}
/* Empty-input disabled state: muted grey, no hover tint, no filter brightness. */
dialog menu button[value="save"]:disabled,
dialog menu button[value="save"][disabled] {
  background: var(--surface-2);
  color: var(--muted);
  border-color: var(--border);
  cursor: not-allowed;
  filter: none;
}
dialog menu button[value="save"]:disabled:hover,
dialog menu button[value="save"][disabled]:hover { filter: none; }
@media (max-width: 479px) {
  dialog { padding: 0.95rem 0.9rem 0.8rem; }
  dialog menu button { padding: 0.45rem 0.82rem; font-size: 0.87rem; }
}

/* ---------- date picker ---------- */
.dp { position: relative; display: block; width: 100%; }
.dp-trigger {
  display: flex; align-items: center; justify-content: space-between;
  width: 100%;
  padding: 0.55rem 0.7rem;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--fg);
  font: inherit; font-size: 0.95rem;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: border-color 120ms ease, box-shadow 120ms ease;
}
@media (hover: hover) and (pointer: fine) {
  .dp-trigger:hover { border-color: var(--accent-strong); }
}
.dp-trigger:focus { outline: none; border-color: var(--accent-strong); box-shadow: 0 0 0 3px var(--accent-glow); }
.dp-trigger-placeholder { color: var(--muted); }
.dp-trigger-icon {
  display: inline-flex; align-items: center;
  color: var(--muted);
  margin-left: 0.5rem;
}
.dp.dp-open .dp-trigger-icon { color: var(--accent-strong); }

.dp-popup {
  display: none;
  position: absolute; z-index: 60;
  top: calc(100% + 6px); left: 50%;
  transform: translateX(-50%);
  width: 280px;
  padding: 0.6rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-lg);
}
.dp.dp-open .dp-popup { display: block; }
.dp-header {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 0.4rem;
}
.dp-title { font-weight: 600; font-size: 0.95rem; }
.dp-nav {
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 6px;
  width: 28px; height: 28px;
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--fg);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
@media (hover: hover) and (pointer: fine) {
  .dp-nav:hover { background: var(--hover-bg); border-color: var(--accent-strong); }
}
.dp-weekdays {
  display: grid; grid-template-columns: repeat(7, 1fr);
  text-align: center;
  font-size: 0.7rem; color: var(--muted);
  text-transform: uppercase; letter-spacing: 0.05em;
  margin-bottom: 0.25rem;
}
.dp-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.dp-day {
  background: transparent;
  border: 1px solid transparent;
  border-radius: 6px;
  padding: 0;
  height: 34px;
  display: flex; align-items: center; justify-content: center;
  color: var(--fg);
  font: inherit; font-size: 0.85rem;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background 120ms ease, border-color 120ms ease;
}
@media (hover: hover) and (pointer: fine) {
  .dp-day:hover:not([disabled]) { background: var(--hover-bg); }
}
.dp-day-other { color: var(--muted); opacity: 0.45; }
.dp-day-disabled { color: var(--muted); opacity: 0.3; cursor: not-allowed; }
.dp-day-today { border-color: var(--accent-strong); }
.dp-day-selected,
.dp-day-selected:hover {
  background: var(--btn-bg);
  color: var(--btn-text);
  border-color: var(--btn-border);
  font-weight: 600;
}
.dp-footer { display: flex; justify-content: flex-end; margin-top: 0.5rem; }
.dp-today-btn {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--fg);
  padding: 0.3rem 0.7rem;
  border-radius: 6px;
  font: inherit; font-size: 0.82rem;
  cursor: pointer;
}
@media (hover: hover) and (pointer: fine) {
  .dp-today-btn:hover { background: var(--hover-bg); border-color: var(--accent-strong); }
}
@media (max-width: 480px) {
  .dp-popup { width: 260px; padding: 0.5rem; }
  .dp-day { height: 36px; font-size: 0.9rem; }
}

/* ---------- square icon button (28x28) ---------- */
.icon-btn-square {
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 6px;
  width: 28px; height: 28px;
  color: var(--fg);
  cursor: pointer;
  padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  flex: 0 0 auto;
  transition: background 120ms ease, border-color 120ms ease, color 120ms ease;
  -webkit-tap-highlight-color: transparent;
}
.icon-btn-square > svg { width: 14px; height: 14px; display: block; }
@media (hover: hover) and (pointer: fine) {
  .icon-btn-square:hover { border-color: var(--accent-strong); background: var(--hover-bg); }
}
.icon-btn-square:active { border-color: var(--accent-strong); }
.icon-btn-square:focus-visible {
  outline: 2px solid var(--accent-strong); outline-offset: 2px;
}

/* ---------- toast ---------- */
#toast { transition: opacity 200ms ease; }

/* ---------- pull-to-refresh indicator ---------- */
/* A floating circular badge that descends from above the viewport
 * during a downward pull on the home view. Sized + coloured to read
 * as a refresh affordance (circular-arrow icon) at rest; switches to
 * a continuous spin while the underlying refresh is in flight. The
 * starting position is translateY(-100%) — i.e. its full height
 * above the top of the viewport — so it's invisible until the JS
 * starts setting a positive translateY based on finger position. */
.home-pull-indicator {
  position: fixed;
  top: 0;
  left: 50%;
  /* The transform is rewritten by JS during a pull; the rest of this
   * declaration is the at-rest baseline. The 200ms transition gives
   * a smooth snap-back when the pull was released without crossing
   * the threshold. */
  transform: translate(-50%, -100%);
  display: flex; align-items: center; justify-content: center;
  width: 40px; height: 40px;
  border-radius: 50%;
  background: var(--surface);
  border: 1px solid var(--accent-strong);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.18);
  z-index: 200;
  pointer-events: none;
  color: var(--accent-strong);
  opacity: 0;
  transition: transform 220ms ease, opacity 220ms ease, background 120ms ease;
}
.home-pull-indicator > svg { width: 18px; height: 18px; }
.home-pull-indicator.is-ready {
  background: var(--accent-glow);
}
.home-pull-indicator.is-loading > svg {
  animation: home-pull-spin 700ms linear infinite;
}
@keyframes home-pull-spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

/* ---------- post header + dialog ---------- */
.card-head {
  display: flex; justify-content: space-between; align-items: center;
  gap: 12px; margin-bottom: 12px;
}
/* Re-use .field textarea styling for the new-post dialog textarea — it's
 * already inside a .field so this comment is for grep-discoverability only. */

/* ---------- sticky-note posts ---------- */
/* Grid is locked to 2 columns on every viewport: keeps the layout
 * predictable and the sticky aspect ratio square-ish on phones. Combined
 * with the max-height that means ~4 stickies (2 rows × 2 cols) are
 * visible before the scroll viewport kicks in. */
.posts-scroll {
  max-height: 320px;
  /* overflow-x must be explicit — setting only overflow-y: auto computes
   * overflow-x to auto as well per spec, and the sticky rotation transform
   * triggers a horizontal scrollbar in that case. */
  overflow-x: hidden;
  overflow-y: auto;
  scrollbar-width: thin;
}
/* The pinned board reuses .posts-scroll markup but holds at most a couple
 * of stickies — no max-height, and overflow stays visible so the 3-dot
 * menu can drop below the single row instead of being clipped at the
 * board's bottom edge (.card doesn't clip). */
#pinned-scroll {
  max-height: none;
  overflow: visible;
}
.post-grid {
  display: grid;
  gap: 12px;
  /* `minmax(0, 1fr)` instead of plain `1fr` so a child with an
   * intrinsic min-width (e.g. a long word in a meta line, or an
   * absolutely-positioned popover whose layout cost iOS Safari
   * surprisingly attributes to its host) can't push the column
   * wider than the grid's fair share. Without the minmax, the 2nd
   * sticky on iPhone was getting shoved off the right edge of
   * `.posts-scroll` (overflow-x: hidden) and the user only saw the
   * first one and a half cards. */
  grid-template-columns: repeat(2, minmax(0, 1fr));
  /* Stop short stickies from stretching to match the row's tallest sibling
   * — each note should be sized to its own content, not the longest post
   * it happens to land beside. Row height is still the max of the row, so
   * a visible gap appears under the short item against the page background;
   * that's the desired "sticky-notes on a board" feel. */
  align-items: start;
}
@media (max-width: 599px) {
  .post-grid { gap: 10px; }
  /* One full row of stickies + half the next visible, so the scroll
   * affordance is obvious. Card height (185px) plus row gap, give or
   * take padding. */
  .posts-scroll { max-height: 280px; }
  /* Mobile stickies are roughly half the previous width, so trim padding,
   * shrink the avatar a touch, and step the body text down so the whole
   * note reads as a small square instead of a stretched landscape card.
   * Fixed height (162px) is sized to fit head + 2-line body + "Show more"
   * + foot at mobile typography. */
  .sticky { padding: 10px 12px 12px; gap: 4px; height: 150px; }
  .sticky-head { margin-bottom: 6px; gap: 6px; }
  .sticky-avatar { flex: 0 0 24px; height: 24px; width: 24px; font-size: 0.7rem; }
  .sticky-meta { font-size: 0.7rem; }
  .sticky-body { font-size: 0.88rem; line-height: 1.35; }
  .sticky-foot { gap: 6px; }
  .sticky-seen { font-size: 0.68rem; }
  .sticky-more { font-size: 0.72rem; }
}
.posts-sentinel,
.posts-end {
  display: flex;
  justify-content: center;
  padding: 14px 0;
  color: var(--muted);
  font-size: 0.85rem;
}
/* Card-scoped loading state — shared between every section on Home
 * (posts, pinned, recent observations, unsubmitted notes) so a pull-
 * to-refresh shows the same earthy-moss spinner + tiny caption in
 * each card simultaneously. The first-page posts variant additionally
 * honours MIN_FIRST_PAGE_SPINNER_MS so a fast API response doesn't
 * flicker. */
.card-loading {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 24px 0;
  color: var(--muted);
}
.card-loading > .gallery-spinner { width: 28px; height: 28px; border-width: 2px; }
/* When the loader is injected into a .post-grid (pinned card during
 * refresh), it would otherwise occupy a single grid cell and read as
 * left-aligned. Span all columns so the spinner + caption land flush
 * in the middle of the card like every other section. */
.post-grid > .card-loading { grid-column: 1 / -1; }
.sticky {
  display: flex; flex-direction: column;
  padding: 12px 14px 14px;
  /* Fixed height — every sticky reserves exactly the room for head +
   * 2-line clamped body + "Show more" + seen-by foot. Combined with
   * `margin-top: auto` on `.sticky-foot`, this guarantees the foot
   * pins to the bottom of every card no matter how short the body
   * is, so the post grid never reads as ragged. */
  height: 164px;
  border-radius: 10px;
  border: 1px solid rgba(0, 0, 0, 0.08);
  box-shadow:
    0 1px 1px rgba(0, 0, 0, 0.08),
    0 8px 16px -8px rgba(0, 0, 0, 0.20),
    inset 0 0 0 1px rgba(255, 255, 255, 0.25);
  color: #1f2620;
  position: relative;
  transition: border-color 120ms ease, box-shadow 120ms ease;
}
@media (hover: hover) and (pointer: fine) {
  .sticky:hover {
    border-color: var(--btn-bg);
    /* INSET emerald ring — outer rings get clipped by overflow-x:hidden
     * on .posts-scroll and by adjacent stickies' opaque tints, leaving an
     * uneven half-visible highlight. Inset paints inside the box so it's
     * always fully visible regardless of neighbors. */
    box-shadow:
      inset 0 0 0 2px var(--btn-bg),
      0 1px 1px rgba(0, 0, 0, 0.08),
      0 8px 16px -8px rgba(0, 0, 0, 0.20),
      inset 0 0 0 1px rgba(255, 255, 255, 0.25);
  }
}
/* No pinned-state outline — the pin icon + "· pinned" label already
 * communicate the state, and the green ring was visually loud
 * especially in the Pinned section where every card had it. */
.sticky-tint-0 { background: #fbf2db; }
.sticky-tint-1 { background: #d9e8d0; }
.sticky-tint-2 { background: #f5d9c5; }
.sticky-tint-3 { background: #e3dff1; }
.sticky-tint-4 { background: #d8e7ef; }

.sticky-head {
  display: flex; align-items: center; gap: 8px;
  margin-bottom: 8px;
}
.sticky-avatar {
  flex: 0 0 26px;
  height: 26px; width: 26px;
  border-radius: 50%;
  background: rgba(31, 38, 32, 0.85);
  color: #fbf2db;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 0.72rem; font-weight: 700;
  letter-spacing: 0.02em;
  border: 0;
  padding: 0;
  font-family: inherit;
}
/* Tappable variant — only when the author has a status to show. The
 * subtle ring + cursor signals it's interactive without making every
 * avatar look like a button. */
.sticky-avatar.has-status {
  cursor: pointer;
  box-shadow: 0 0 0 1px rgba(251, 242, 219, 0.18);
}
@media (hover: hover) and (pointer: fine) {
  .sticky-avatar.has-status:hover {
    box-shadow: 0 0 0 2px var(--accent-strong);
  }
}
.sticky-avatar.has-status:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px var(--accent-strong);
}
.sticky-meta {
  flex: 1;
  /* `min-width: 0` lets the flex item shrink below its intrinsic
   * content size; `overflow + ellipsis + nowrap` then clip a long
   * "· edited" suffix instead of pushing the pin / menu past the
   * sticky's right edge (which the grid would clip with overflow-x:
   * hidden and the user would see as "the buttons disappeared"). */
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: rgba(31, 38, 32, 0.55);
  font-size: 0.74rem;
}
.sticky-body {
  font-size: 0.95rem;
  white-space: pre-wrap;
  word-break: break-word;
  line-height: 1.4;
  /* Cap each note at 2 lines so every sticky on the board converges to
   * the same height regardless of body length — eliminates the "gap
   * under the short post above the next row" problem entirely. JS
   * detects `scrollHeight > clientHeight` after layout, tags the body
   * with `is-clipped`, and appends a "Show more" link that opens the
   * full body in a modal. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.sticky-body.is-clipped { cursor: pointer; }
.sticky-more {
  margin-top: 4px;
  align-self: flex-start;
  background: transparent;
  border: 0;
  padding: 0;
  font: inherit; font-size: 0.78rem; font-weight: 600;
  color: var(--accent-strong, #2e8b57);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.sticky-more:hover { text-decoration: underline; }
.sticky-foot {
  display: flex;
  align-items: flex-end;
  gap: 8px;
  /* Pin to the bottom of the fixed-height sticky. The card is a column
   * flex; `margin-top: auto` consumes whatever vertical room is left
   * after head + body + (optional) "Show more", so the seen-by line
   * always lands flush with the card bottom. Empty foot still occupies
   * a no-height slot at the bottom, which is exactly what we want. */
  margin-top: auto;
  min-height: 0;
}
.sticky-seen {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 0.7rem;
  color: rgba(31, 38, 32, 0.6);
  line-height: 1.3;
  word-break: break-word;
}

/* 3-dot action menu trigger — vertical glyph, narrow footprint. The
 * negative right margin pulls the glyph past the sticky's content
 * padding so the dots land closer to the visible card edge (the
 * head was reading as "drift left" with a comfortable padding gap
 * to the right of the icon). The "pressed" state uses opacity only
 * — the green accent-glow background read as a heavy active-state
 * for a button that's really just a menu trigger. */
.sticky-menu-btn {
  flex: 0 0 auto;
  background: transparent;
  border: 0;
  padding: 2px 2px 2px 4px;
  margin-right: -4px;
  line-height: 0;
  border-radius: 6px;
  color: inherit;
  cursor: pointer;
  opacity: 0.6;
  transition: opacity 120ms ease;
  -webkit-tap-highlight-color: transparent;
}
@media (hover: hover) and (pointer: fine) {
  .sticky-menu-btn:hover { opacity: 1; }
}
.sticky-menu-btn:focus-visible {
  outline: none;
  opacity: 1;
}
.sticky-menu-btn[aria-expanded="true"] { opacity: 1; }
/* Anchored popover. The menu's right edge aligns to its trigger;
 * width is capped at the host card's width so it can never overflow
 * the column on a mobile-narrow sticky. Theme-aware: `var(--surface)`
 * resolves to white in light mode and `#1a2018` in dark, so the menu
 * always carries the same surface tone as the rest of the app and
 * the item text (`var(--fg)`) is high-contrast in both palettes.
 * The deep moss border + accent-glow hover are the same in both. */
.sticky-menu {
  position: absolute;
  top: calc(100% + 4px);
  right: 0;
  z-index: 60;
  display: none;
  flex-direction: column;
  /* Sized to its widest item (`white-space: nowrap`); a tight
   * min-width keeps short-only menus from collapsing too narrow. */
  min-width: 96px;
  max-width: 100%;
  padding: 3px;
  background: var(--surface);
  border: 1px solid var(--accent-strong);
  border-radius: 8px;
  box-shadow: var(--shadow-lg);
  color: var(--fg);
}
.sticky-menu.is-shown { display: flex; }
/* Drop upward when the default top-anchor would clip against the
 * scroll container's bottom edge — JS flips this class on open per
 * `getBoundingClientRect()` so the menu stays inside the viewport. */
.sticky-menu.drops-up {
  top: auto;
  bottom: calc(100% + 4px);
}
.sticky-menu-item {
  background: transparent;
  border: 0;
  padding: 6px 10px;
  margin: 0;
  font: inherit; font-size: 0.78rem;
  text-align: left;
  border-radius: 5px;
  color: inherit;
  cursor: pointer;
  white-space: nowrap;
  -webkit-tap-highlight-color: transparent;
}
@media (hover: hover) and (pointer: fine) {
  .sticky-menu-item:hover {
    background: var(--accent-glow);
    color: var(--accent-strong);
  }
}
.sticky-menu-item:focus-visible {
  outline: none;
  background: var(--accent-glow);
  color: var(--accent-strong);
  box-shadow: inset 0 0 0 2px var(--accent-strong);
}
.sticky-menu-item-danger {
  color: var(--danger);
}
@media (hover: hover) and (pointer: fine) {
  .sticky-menu-item-danger:hover {
    background: var(--danger-soft);
    color: var(--danger);
  }
}

/* Author-status popover — anchored to the TOP of the avatar (drops
 * down below it) with a dark Slack-style tooltip look. Only
 * rendered when the author has a status_tag, only shown when JS
 * toggles .is-shown. The .sticky-head needs `position: relative` so
 * the absolute positioning lands inside the note. */
.sticky-head { position: relative; }
.sticky-avatar-pop {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  background: #1f2620;
  color: #fbf2db;
  padding: 6px 10px;
  border-radius: 6px;
  font-size: 0.78rem;
  white-space: normal;
  line-height: 1.35;
  width: max-content;
  max-width: min(260px, 80vw);
  box-shadow: var(--shadow-lg);
  opacity: 0;
  pointer-events: none;
  transform: translateY(-2px);
  transition: opacity 120ms ease, transform 120ms ease;
  z-index: 50;
}
.sticky-avatar-pop::before {
  content: "";
  position: absolute;
  bottom: 100%; left: 8px;
  border: 5px solid transparent;
  border-bottom-color: #1f2620;
}
.sticky-avatar-pop.is-shown {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}


/* ---------- activity (Home) ---------- */
.activity-row {
  display: flex; flex-direction: column; gap: 4px;
  padding: 10px 4px;
  border-bottom: 1px solid var(--border);
  text-decoration: none; color: inherit;
}
.activity-row:last-child { border-bottom: none; }
.activity-row:hover { background: var(--hover-bg); }
.activity-head { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; }
.activity-snippet { font-size: 0.9rem; word-break: break-word; }

.muted-tiny { font-size: 0.78rem; color: var(--muted); }

/* ---------- pending (unsubmitted) drafts ---------- */
.pending-row {
  display: flex; flex-direction: column; gap: 4px;
  padding: 10px 4px;
  border-bottom: 1px solid var(--border);
  text-decoration: none; color: inherit;
}
.pending-row:last-child { border-bottom: none; }
@media (hover: hover) and (pointer: fine) {
  .pending-row:hover { background: var(--hover-bg); }
}
.pending-head { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; }
.pending-snippet {
  font-size: 0.9rem; word-break: break-word;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}

/* ---------- colonies / dead colonies ---------- */
/* Small neutral link under the species dropdown in the new-colony dialog
 * that toggles the inline "add new species" textbox. */
.dlg-add-toggle {
  background: transparent; border: 0; padding: 0;
  margin: 6px 0 0; font: inherit; font-size: 0.8rem;
  color: var(--muted); cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
@media (hover: hover) and (pointer: fine) {
  .dlg-add-toggle:hover { color: var(--accent-strong, #c3845a); }
}
.dlg-add-toggle:focus-visible { outline: none; color: var(--accent-strong, #c3845a); }
#new-colony-new-species-field { margin-top: 8px; }
.species-section { margin-bottom: 18px; }
.species-head {
  display: flex; align-items: center; gap: 10px;
  width: 100%;
  cursor: pointer; user-select: none;
  padding: 10px 12px;
  margin-bottom: 8px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: inherit;
  font: inherit; font-weight: 600; font-size: 0.95rem;
  text-align: left;
  position: relative;
  -webkit-tap-highlight-color: transparent;
  transition: background 120ms ease, border-color 120ms ease;
}
.species-head::before {
  content: "";
  position: absolute; left: 0; top: 6px; bottom: 6px; width: 3px;
  background: var(--btn-bg);
  border-radius: 3px;
}
@media (hover: hover) and (pointer: fine) {
  .species-head:hover { background: var(--hover-bg); border-color: var(--muted); }
}
.species-head:focus { outline: none; }
.species-head:focus-visible {
  outline: 2px solid var(--accent-strong); outline-offset: 2px;
}
.species-head .caret {
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px;
  transition: transform 200ms ease;
}
.species-head .caret svg { width: 16px; height: 16px; }
.species-section.collapsed .caret { transform: rotate(-90deg); }
.species-section.collapsed .colony-grid { display: none; }
.species-name { flex: 1; }
.species-count {
  font-size: 0.78rem;
  color: var(--muted);
  font-weight: 500;
  background: var(--bg);
  padding: 2px 8px;
  border-radius: 999px;
  border: 1px solid var(--border);
}

.colony-grid {
  display: grid;
  gap: 8px;
  grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
}
.colony-card {
  display: flex; flex-direction: column; gap: 6px;
  padding: 12px 14px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  text-decoration: none; color: inherit;
  box-shadow: var(--shadow);
  transition: transform 120ms ease, box-shadow 120ms ease, border-color 120ms ease;
  -webkit-tap-highlight-color: transparent;
}
@media (hover: hover) and (pointer: fine) {
  .colony-card:hover {
    border-color: var(--btn-border);
    box-shadow: var(--shadow-lg);
    transform: translateY(-1px);
  }
}
.colony-card:active { transform: scale(0.99); }
.colony-card.is-dead { opacity: 0.78; }
.colony-card-head {
  display: flex; justify-content: space-between; align-items: center;
  gap: 8px;
}
.colony-card-code {
  font-weight: 600; font-size: 0.92rem;
  word-break: break-word;
}
.queen-pill {
  flex: 0 0 auto;
  font-size: 0.72rem; font-weight: 600;
  padding: 2px 8px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--muted);
  letter-spacing: 0.02em;
}
.queen-pill.queen-pos {
  background: var(--btn-bg);
  color: var(--btn-text);
  border-color: var(--btn-border);
}
.queen-pill.queen-neg {
  background: #5a2222;
  color: #ffd9d9;
  border-color: #a04545;
}
.colony-card-foot { margin-top: 2px; }

/* Bigger phones in portrait can wrap a colony code or pill onto a second line
 * because the cards live in a 170px-min grid. Shrinking the in-card text 10%
 * on phone-width viewports buys enough horizontal room to keep things tidy.
 * Species headers are intentionally left at full size. */
@media (max-width: 599px) {
  .colony-card-code { font-size: 0.828rem; }
  .colony-card .queen-pill { font-size: 0.648rem; }
  .colony-card-foot.muted-tiny { font-size: 0.702rem; }
}

/* ---------- notes (colony detail) ---------- */
.notes-card { padding-bottom: 12px; }
.notes-backlink {
  display: inline-block;
  font-size: 0.82rem;
  color: var(--muted);
  text-decoration: none;
  margin-bottom: 8px;
  padding: 2px 0;
}
@media (hover: hover) and (pointer: fine) {
  .notes-backlink:hover { color: var(--accent-strong); text-decoration: underline; }
}
.notes-header {
  display: flex; align-items: center; gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 4px;
}
.notes-title {
  flex: 1; min-width: 0;
  display: flex; flex-direction: column; gap: 4px;
}
.notes-code { font-weight: 700; font-size: 1.15rem; word-break: break-word; }
.notes-status {
  display: flex; align-items: center; gap: 8px;
}
.notes-status .queen-pill { font-size: 0.74rem; }
.notes-actions {
  display: flex; gap: 8px; flex: 0 0 auto;
  flex-wrap: wrap; justify-content: flex-end;
}
.setup-details {
  margin-top: 10px;
  border-top: 1px solid var(--border);
  padding-top: 8px;
}
.setup-details summary {
  cursor: pointer; color: var(--muted); font-size: 0.85rem;
  display: flex; align-items: center; gap: 8px;
  list-style: none;
}
/* Default `▾` marker is hidden so the inline caret below can take its place
   — flexbox layout on summary wouldn't position the native marker cleanly
   alongside the edit button. */
.setup-details summary::-webkit-details-marker { display: none; }
.setup-details .caret {
  display: inline-flex; align-items: center; justify-content: center;
  width: 16px; height: 16px;
  transition: transform 200ms ease;
  transform: rotate(-90deg);
}
.setup-details .caret svg { width: 14px; height: 14px; }
.setup-details[open] .caret { transform: rotate(0deg); }
.setup-summary-text { flex: 1; }
.setup-edit { margin-left: auto; }
.setup-body { margin-top: 6px; font-size: 0.9rem; white-space: pre-wrap; }

/* Section-card heading sits tight to the top of its card. */
.section-card .section-title {
  margin-top: 0;
  margin-bottom: 0.7rem;
  font-size: 1rem;
  font-weight: 600;
}
.section-card .section-title .muted { font-weight: 400; }

/* Status text + Submit button row, bottom-right anchored submit. The
 * top margin opens the gap with the chip-row above so the pills don't
 * crowd the Notify-admins/Submit pair. */
.form-actions {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
  margin-top: 22px;
}

.chip-row { display: flex; flex-wrap: wrap; gap: 6px; margin: 8px 0; }
.chip {
  font: inherit; font-size: 0.85rem;
  padding: 6px 10px; border-radius: 999px;
  background: var(--surface-2); color: var(--fg);
  border: 1px solid var(--border);
  cursor: pointer; user-select: none;
  display: inline-flex; align-items: center; gap: 6px;
  transition: background 120ms ease, border-color 120ms ease;
}
@media (hover: hover) and (pointer: fine) {
  .chip:hover:not(:disabled) { background: var(--hover-bg); border-color: var(--accent-strong); }
}
.chip:active:not(:disabled) { background: var(--hover-bg); border-color: var(--accent-strong); }
.chip:disabled,
.chip[disabled] {
  opacity: 0.5;
  cursor: not-allowed;
  color: var(--muted);
}
.chip-stepper { display: inline-flex; align-items: center; gap: 4px; }
.chip-stepper button {
  padding: 0 6px;
  min-width: 22px;
  border: none;
  background: transparent;
  color: inherit;
  cursor: pointer;
  font: inherit;
}

.history-row {
  display: flex; gap: 10px; align-items: flex-start;
  padding: 6px 0;
  transition: background-color 600ms ease;
  border-radius: 6px;
}
.history-row.is-highlighted {
  background: var(--accent-soft, rgba(195, 132, 90, 0.18));
  box-shadow: 0 0 0 2px var(--accent-strong, #c3845a) inset;
  padding: 6px 8px;
}
.history-body { flex: 1; min-width: 0; }
.history-text { white-space: pre-wrap; word-break: break-word; font-size: 0.93rem; }
.history-edit { flex: 0 0 auto; }
.history-actions { display: flex; gap: 6px; flex: 0 0 auto; }
@media (hover: hover) and (pointer: fine) {
  .history-delete:hover { color: #ffd9d9; border-color: #a04545; }
}

/* "Notify admins" checkbox + chip cycle highlight. The label sits inside
 * .form-actions-right (next to Submit) and uses the themed .tk-checkbox. */
.notify-row {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 0.9rem;
  user-select: none; cursor: pointer;
}
.notify-row input[type="checkbox"] { margin: 0; flex: 0 0 auto; }
/* Right-side group inside .form-actions: notify checkbox + Submit button,
 * paired so Submit visually anchors the notify control instead of being
 * pushed to opposite ends of the row by space-between. */
.form-actions-right {
  display: flex; align-items: center; gap: 12px;
}
.form-actions-left {
  display: flex; align-items: center; gap: 10px;
  min-width: 0;
}
/* Label row that pairs "What did you do?" with the small "Clear" affordance
 * on the same baseline so the discard control sits where the eye already is
 * when starting a new draft, instead of floating down by Submit. */
.field-label-row {
  display: flex;
  width: 100%;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
}
.btn-clear-draft {
  background: transparent;
  border: 0;
  padding: 0;
  margin: 0 0 0 auto;
  font: inherit;
  font-size: 0.78rem;
  color: var(--muted);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
@media (hover: hover) and (pointer: fine) {
  .btn-clear-draft:hover { color: var(--danger); }
}
.btn-clear-draft:focus-visible {
  outline: none;
  color: var(--danger);
}
.chip.active {
  background: var(--accent-soft, rgba(195, 132, 90, 0.22));
  border-color: var(--accent-strong, #c3845a);
}

/* ---------- Notifications view ---------- */
.notif-card { display: flex; flex-direction: column; gap: 12px; }
#enable-push-row {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
  padding: 12px 14px;
  border: 1px dashed var(--border);
  border-radius: 12px;
  background: var(--surface-2);
}
.notif-enable-copy {
  margin: 0;
  font-size: 0.9rem;
  line-height: 1.4;
  color: var(--muted);
}
.notif-empty {
  color: var(--muted);
  font-size: 0.95rem;
  text-align: center;
  padding: 24px 8px;
  margin: 0;
}
/* Stack rows with their own gutter — the parent .card already pads the
 * outer edge, so we only need vertical spacing between siblings. */
#notif-list { display: flex; flex-direction: column; gap: 10px; }
.notif-row {
  position: relative;
  display: block;
  padding: 14px 16px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--surface-2);
  color: inherit;
  text-decoration: none;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
  transition: background 140ms ease, border-color 140ms ease,
              transform 80ms ease, box-shadow 140ms ease;
}
@media (hover: hover) and (pointer: fine) {
  .notif-row:hover {
    background: var(--hover-bg);
    border-color: var(--accent-strong);
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.10);
    text-decoration: none;
  }
}
.notif-row:active { transform: scale(0.99); }
/* Unread tag: a thicker, accent-coloured left edge. Padding compensates so
 * the body text doesn't shift between read / unread states. */
.notif-row.is-unread {
  border-left: 4px solid var(--accent-strong, #c3845a);
  padding-left: 13px;
}
.notif-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 10px;
  margin-bottom: 4px;
}
.notif-code { font-weight: 600; font-size: 0.98rem; }
.notif-snippet {
  font-size: 0.9rem;
  line-height: 1.4;
  opacity: 0.88;
  word-break: break-word;
  /* Clamp at two lines so long notes don't bloat the inbox. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Menu badge for unread count. */
.menu-item .menu-badge {
  display: inline-block;
  margin-left: 8px;
  min-width: 20px;
  padding: 0 6px;
  text-align: center;
  border-radius: 10px;
  background: var(--accent-strong, #c3845a);
  color: var(--on-accent, #1c1d1a);
  font-size: 0.75rem;
  line-height: 1.4;
}

/* ---------- install-to-home-screen card ---------- */
.install-card {
  position: fixed;
  left: 50%;
  bottom: 16px;
  transform: translateX(-50%);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 14px 16px;
  box-shadow: var(--shadow-lg);
  z-index: 200;
  max-width: 92vw;
  width: 380px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  font-size: 0.9rem;
}
.install-text { line-height: 1.4; }
.install-actions { display: flex; gap: 8px; justify-content: flex-end; }

/* ---------- photo upload widget (notes.js) ---------- */
/* Collapsible <details> styled to match `.setup-details` — same caret,
 * same muted summary text, but stretches across the obs form's full
 * width so the body can host the thumb row. */
.photo-details {
  margin: 8px 0 4px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
}
.photo-details > summary.photo-summary {
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  font-size: 0.92rem;
  color: var(--text);
}
.photo-details > summary.photo-summary::-webkit-details-marker { display: none; }
.photo-details .caret {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px; height: 16px;
  transition: transform 200ms ease;
  transform: rotate(-90deg);
  color: var(--muted);
}
.photo-details .caret svg { width: 14px; height: 14px; }
.photo-details[open] .caret { transform: rotate(0deg); }
.photo-summary-text { flex: 1; }
.photo-summary-count {
  font-size: 0.72rem;
  font-weight: 600;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--accent-strong);
  color: white;
}
.photo-body {
  padding: 0 10px 10px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 12px;
}
.btn-photo {
  background: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--border);
  padding: 7px 12px;
  border-radius: var(--radius-sm);
  font-size: 0.92rem;
}
.btn-photo:disabled { opacity: 0.55; cursor: not-allowed; }
.photo-original-row {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 0.92rem;
}
.photo-original-hint {
  flex-basis: 100%;
  margin: -4px 0 0;
}
.photo-thumbs {
  flex-basis: 100%;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 4px;
}
.photo-thumb {
  position: relative;
  width: 72px;
  height: 72px;
  border-radius: var(--radius-sm);
  overflow: hidden;
  border: 1px solid var(--border);
  background: var(--surface-2);
}
.photo-thumb img { width: 100%; height: 100%; object-fit: cover; }
.photo-thumb-remove {
  position: absolute;
  top: 2px;
  right: 2px;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  border: 0;
  background: rgba(0, 0, 0, 0.65);
  color: white;
  cursor: pointer;
  padding: 0;
  /* `display: grid; place-items: center` centres the SVG more reliably
   * than flex on iOS Safari, which gets the cross-axis off-by-a-pixel
   * for small absolutely-positioned circular buttons. */
  display: grid;
  place-items: center;
  line-height: 0;
}
.photo-thumb-remove svg { display: block; }
.photo-thumb-badge {
  position: absolute;
  bottom: 2px;
  left: 2px;
  font-size: 0.6rem;
  text-transform: uppercase;
  padding: 1px 5px;
  border-radius: 4px;
  background: var(--accent-strong);
  color: white;
  letter-spacing: 0.04em;
}

/* ---------- "has photos" inline mark in history + activity rows ---- */
/* A small camera glyph that prefixes the body text so the user can
 * spot photo-bearing rows without opening each one. The emoji glyph
 * itself does the visual work; the span just gives it consistent
 * letter-spacing and a screen-reader label. */
.history-photo-mark,
.activity-photo-mark {
  display: inline-block;
  margin-right: 2px;
  font-size: 0.95em;
  vertical-align: -1px;
}

/* ---------- Pictures(n) pill next to Q+ in the notes header --------- */
/* Inherits `.queen-pill` for shape + size so the two read as a pair. The
 * `.pictures-pill` variant replaces colour-coded queen states with a
 * neutral surface so it doesn't compete visually with Q+ / Q-. */
.pictures-pill {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  text-decoration: none;
  background: var(--surface-2);
  color: var(--text);
}
@media (hover: hover) and (pointer: fine) {
  .pictures-pill:hover { border-color: var(--accent-strong); }
}

/* ---------- gallery view ---------- */
/* Title sits on its own row; the filter stacks below it so the dropdown
 * panel has the full card width to land on without colliding with the
 * title. */
.gallery-title { margin: 0 0 8px; }
.gallery-filter {
  margin-bottom: 12px;
}

/* ---------- custom dropdown (shared/dropdown.js) ---------- */
.dd { position: relative; display: block; width: 100%; }
.dd-trigger {
  display: flex; align-items: center; justify-content: space-between;
  width: 100%;
  padding: 0.55rem 0.7rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
  font: inherit; font-size: 0.95rem;
  cursor: pointer;
  text-align: left;
  -webkit-tap-highlight-color: transparent;
  transition: border-color 120ms ease, box-shadow 120ms ease;
}
@media (hover: hover) and (pointer: fine) {
  .dd-trigger:hover { border-color: var(--accent-strong); }
}
.dd-trigger:focus { outline: none; border-color: var(--accent-strong); box-shadow: 0 0 0 3px var(--accent-glow); }
.dd-trigger-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dd-trigger-placeholder { color: var(--muted); }
.dd-trigger-icon {
  display: inline-flex; align-items: center;
  color: var(--muted);
  margin-left: 0.5rem;
  transition: transform 200ms ease;
}
.dd-trigger-icon svg { width: 16px; height: 16px; }
.dd.dd-open .dd-trigger-icon { color: var(--accent-strong); transform: rotate(180deg); }
.dd-panel {
  display: none;
  position: absolute; z-index: 60;
  top: calc(100% + 6px); left: 0; right: 0;
  padding: 6px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-lg);
  max-height: 280px;
  overflow-y: auto;
}
.dd.dd-open .dd-panel { display: block; }
.dd-group-label {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted);
  padding: 6px 8px 2px;
}
.dd-item {
  display: block;
  width: 100%;
  text-align: left;
  background: transparent;
  border: 0;
  padding: 7px 10px;
  border-radius: 6px;
  color: var(--text);
  font: inherit; font-size: 0.92rem;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
@media (hover: hover) and (pointer: fine) {
  .dd-item:hover { background: var(--hover-bg, var(--surface-2)); }
}
.dd-item.is-selected {
  background: var(--accent-glow);
  color: var(--accent-strong);
  font-weight: 600;
}
.gallery-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
}
@media (min-width: 720px) {
  .gallery-grid { grid-template-columns: repeat(5, 1fr); }
}
.gallery-tile {
  position: relative;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: var(--surface-2);
  cursor: pointer;
  aspect-ratio: 1 / 1;
  display: block;
}
.gallery-tile img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.gallery-tile-foot {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  padding: 3px 6px;
  background: linear-gradient(to top, rgba(0,0,0,0.55), rgba(0,0,0,0));
  color: white;
  font-size: 0.7rem;
  text-align: left;
  pointer-events: none;
}
.gallery-sentinel {
  padding: 24px 0;
  display: flex;
  justify-content: center;
  align-items: center;
}
/* Bottom-of-history loader for the colony notes view. Hidden once all
 * pages are in; visible while more can load so the IntersectionObserver
 * has something in layout to trip. */
.history-sentinel {
  padding: 14px 0;
  display: flex;
  justify-content: center;
  align-items: center;
}
.history-sentinel > .gallery-spinner { width: 24px; height: 24px; border-width: 2px; }
/* Earthy-moss spinner using the project's accent palette — a faint glow
 * ring with a strong arc that rotates. Same animation pattern as the
 * photo-modal-spin keyframes but coloured to fit the gallery card. */
.gallery-spinner {
  width: 36px;
  height: 36px;
  border: 3px solid var(--accent-glow);
  border-top-color: var(--accent-strong);
  border-radius: 50%;
  animation: gallery-spin 0.8s linear infinite;
}
@keyframes gallery-spin {
  to { transform: rotate(360deg); }
}
.gallery-end { padding: 12px 0 0; text-align: center; }

/* ---------- photo modal ---------- */
.photo-modal {
  width: min(96vw, 720px);
  max-width: 96vw;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0;
  background: var(--surface);
  color: var(--text);
}
.photo-modal::backdrop { background: rgba(0, 0, 0, 0.7); }
.photo-modal-close {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  border: 0;
  background: rgba(0, 0, 0, 0.55);
  color: white;
  cursor: pointer;
  z-index: 1;
  padding: 0;
  /* Same grid-centering as the photo-thumb-remove — reliable across
   * iOS Safari for tiny circular buttons. */
  display: grid;
  place-items: center;
  line-height: 0;
}
.photo-modal-close svg { display: block; }
.photo-modal-image-wrap {
  position: relative;
  background: #000;
  display: flex;
  justify-content: center;
  align-items: center;
  /* Reserve a chunk of vertical space so the modal opens at a stable
   * size even before the image finishes downloading — otherwise the
   * dialog would compress to the actions row's height and snap open
   * once the bytes land. */
  min-height: 50vh;
  max-height: 70vh;
}
.photo-modal-image-wrap img {
  max-width: 100%;
  max-height: 70vh;
  object-fit: contain;
  transition: opacity 200ms ease;
}
.photo-modal-image-wrap.is-loading img { opacity: 0; }
/* CSS-only spinner so we don't need to ship an extra asset. Sits dead
 * centre in the reserved space until the `is-loading` class is removed
 * by the image's `load` event handler. */
.photo-modal-image-wrap.is-loading::before {
  content: "";
  position: absolute;
  top: 50%; left: 50%;
  width: 36px; height: 36px;
  margin: -18px 0 0 -18px;
  border: 3px solid rgba(255, 255, 255, 0.18);
  border-top-color: rgba(255, 255, 255, 0.75);
  border-radius: 50%;
  animation: photo-modal-spin 0.8s linear infinite;
}
@keyframes photo-modal-spin {
  to { transform: rotate(360deg); }
}
.photo-modal-body { padding: 12px 14px 14px; }
.photo-modal-caption { margin-bottom: 4px; }
.photo-modal-caption.is-empty { font-style: italic; color: var(--text-muted); }
.photo-modal-meta { margin-bottom: 10px; }
.photo-modal-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: flex-end;
  align-items: center;
}

/* Post-detail modal — expanded view of a single sticky note. Same dim
 * backdrop + close-X as photo-modal so the two read as a family. */
.post-detail-dialog {
  width: min(96vw, 560px);
  max-width: 96vw;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0;
  background: var(--surface);
  color: var(--text);
  max-height: calc(100vh - 48px);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
}
.post-detail-dialog::backdrop { background: rgba(0, 0, 0, 0.7); }
.post-detail-close {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  border: 0;
  background: rgba(0, 0, 0, 0.55);
  color: white;
  cursor: pointer;
  z-index: 2;
  padding: 0;
  display: grid;
  place-items: center;
  line-height: 0;
}
.post-detail-close svg { display: block; }
.post-detail-head {
  display: flex; align-items: center; gap: 10px;
  padding: 18px 50px 12px 18px;  /* right padding clears the close-X */
}
.post-detail-avatar {
  flex: 0 0 36px; height: 36px; width: 36px;
  border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 0.85rem;
  color: #1f2620;
}
.post-detail-author { font-weight: 600; }
.post-detail-when { margin-top: 2px; }
.post-detail-body {
  padding: 6px 18px 18px;
  font-size: 0.98rem;
  line-height: 1.5;
  white-space: pre-wrap;
  word-break: break-word;
  max-height: 50vh;
  overflow-y: auto;
}
.post-detail-foot {
  display: flex; align-items: center;
  padding: 12px 18px 18px;
  border-top: 1px solid var(--border);
}
.post-detail-seen {
  flex: 1 1 auto; min-width: 0;
  font-size: 0.82rem;
  color: var(--muted);
  word-break: break-word;
}
@media (max-width: 599px) {
  .post-detail-head { padding: 16px 44px 10px 14px; }
  .post-detail-body { padding: 4px 14px 14px; font-size: 0.95rem; }
  .post-detail-foot { padding: 10px 14px 14px; }
}

/* Always-red Delete button — same gradient + border as the confirm-
 * dialog's danger-confirm rule (which is scoped to `<dialog> menu
 * button[value="save"]` and so doesn't match outside the dialog
 * action area). Reuses `.btn` for shape + sizing. */
.btn-danger-strong {
  background: linear-gradient(180deg, #c1543f 0%, #a8412e 100%);
  color: #fff;
  border-color: #872d1e;
  font-weight: 600;
}
@media (hover: hover) and (pointer: fine) {
  .btn-danger-strong:hover {
    background: linear-gradient(180deg, #c1543f 0%, #a8412e 100%);
    border-color: #872d1e;
    color: #fff;
    filter: brightness(1.07);
  }
}
.btn-danger-strong:focus-visible {
  outline: 2px solid #872d1e;
  outline-offset: 2px;
}

/* ===================== Schedule ===================== */
.sched-monthnav {
  display: flex; justify-content: space-between; align-items: center;
  margin: 10px 0 6px; gap: 8px;
}
.sched-month-title { font-weight: 600; color: var(--accent-strong); }
.sched-nav { padding: 2px 14px; font-size: 1.05rem; line-height: 1.4; }
.sched-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 3px; }
.sched-dow { text-align: center; font-size: 0.65rem; color: var(--muted); padding: 2px 0; }
.sched-blank { min-height: 38px; }
.sched-day {
  text-align: center; padding: 5px 0 4px; border-radius: var(--radius-sm);
  min-height: 38px; font-size: 0.85rem; color: var(--muted);
  box-sizing: border-box;
}
.sched-off { opacity: 0.45; }
.sched-shift {
  background: var(--surface-2); border: 1px solid var(--border);
  color: var(--fg); cursor: pointer;
}
.sched-ini { display: block; font-weight: 700; font-size: 0.78rem; color: var(--accent-strong); }
.sched-blocked { background: var(--warm-soft); border-color: var(--warm); color: var(--warm); }
.sched-gap { background: var(--warm-soft); border-color: var(--warm); }
.sched-gap .sched-ini { color: var(--warm); }
.sched-mine { outline: 2px solid var(--accent); outline-offset: -2px; }
.sched-today { box-shadow: inset 0 0 0 2px var(--accent-2); }
.sched-target { outline: 2px dashed var(--warm); outline-offset: -2px; }
.sched-foot { display: flex; justify-content: space-between; align-items: center; margin-top: 10px; gap: 10px; }
.sched-pills { display: flex; flex-wrap: wrap; gap: 6px; margin: 8px 0; }
.sched-pill {
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: 999px; padding: 3px 10px; font-size: 0.8rem; color: var(--fg-soft);
}
.sched-pill.ok { border-color: var(--accent); }
/* Shift-count row under the current-schedule calendar — ruled off from
 * the grid above so the tally reads as a summary, not more calendar. */
.sched-counts {
  border-top: 1px solid var(--border);
  margin-top: 12px;
  padding-top: 12px;
}
.sched-pill.wait { border-color: var(--warm); color: var(--warm); }
.sched-sub { font-size: 0.95rem; margin: 14px 0 4px; }
.sched-sheet {
  margin-top: 10px; background: var(--surface-2);
  border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 10px;
}
.sched-sheet h4 { margin: 0 0 8px; font-size: 0.9rem; color: var(--fg-soft); }
.sched-sheet-row { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 8px; }
.sched-request {
  border: 1px solid var(--accent); border-radius: var(--radius-sm);
  padding: 10px 12px; margin-bottom: 8px; background: var(--accent-glow);
}
.sched-request p { margin: 0 0 8px; }
.sched-request-actions { display: flex; gap: 8px; }
.sched-outgoing {
  display: flex; justify-content: space-between; align-items: center; gap: 8px;
  padding: 6px 0; border-bottom: 1px solid var(--border);
  font-size: 0.9rem; color: var(--fg-soft);
}
.sched-outgoing:last-child { border-bottom: none; }
/* Sits beside the initials chip — same height as its diameter at each
   breakpoint (40px desktop, 34px on small screens), normal button corners. */
.checkin-btn {
  margin-right: 8px;
  height: 40px;
  padding: 0 14px;
  display: inline-flex; align-items: center;
}
@media (max-width: 480px) {
  .checkin-btn { height: 34px; padding: 0 10px; font-size: 0.82rem; }
}
.checkin-pills { display: flex; flex-wrap: wrap; gap: 6px; }
.checkin-pill {
  background: var(--surface-2); border: 1px solid var(--accent);
  border-radius: 999px; padding: 4px 12px; font-weight: 600; color: var(--fg);
}
.checkin-pill small { color: var(--muted); font-weight: 400; }
