/* Sheriff design system -- "shire ledger": a warm household almanac.
   No framework; CSS variables mirror templates/core/home.html's naming
   style (--bg/--fg/--accent/--muted/--card-bg/--border) so the two
   stylesheets read as one family. See docs/plans/2026-07-28_m3_pwa_ui.md
   Stage 1 for the design brief this file implements. */

/* ---------------------------------------------------------------------
   Fonts -- self-hosted, no external CDN at runtime.
   Fraunces (variable, wght 100-900) for display/headers.
   Alegreya Sans (400/700 statics) for body/UI.
   --------------------------------------------------------------------- */
@font-face {
  font-family: "Fraunces";
  src: url("../fonts/Fraunces-Variable.eb2486760f75.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Fraunces";
  src: url("../fonts/Fraunces-Italic-Variable.701ae03b5183.woff2") format("woff2");
  font-weight: 100 900;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "Alegreya Sans";
  src: url("../fonts/AlegreyaSans-Regular.dec96422d9be.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Alegreya Sans";
  src: url("../fonts/AlegreyaSans-Bold.c198fa600447.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

/* ---------------------------------------------------------------------
   Palette -- light "parchment" default, dark "candlelit" via
   prefers-color-scheme. Brass stays constant across both themes.
   --------------------------------------------------------------------- */
:root {
  color-scheme: light dark;

  --bg: #f6f1e5; /* parchment */
  --fg: #2a2620; /* ink */
  --accent: #8f3b2c; /* sheriff crimson */
  --accent-ink: #ffffff;
  --brass: #b08b4f; /* secondary accent */
  --muted: #746b5a;
  --card-bg: #fffdf6;
  --border: #ded2b8;
  --hairline: rgba(42, 38, 32, 0.16);
  --shadow: rgba(42, 38, 32, 0.12);

  --urgency-low: var(--brass);
  --urgency-high: #c9603f; /* ember, used for the hot end of the meter in both themes */

  --font-display: "Fraunces", Georgia, "Times New Roman", serif;
  --font-body: "Alegreya Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;

  --radius: 10px;
  --radius-sm: 6px;
  --touch-min: 44px;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #171512; /* candlelit */
    --fg: #e8e2d4; /* warm parchment-ink */
    --accent: #c9603f; /* ember */
    --accent-ink: #171512;
    --brass: #b08b4f; /* unchanged */
    --muted: #a89a80;
    --card-bg: #201d18;
    --border: #3a342a;
    --hairline: rgba(232, 226, 212, 0.14);
    --shadow: rgba(0, 0, 0, 0.4);

    --urgency-low: var(--brass);
    --urgency-high: #e07a52;
  }
}

/* ---------------------------------------------------------------------
   Base
   --------------------------------------------------------------------- */
* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font-body);
  -webkit-font-smoothing: antialiased;
}

body {
  position: relative;
  min-height: 100vh;
}

/* Very subtle paper-grain texture (opacity <= 0.04), tiled. Purely
   decorative; sits behind content and never intercepts input. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: 0.04;
  background-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='180'%20height='180'%3E%3Cfilter%20id='n'%3E%3CfeTurbulence%20type='fractalNoise'%20baseFrequency='0.85'%20numOctaves='2'%20stitchTiles='stitch'/%3E%3C/filter%3E%3Crect%20width='100%25'%20height='100%25'%20filter='url(%23n)'/%3E%3C/svg%3E");
  background-repeat: repeat;
}

#page-root {
  position: relative;
  z-index: 1;
}

h1,
h2,
h3,
h4 {
  font-family: var(--font-display);
  font-weight: 600;
  color: var(--fg);
  margin: 0 0 0.4em 0;
}

a {
  color: var(--accent);
}

p {
  line-height: 1.5;
}

.small-caps {
  font-variant: small-caps;
  letter-spacing: 0.04em;
  font-size: 0.78rem;
  color: var(--muted);
  font-weight: 700;
}

/* ---------------------------------------------------------------------
   Buttons
   --------------------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5em;
  min-height: var(--touch-min);
  padding: 0.6em 1.1em;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--card-bg);
  color: var(--fg);
  font-family: var(--font-body);
  font-size: 1rem;
  font-weight: 700;
  text-decoration: none;
  cursor: pointer;
  transition: transform 0.08s ease, box-shadow 0.15s ease;
}

.btn:active {
  transform: translateY(1px) scale(0.98);
}

.btn-primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
  border-radius: 4px; /* "slightly squared" per brief */
}

.btn-primary:hover {
  filter: brightness(1.05);
}

.btn-block {
  display: flex;
  width: 100%;
}

/* ---------------------------------------------------------------------
   Ledger list / rows -- the primary list component for later stages.
   --------------------------------------------------------------------- */
.ledger-list {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--hairline);
}

.ledger-row {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 56px;
  padding: 10px 4px;
  border-bottom: 1px solid var(--hairline);
  text-decoration: none;
  color: inherit;
  opacity: 0;
  animation: ledger-fade-up 0.4s ease-out forwards;
}

/* Staggered fade-up on page load, capped at 8 rows. */
.ledger-row:nth-child(1) { animation-delay: 0.02s; }
.ledger-row:nth-child(2) { animation-delay: 0.06s; }
.ledger-row:nth-child(3) { animation-delay: 0.1s; }
.ledger-row:nth-child(4) { animation-delay: 0.14s; }
.ledger-row:nth-child(5) { animation-delay: 0.18s; }
.ledger-row:nth-child(6) { animation-delay: 0.22s; }
.ledger-row:nth-child(7) { animation-delay: 0.26s; }
.ledger-row:nth-child(8) { animation-delay: 0.3s; }
.ledger-row:nth-child(n + 9) { animation-delay: 0.3s; }

@keyframes ledger-fade-up {
  from {
    opacity: 0;
    transform: translateY(6px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.ledger-row .title {
  flex: 1 1 auto;
  min-width: 0;
}

.ledger-row .title strong {
  display: block;
  font-family: var(--font-body);
  font-weight: 700;
}

.ledger-row .subtitle {
  color: var(--muted);
  font-size: 0.85rem;
}

/* 0.7.1 plan item 3: overdue subtitle text reuses the urgency meter's hot
   end instead of the default muted color, on Today (Schedule/wall never
   produce an overdue row through this same partial -- see
   chores/_occurrence_row.html). */
.subtitle-overdue {
  color: var(--urgency-high);
  font-weight: 700;
}

/* 0.7.1 plan item 1: the shared "Last done ..." line, one muted row of
   text under the due-date subtitle. */
.last-done-line {
  display: block;
}

/* A ledger-row can also be a <form> (e.g. logout, which Django requires as
   POST); this makes the submit button inside it look like plain row text. */
.ledger-btn {
  all: unset;
  display: flex;
  align-items: center;
  width: 100%;
  min-height: 44px;
  cursor: pointer;
  font-family: inherit;
  color: inherit;
}

/* Notifications card (M4 stage B, More page) -- sits below the ledger-list,
   same card surface as .login-card/other rows rather than a new component. */
.notify-card {
  margin-top: 24px;
  padding: 16px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--card-bg);
}

.notify-card .subtitle {
  color: var(--muted);
  font-size: 0.85rem;
  margin: 4px 0 12px 0;
}

.notify-note {
  margin-top: 12px;
  color: var(--muted);
  font-size: 0.85rem;
}

/* ---------------------------------------------------------------------
   Chips -- category / status pills, muted natural hues.
   --------------------------------------------------------------------- */
.chip {
  display: inline-flex;
  align-items: center;
  padding: 0.15em 0.7em;
  border-radius: 999px;
  font-size: 0.78rem;
  font-weight: 700;
  line-height: 1.6;
  background: var(--border);
  color: var(--fg);
  white-space: nowrap;
}

.chip-brass {
  background: color-mix(in srgb, var(--brass) 25%, var(--card-bg));
  color: var(--fg);
}

.chip-crimson {
  background: color-mix(in srgb, var(--accent) 20%, var(--card-bg));
  color: var(--fg);
}

.chip-muted {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--muted);
}

/* Batch A item 6 (inbox #14): unassigned occurrences render a quiet
   "any" owner chip -- italic to read as a word, not someone's initials. */
.chip-any {
  font-style: italic;
}

/* 0.7.1 plan item 6: inbox items still awaiting a decision after 7+ days
   -- a gentle parchment-yellowing nudge to revisit, not a warning (brass,
   never crimson/urgency-high; this is about the item, never a person). */
.chip-aging {
  background: color-mix(in srgb, var(--brass) 22%, var(--card-bg));
  color: var(--fg);
  border: 1px solid var(--brass);
}

.ledger-row-aging {
  background: color-mix(in srgb, var(--brass) 6%, transparent);
}

/* ---------------------------------------------------------------------
   Urgency meter -- thin bar, brass -> ember gradient fill proportional
   to --urgency (0-100+ %). Pulses gently at >=100%.
   --------------------------------------------------------------------- */
.urgency {
  --urgency: 0;
  position: relative;
  width: 100%;
  height: 5px;
  border-radius: 999px;
  background: var(--hairline);
  overflow: hidden;
}

.urgency > .urgency-fill {
  display: block;
  height: 100%;
  width: clamp(0%, var(--urgency), 100%);
  border-radius: 999px;
  background: linear-gradient(90deg, var(--urgency-low), var(--urgency-high));
}

.urgency.is-due > .urgency-fill {
  animation: urgency-pulse 2s ease-in-out infinite;
}

@keyframes urgency-pulse {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.55;
  }
}

/* ---------------------------------------------------------------------
   Wax check -- the check-off button. On completion (htmx swap), plays a
   "wax seal" stamp-in: scale + rotate overshoot + fade.
   --------------------------------------------------------------------- */
.wax-check {
  flex: 0 0 auto;
  width: var(--touch-min);
  height: var(--touch-min);
  border-radius: 50%;
  border: 2px solid var(--accent);
  background: var(--card-bg);
  color: var(--accent);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  padding: 0;
}

.wax-check.is-done {
  background: var(--accent);
  color: var(--accent-ink);
  border-color: var(--accent);
  animation: wax-stamp 350ms cubic-bezier(0.34, 1.56, 0.64, 1) both;
}

@keyframes wax-stamp {
  0% {
    opacity: 0;
    transform: scale(1.4) rotate(6deg);
  }
  100% {
    opacity: 1;
    transform: scale(1) rotate(0deg);
  }
}

/* ---------------------------------------------------------------------
   Banners / empty states
   --------------------------------------------------------------------- */
.banner-stale {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 14px;
  border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--brass) 18%, var(--card-bg));
  border: 1px solid var(--border);
  color: var(--fg);
  font-size: 0.9rem;
}

/* Refresh pill -- static/js/freshness.js (0.5.1 plan item 2): the
   non-destructive "tap to refresh" affordance shown either when stale
   content couldn't auto-reload because a form is dirty/focused, or when
   a new service worker is waiting to take over. Fixed near the top of
   the viewport (the bottom is already owned by .bottom-nav), a floating
   pill rather than a banner so it never shifts page layout underneath a
   mid-edit form. */
.refresh-pill {
  position: fixed;
  top: calc(env(safe-area-inset-top, 0px) + 10px);
  left: 50%;
  transform: translateX(-50%);
  z-index: 5;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: var(--touch-min);
  padding: 8px 18px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: color-mix(in srgb, var(--brass) 30%, var(--card-bg));
  color: var(--fg);
  font-family: var(--font-body);
  font-size: 0.85rem;
  font-weight: 700;
  box-shadow: 0 2px 10px var(--shadow);
  cursor: pointer;
}

.refresh-pill[hidden] {
  display: none;
}

.empty-state {
  text-align: center;
  padding: 48px 20px;
  color: var(--muted);
  font-family: var(--font-display);
  font-style: italic;
  font-size: 1.15rem;
}

/* ---------------------------------------------------------------------
   Authenticated app shell -- base_app.html
   --------------------------------------------------------------------- */
.app-shell {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

.app-header {
  padding: 18px 16px 10px 16px;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
}

.header-refresh {
  background: none;
  border: none;
  padding: 6px;
  margin: 2px 0 0 8px;
  color: var(--muted);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.header-refresh svg {
  width: 24px;
  height: 24px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.header-refresh:active {
  color: var(--fg);
}

.header-actions {
  display: flex;
  align-items: flex-start;
}

/* ---------------------------------------------------------------------
   Search (0.7.3) -- header toggle expands this bar; static/js/search.js
   filters the page's .ledger-row set client-side.
   --------------------------------------------------------------------- */
.search-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 16px 10px 16px;
  max-width: 640px; /* track .app-content's centered column */
  width: 100%;
  margin: 0 auto;
}

.search-bar[hidden] {
  display: none;
}

.search-bar input[type="search"] {
  flex: 1 1 auto;
  min-width: 0;
  min-height: var(--touch-min);
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font-body);
  font-size: 1rem;
}

.search-count {
  color: var(--muted);
  font-size: 0.85rem;
  white-space: nowrap;
}

mark.search-mark {
  background: rgba(176, 139, 79, 0.35); /* --brass at 35% for pre-color-mix engines */
  background: color-mix(in srgb, var(--brass) 35%, transparent);
  color: inherit;
  border-radius: 2px;
}

/* Filtered-out rows/groups. Explicit rules because .ledger-row and
   .search-bar are display:flex, which beats the UA's [hidden] rule. */
.ledger-row[hidden],
.ledger-list[hidden],
.app-content section[hidden],
.app-content h3[hidden] {
  display: none;
}

/* While a search is live, rows re-show as the query changes; the
   staggered load-in animation must not replay on every keystroke
   (it leaves rows at opacity 0 until it runs). */
body.search-active .ledger-row {
  animation: none;
  opacity: 1;
}

.app-header h1 {
  font-size: 1.6rem;
  margin: 0;
}

.app-header .app-date {
  margin: 2px 0 0 0;
  color: var(--muted);
  font-size: 0.9rem;
}

.app-content {
  flex: 1 1 auto;
  padding: 4px 16px 24px 16px;
  max-width: 640px;
  width: 100%;
  margin: 0 auto;
}

.app-footer {
  text-align: center;
  padding: 10px 16px 14px 16px;
  font-size: 0.72rem;
  color: var(--muted);
}

/* Bottom nav -- 4 items, inline-SVG icons, fixed to the viewport bottom. */
.bottom-nav {
  position: sticky;
  bottom: 0;
  z-index: 2;
  display: flex;
  background: var(--card-bg);
  border-top: 1px solid var(--border);
  box-shadow: 0 -2px 8px var(--shadow);
  padding-bottom: env(safe-area-inset-bottom, 0);
}

.bottom-nav a {
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  min-height: 56px;
  padding: 6px 4px;
  color: var(--muted);
  text-decoration: none;
  font-size: 0.7rem;
  font-weight: 700;
}

.bottom-nav a svg {
  width: 24px;
  height: 24px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.bottom-nav a.is-active {
  color: var(--accent);
}

/* ---------------------------------------------------------------------
   Login page -- centered card on parchment, public, kept quiet.
   --------------------------------------------------------------------- */
.login-page {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px 16px;
}

.login-card {
  width: 100%;
  max-width: 360px;
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 32px 28px;
  box-shadow: 0 6px 24px var(--shadow);
  text-align: center;
}

.login-card h1 {
  font-size: 1.5rem;
  margin-bottom: 4px;
}

.login-card .tagline {
  color: var(--muted);
  font-size: 0.9rem;
  margin: 0 0 24px 0;
}

.login-card .errorlist {
  list-style: none;
  margin: 0 0 4px 0;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--accent) 12%, var(--card-bg));
  color: var(--accent);
  font-size: 0.85rem;
}

.login-footer {
  margin-top: 20px;
  font-size: 0.7rem;
  color: var(--muted);
}

/* Google sign-in (M3 auth section) -- the only sign-in method since
   password login was retired 2026-08-02. Reuses .btn/.btn-block. */
.btn-google {
  margin-top: 8px;
  background: var(--card-bg);
}

/* Shown instead of the Google button when GOOGLE_LOGIN_ENABLED is False
   (no OAuth env vars, e.g. a fresh dev clone) -- same quiet treatment as
   .errorlist without implying anything went wrong. */
.login-not-configured {
  margin: 8px 0 0 0;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--muted) 12%, var(--card-bg));
  color: var(--muted);
  font-size: 0.85rem;
}

/* ---------------------------------------------------------------------
   Stage 2 -- Today/Schedule ledger rows that mix a wax-check button with
   a tappable link (row-link/row-top), section spacing, form fields for
   the occurrence-detail action row, inbox capture, and the markdown/
   chore-facts read views. Reuses the same tokens as everything above.
   --------------------------------------------------------------------- */
.app-content section {
  margin-top: 22px;
}

.app-content section:first-child {
  margin-top: 4px;
}

.app-content h3 {
  margin-top: 20px;
  font-size: 1.05rem;
}

.wax-check-form {
  flex: 0 0 auto;
  display: flex;
}

.wax-check svg {
  width: 20px;
  height: 20px;
}

.row-link {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
  text-decoration: none;
  color: inherit;
}

.row-top {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.ack-form,
.drop-form {
  flex: 0 0 auto;
}

/* ---------------------------------------------------------------------
   Occurrence detail / chore detail read views
   --------------------------------------------------------------------- */
.occ-detail-head {
  display: flex;
  gap: 8px;
  margin-bottom: 6px;
}

.markdown-body {
  font-size: 0.95rem;
  line-height: 1.55;
}

.markdown-body :first-child {
  margin-top: 0;
}

.markdown-body pre {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 10px 12px;
  overflow-x: auto;
}

.markdown-body code {
  background: var(--card-bg);
  border-radius: 4px;
  padding: 0.1em 0.35em;
}

.chore-facts {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 6px 14px;
  margin: 0;
}

.chore-facts dt {
  color: var(--muted);
  font-weight: 700;
  font-size: 0.85rem;
}

.chore-facts dd {
  margin: 0;
}

/* ---------------------------------------------------------------------
   Occurrence-detail actions row + inbox capture -- shared field styling.
   --------------------------------------------------------------------- */
.occ-actions {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.occ-action-form {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  padding: 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--card-bg);
}

.occ-action-form > .btn,
.occ-action-form > .wax-check {
  flex: 0 0 auto;
}

.occ-action-label {
  font-weight: 700;
}

.occ-action-form details {
  flex: 1 1 100%;
  font-size: 0.85rem;
}

.occ-action-form details label {
  display: block;
  margin-top: 8px;
  font-size: 0.8rem;
  color: var(--muted);
  font-weight: 700;
}

.occ-action-form label.small-caps {
  flex: 0 0 auto;
}

.occ-action-form input[type="text"],
.occ-action-form input[type="date"],
.occ-action-form input[type="time"],
.occ-action-form input[type="number"],
.occ-action-form input[type="file"],
.occ-action-form select,
.occ-action-form textarea,
.capture-form input[type="file"],
.capture-form textarea {
  min-height: var(--touch-min);
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font-body);
  font-size: 1rem;
  width: 100%;
}

.occ-action-form textarea,
.capture-form textarea {
  min-height: 44px;
  resize: vertical;
}

.capture-form {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 18px;
}

/* Batch B #16: capture-photo thumbnail on inbox rows. Lives inside the
   row's .title span (never a new column -- the fixed 92px .deputy-cell
   layout is untouched); chip-ish framing, tap-through to the full image. */
.inbox-photo-link {
  display: inline-block;
  margin-top: 4px;
  line-height: 0;
}

.inbox-photo-thumb {
  max-height: 44px;
  max-width: 88px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  display: inline-block;
}

/* ---------------------------------------------------------------------
   0.7.0 stage B -- type-kicker badges (D7): small-caps label above the
   h2 on both detail pages, visually distinct per page so "Chore vs
   Occurrence" is unmistakable at a glance (Michael's complaint that the
   two pages looked like twins).
   --------------------------------------------------------------------- */
.type-kicker {
  display: inline-block;
  font-variant: small-caps;
  letter-spacing: 0.08em;
  font-size: 0.72rem;
  font-weight: 700;
  padding: 3px 10px;
  border-radius: 999px;
  margin: 0 0 8px 0;
}

.type-kicker-chore {
  background: color-mix(in srgb, var(--brass) 30%, var(--card-bg));
  color: var(--fg);
}

.type-kicker-occurrence {
  background: color-mix(in srgb, var(--accent) 22%, var(--card-bg));
  color: var(--accent);
}

.next-up {
  font-weight: 700;
}

.next-up a {
  text-decoration: none;
}

.schedule-provenance {
  margin-top: -8px;
}

/* ---------------------------------------------------------------------
   Tag chips (D5) -- the chip row sits OUTSIDE any wrapping row-link/
   occ-detail-head anchor so a real clickable <a> chip never nests
   inside another <a> (invalid HTML, unreliable tap targets).
   --------------------------------------------------------------------- */
.chip-link {
  text-decoration: none;
  cursor: pointer;
}

.chip-link:hover,
.chip-link:focus-visible {
  filter: brightness(1.08);
  text-decoration: underline;
}

.row-tags {
  flex: 0 0 auto;
  display: flex;
  flex-wrap: wrap;
  align-content: center;
  justify-content: flex-end;
  gap: 6px;
  max-width: 45%;
}

/* ---------------------------------------------------------------------
   Claim panel (D3) -- inline reveal (native <details>, never
   window.confirm/alert) for the Take-over/Join choice when the
   occurrence is already assigned to the other household member.
   --------------------------------------------------------------------- */
.claim-panel {
  margin: 10px 0 4px 0;
}

.claim-summary {
  list-style: none;
  cursor: pointer;
}

.claim-summary::-webkit-details-marker {
  display: none;
}

.claim-choices {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 10px;
  padding: 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--card-bg);
}

.claim-form {
  display: flex;
}

.claim-form .btn {
  width: 100%;
}

.claim-cancel {
  align-self: flex-start;
}

.claim-error {
  margin-top: 8px;
  color: var(--accent);
  font-size: 0.85rem;
  font-weight: 700;
}

.claim-error[hidden] {
  display: none;
}

.handoff-blocked-note {
  padding: 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

/* ---------------------------------------------------------------------
   Chore edit form (D6) -- vertical label-above-field layout, distinct
   from .occ-action-form's compact inline rows above (those are for
   short single-purpose action rows; this is a full multi-field form).
   --------------------------------------------------------------------- */
.edit-form {
  display: flex;
  flex-direction: column;
  gap: 16px;
  margin-top: 12px;
}

.edit-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.edit-field label {
  font-weight: 700;
  font-size: 0.85rem;
  color: var(--muted);
}

.edit-field input[type="text"],
.edit-field input[type="number"],
.edit-field select,
.edit-field textarea {
  min-height: var(--touch-min);
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font-body);
  font-size: 1rem;
  width: 100%;
}

.edit-field textarea {
  min-height: 80px;
  resize: vertical;
}

.new-tag-field {
  margin-top: 4px;
}

/* New-chore page: one per-schedule-type field group (chore_new.html).
   Server renders every group visible; the page's inline script hides
   all but the selected type's group (progressive enhancement). */
.schedule-type-fields {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.schedule-type-fields[hidden] {
  display: none;
}

.form-help {
  font-size: 0.85rem;
  color: var(--muted);
}

.chip-toggle-list {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.chip-toggle {
  display: inline-flex;
  cursor: pointer;
}

.chip-toggle input {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.chip-toggle .chip {
  border: 1px solid var(--border);
  background: var(--card-bg);
}

.chip-toggle input:checked + .chip {
  background: color-mix(in srgb, var(--accent) 22%, var(--card-bg));
  border-color: var(--accent);
  color: var(--fg);
}

.chip-toggle input:focus-visible + .chip {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.checkbox-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.checkbox-row {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 400;
  color: var(--fg);
}

.propagate-row {
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--brass) 18%, var(--card-bg));
}

.propagate-row[hidden] {
  display: none;
}

.errorlist {
  list-style: none;
  margin: 0 0 12px 0;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--accent) 12%, var(--card-bg));
  color: var(--accent);
  font-size: 0.85rem;
}

/* ---------------------------------------------------------------------
   Motion restraint: everything above is off under reduced motion.
   --------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .ledger-row {
    animation: none !important;
    opacity: 1 !important;
    transform: none !important;
  }
  .urgency.is-due > .urgency-fill {
    animation: none !important;
  }
  .wax-check.is-done {
    animation: none !important;
  }
  * {
    scroll-behavior: auto !important;
  }
}

/* ---------------------------------------------------------------------
   /wall kiosk (M3 stage 3) -- always dark via html.wall-dark (see
   templates/wall.html), independent of the device's own light/dark
   setting: html.wall-dark has higher specificity than the
   prefers-color-scheme media query above, so it wins regardless. Sized
   for a Tab A9+ 1920x1200 landscape panel at arm's length -- large type,
   a 75px tap target, burn-in-safe slow drift + idle dim.
   --------------------------------------------------------------------- */
html.wall-dark {
  color-scheme: dark;
  --bg: #171512;
  --fg: #e8e2d4;
  --accent: #c9603f;
  --accent-ink: #171512;
  --brass: #b08b4f;
  --muted: #a89a80;
  --card-bg: #201d18;
  --border: #3a342a;
  --hairline: rgba(232, 226, 212, 0.14);
  --shadow: rgba(0, 0, 0, 0.4);
  --urgency-low: var(--brass);
  --urgency-high: #e07a52;
}

.wall-shell {
  min-height: 100vh;
  padding: 28px 40px;
  transition: transform 6s linear, filter 1.2s ease;
}

/* Burn-in mitigation: a few px of slow position drift, alternated each
   time the row list refreshes (poll or check-off -- see templates/wall.html
   JS). The Tab A9+ is LCD (low burn-in risk) but this is free insurance
   and matches the design brief. */
.wall-shell.wall-drift-a {
  transform: translate(0, 0);
}

.wall-shell.wall-drift-b {
  transform: translate(8px, -6px);
}

body.wall-dimmed .wall-shell {
  filter: brightness(0.6);
}

.wall-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-bottom: 24px;
}

.wall-date {
  font-family: var(--font-display);
  font-size: 2.6rem;
  margin: 0;
}

.wall-clock {
  font-family: var(--font-body);
  font-size: 1.6rem;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.wall-banner-stale {
  margin-bottom: 20px;
  font-size: 1.1rem;
  padding: 16px 20px;
}

/* M6 stage C: compact weather strip -- today hi/lo, precip if any, active
   NWS alert badges, and the dead-man stale banner (people/views.py's
   _wall_weather_context / wx.services.staleness). Deliberately its own
   block, not #wall-banner-slot -- that div is JS-managed (wall.html's
   htmx:afterSwap handler does bannerSlot.innerHTML = "") and would wipe
   this out on every row refresh. */
.wall-weather {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 14px;
  margin-bottom: 20px;
  font-family: var(--font-body);
  font-size: 1.1rem;
  color: var(--muted);
}

.wall-weather-hilo {
  font-family: var(--font-display);
  font-size: 1.5rem;
  color: var(--fg);
  font-variant-numeric: tabular-nums;
}

.wall-weather-precip {
  color: var(--muted);
}

.wall-alert-badge {
  display: inline-flex;
  align-items: center;
  padding: 0.2em 0.9em;
  border-radius: 999px;
  font-weight: 700;
  font-size: 0.95rem;
  background: #6b0f0f;
  color: #f7ece4;
}

.wall-weather-stale {
  color: var(--brass);
  font-weight: 700;
}

.wall-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.wall-row {
  display: flex;
  align-items: center;
  gap: 24px;
  min-height: 96px;
  padding: 14px 8px;
  border-bottom: 1px solid var(--hairline);
}

.wall-row-main {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.wall-chore-name {
  font-family: var(--font-display);
  font-size: 2.5rem;
  font-weight: 600;
  line-height: 1.1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.wall-owner-chip {
  align-self: flex-start;
  font-size: 1.1rem;
  padding: 0.2em 0.9em;
}

/* 0.7.1 plan item 1: same shared "Last done ..." line as the phone rows,
   sized for the kiosk's much larger type scale. */
.wall-last-done {
  display: block;
  font-size: 1.1rem;
  color: var(--muted);
}

.wall-urgency {
  height: 10px;
  max-width: 480px;
}

.wall-check-form {
  flex: 0 0 auto;
}

.wall-check.wax-check {
  width: 75px;
  height: 75px;
  border-width: 3px;
}

.wall-check svg {
  width: 36px;
  height: 36px;
}

.wall-overflow {
  text-align: center;
  color: var(--muted);
  font-family: var(--font-display);
  font-style: italic;
  font-size: 1.3rem;
  padding: 12px;
}

.wall-empty {
  padding: 25vh 20px;
  font-size: 2rem;
}

@media (prefers-reduced-motion: reduce) {
  .wall-shell {
    transition: none !important;
  }
}

/* ---------------------------------------------------------------------
   0.7.1 plan item 2 -- detail-page back/parent link. Sits above the
   type-kicker so it reads as "how I got here" before "what this is".
   --------------------------------------------------------------------- */
.back-link {
  margin: 0 0 8px 0;
  font-size: 0.85rem;
}

.back-link a {
  color: var(--muted);
  text-decoration: none;
}

.back-link a:hover,
.back-link a:focus-visible {
  color: var(--fg);
  text-decoration: underline;
}

/* ---------------------------------------------------------------------
   0.7.1 plan items 12/13 -- Schedule cadence chips + Schedule/Today
   assignee focus filter. Plain toggle-link chips (not the chip-toggle
   checkbox pattern used in the chore-edit form -- these navigate via a
   plain href, so state lives in the URL and stays bookmarkable).
   --------------------------------------------------------------------- */
.filter-chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 14px;
}

.filter-chip {
  display: inline-flex;
  align-items: center;
  padding: 0.3em 0.85em;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--card-bg);
  color: var(--fg);
  font-size: 0.82rem;
  font-weight: 700;
  text-decoration: none;
  white-space: nowrap;
}

.filter-chip.is-active {
  background: color-mix(in srgb, var(--accent) 22%, var(--card-bg));
  border-color: var(--accent);
  color: var(--fg);
}

.filter-chip:hover,
.filter-chip:focus-visible {
  filter: brightness(1.06);
}

/* ---------------------------------------------------------------------
   0.7.1 plan item 16 -- shared "Processing..." button state (static/js/
   processing.js) + the shared dismissible error banner every
   hx-processing-form's failure writes into (base_app.html).
   --------------------------------------------------------------------- */
.is-processing {
  opacity: 0.55;
  cursor: not-allowed;
}

.action-error-banner {
  position: fixed;
  top: calc(env(safe-area-inset-top, 0px) + 10px);
  left: 50%;
  transform: translateX(-50%);
  z-index: 6;
  display: flex;
  align-items: center;
  gap: 10px;
  max-width: calc(100vw - 32px);
  padding: 10px 14px;
  border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--accent) 16%, var(--card-bg));
  border: 1px solid var(--accent);
  color: var(--accent);
  font-size: 0.85rem;
  font-weight: 700;
  box-shadow: 0 2px 10px var(--shadow);
}

.action-error-banner[hidden] {
  display: none;
}

.action-error-dismiss {
  all: unset;
  cursor: pointer;
  font-size: 1.15rem;
  line-height: 1;
  padding: 0 2px;
}

/* ---------------------------------------------------------------------
   0.7.1 plan items 5/7/8 -- More page DND status line + "Your devices"
   collapsible list + honest push-device count.
   --------------------------------------------------------------------- */
.dnd-status,
.push-device-count {
  font-weight: 700;
}

.device-list-details {
  margin-top: 14px;
}

.device-list-details summary {
  cursor: pointer;
}

.device-list-details .ledger-list {
  margin-top: 8px;
}

/* ---------------------------------------------------------------------
   Deputy row states (amended D-LLM4) -- inbox rows' "Draft now" section
   (templates/inbox/_item_row.html). Status text sits in the row's muted
   register; the failed state is LOUD (accent, bold -- same voice as
   .claim-error) per the fail-loudly rule: a failed draft must never
   read like nothing happened.
   --------------------------------------------------------------------- */
/* Fixed narrow Deputy column (Kaijen 2026-08-22): the status must never
   crowd the note text out of the row. Labels are short; details live
   behind the cell's deep links (chore page / admin draft page). */
.deputy-cell {
  flex: 0 0 92px;
  width: 92px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
}

.deputy-cell .btn {
  font-size: 0.8rem;
  padding: 4px 8px;
}

.deputy-status {
  color: var(--muted);
  font-size: 0.8rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}

a.deputy-status {
  text-decoration: underline;
}

.deputy-status-failed {
  color: var(--accent);
  font-weight: 700;
}

/* ---------------------------------------------------------------------
   Retire/revive (Kaijen 2026-09-04): retire disclosure on chore_detail,
   retired-chores section on the directory, and the post-revive
   "check the date" notice on occurrence_detail. */
.retire-chore,
.retired-chores {
  margin: 12px 0;
}

.retire-chore summary,
.retired-chores summary {
  cursor: pointer;
  color: var(--muted);
}

.retire-chore .subtitle {
  margin: 8px 0;
}

.revived-notice {
  margin: 8px 0;
  padding: 8px 12px;
  border-left: 3px solid var(--accent);
  font-size: 0.9rem;
}
