/* Dooable — chassis styles.
   Brand tokens are rewritten by `appfactory new`; everything else is structure. */

/* >>> tokens */
:root {
  --bg: #151A21;
  --surface: #1b1b24;
  --text: #f2f2f7;
  --dim: #9a9aa8;
  --accent: #F2A65A;
  --radius: 14px;
  --pad: 16px;
}
/* <<< tokens */

/* App palette. Declared after the factory token block so these win, while the
   block above stays untouched for `appfactory sync` to rewrite. */
:root {
  --surface: #1E242D;
  --raised: #28313D;
  --line: rgba(255,255,255,.09);
  --text: #ECEFF3;
  --dim: #98A2AF;

  --e-deep:  #7C8CF8;
  --e-light: #4FB8A8;
  --e-zero:  #9AA3AE;

  --on-accent: #1A1206;
  --danger: #E4736B;
  --tap: 44px;
  --text-scale: 1;

  /* Type scale. Deliberately wide steps — the previous set ran 1rem to
     1.15rem, which reads as one undifferentiated size and made every screen a
     wall of sameness. */
  --fs-display: 1.75rem;
  --fs-title:   1.25rem;
  --fs-body:    1rem;
  --fs-small:   0.875rem;
  --fs-caption: 0.75rem;

  /* Motion. One place to tune, and one place for prefers-reduced-motion to
     neutralise without hunting down individual rules. */
  --dur-fast: 140ms;
  --dur:      210ms;
  --dur-slow: 320ms;
  --ease: cubic-bezier(.2, .7, .3, 1);

  --shadow-1: 0 1px 2px rgba(0,0,0,.24);
  --shadow-2: 0 6px 18px rgba(0,0,0,.30);
}

:root[data-theme="light"] {
  --bg: #F7F5F2;
  --surface: #FFFFFF;
  --raised: #F0EDE8;
  --line: rgba(0,0,0,.10);
  --text: #1A1F26;
  --dim: #5C6672;
  --accent: #9A5610;

  --e-deep:  #4A57BE;
  --e-light: #257A6C;
  --e-zero:  #667080;

  --on-accent: #FFFFFF;
  --danger: #C0392B;

  --shadow-1: 0 1px 2px rgba(0,0,0,.07);
  --shadow-2: 0 6px 18px rgba(0,0,0,.10);
}

* { box-sizing: border-box; }

/* Author `display` rules outrank the UA's [hidden] rule, so any element this
   app both styles and toggles would otherwise stay visible. Guard it once here
   rather than remembering a [hidden] variant for every new component. */
[hidden] { display: none !important; }

html {
  /* Drives the in-app text-size setting. Everything below is in rem so the
     whole interface scales together rather than only the body copy. */
  font-size: calc(16px * var(--text-scale, 1));
  scroll-behavior: smooth;
}

html, body {
  margin: 0;
  /* --app-height is set ONLY while a field is focused (see index.html).
     Unset, this falls through to 100dvh, which is what we want the rest of
     the time because it survives rotation without stale pixel values. */
  height: var(--app-height, 100dvh);
  overflow: hidden;
}

body {
  background: var(--bg);
  color: var(--text);
  font: var(--fs-body)/1.5 -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
  -webkit-font-smoothing: antialiased;
  /* Never let a rubber-band scroll expose the page behind the app. */
  overscroll-behavior: none;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}

::selection { background: color-mix(in srgb, var(--accent) 35%, transparent); color: var(--text); }

/* Subtle, on-brand, and out of the way until you scroll. */
* { scrollbar-width: thin; scrollbar-color: var(--raised) transparent; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: var(--raised);
  border-radius: 999px;
  border: 3px solid transparent;
  background-clip: content-box;
}
::-webkit-scrollbar-thumb:hover { background: var(--dim); background-clip: content-box; }

#app {
  display: flex;
  flex-direction: column;
  height: 100%;
  /* Top/sides only — the tab bar (or batch bar) owns the bottom safe-area so we
     never double-count the home indicator. */
  padding: env(safe-area-inset-top) env(safe-area-inset-right) 0 env(safe-area-inset-left);
  opacity: 1;
  transition: opacity var(--dur) var(--ease);
}
html:not([data-ready="1"]) #nowList,
html:not([data-ready="1"]) #nowEmpty {
  min-height: 120px;
  border-radius: var(--radius);
  background: linear-gradient(90deg, var(--surface), var(--raised), var(--surface));
  background-size: 200% 100%;
  animation: shimmer 1.2s ease-in-out infinite;
}
@keyframes shimmer { 50% { background-position: 100% 0; } }

#appBar {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--pad);
  padding: 10px var(--pad) 4px;
  flex: 0 0 auto;
  position: sticky;
  top: 0;
  z-index: 5;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  transition: box-shadow var(--dur) var(--ease), padding var(--dur) var(--ease);
}
.app-bar-copy { min-width: 0; }
#appTitle { font-size: var(--fs-title); margin: 0; font-weight: 650; letter-spacing: -.02em; }
.app-subtitle {
  margin: 2px 0 0;
  font-size: var(--fs-caption);
  color: var(--dim);
  letter-spacing: .01em;
}

.screen {
  flex: 1 1 auto;
  overflow-y: auto;
  padding: 0 var(--pad) 24px;
  -webkit-overflow-scrolling: touch;
}
.screen.is-active { animation: screen-in var(--dur-slow) var(--ease); }
.screen-head { margin: 4px 0 14px; }
.screen-title {
  margin: 0;
  font-size: var(--fs-display);
  font-weight: 650;
  letter-spacing: -.02em;
  line-height: 1.15;
}
.screen-lede {
  margin: 6px 0 0;
  color: var(--dim);
  font-size: var(--fs-small);
  max-width: 36em;
}
@keyframes screen-in { from { opacity: .0; transform: translateY(6px); } to { opacity: 1; transform: none; } }

.card {
  background: var(--surface);
  border-radius: var(--radius);
  padding: var(--pad);
}
.card h2 { margin: 0 0 .5rem; font-size: var(--fs-title); letter-spacing: -.01em; line-height: 1.25; }
.card p { margin: 0 0 .75rem; }
.dim { color: var(--dim); }
code { background: rgba(128,128,128,.18); padding: .1em .4em; border-radius: 6px; font-size: .9em; }

.icon-btn {
  appearance: none;
  border: 0;
  background: transparent;
  color: inherit;
  padding: 10px;
  border-radius: 10px;
  cursor: pointer;
  display: inline-flex;
  line-height: 0;
  min-width: var(--tap);
  min-height: var(--tap);
  align-items: center;
  justify-content: center;
  transition: background var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.icon-btn:active { background: rgba(128,128,128,.2); transform: scale(.94); }

/* --- buttons -------------------------------------------------------------- */
.btn {
  appearance: none;
  border: 1px solid var(--line);
  background: var(--raised);
  color: var(--text);
  font: inherit;
  font-weight: 550;
  padding: 12px 18px;
  min-height: var(--tap);
  border-radius: 12px;
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease),
              transform var(--dur-fast) var(--ease),
              box-shadow var(--dur-fast) var(--ease),
              opacity var(--dur-fast) var(--ease);
}
/* Press feedback is a scale rather than a nudge — it reads as the surface
   yielding under the finger instead of the whole row shifting. */
.btn:active { transform: scale(.975); }
.btn:disabled { opacity: .4; cursor: default; transform: none; }
.btn-primary { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
.btn-accent {
  background: color-mix(in srgb, var(--accent) 22%, var(--raised));
  border-color: color-mix(in srgb, var(--accent) 55%, var(--line));
  color: var(--text);
}
.btn-danger { background: transparent; border-color: var(--danger); color: var(--danger); }
.btn-quiet { background: transparent; }
.btn-block { display: block; width: 100%; }
.btn-sm { padding: 8px 12px; min-height: 36px; font-size: var(--fs-small); }

/* Hover is a desktop-only affordance; on touch it sticks after a tap and makes
   the last-pressed control look permanently active. */
@media (hover: hover) and (pointer: fine) {
  .btn:hover:not(:disabled) { border-color: var(--dim); box-shadow: var(--shadow-1); transform: translateY(-1px); }
  .btn-primary:hover:not(:disabled) { filter: brightness(1.06); }
  .btn-accent:hover:not(:disabled) { border-color: var(--accent); }
  .btn-danger:hover:not(:disabled) { background: color-mix(in srgb, var(--danger) 12%, transparent); }
  .icon-btn:hover { background: rgba(128,128,128,.14); }
}

/* --- capture -------------------------------------------------------------- */
.capture-panel { margin-bottom: 14px; }
.capture-open {
  appearance: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: 40px;
  padding: 8px 14px;
  border: 1px dashed color-mix(in srgb, var(--accent) 55%, var(--line));
  border-radius: 12px;
  background: color-mix(in srgb, var(--accent) 10%, transparent);
  color: var(--accent);
  font: inherit;
  font-size: var(--fs-small);
  font-weight: 650;
  line-height: 1;
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease),
              transform var(--dur-fast) var(--ease);
}
.capture-open > span[data-icon],
.capture-open > svg {
  display: inline-flex;
  line-height: 0;
  flex: 0 0 auto;
}
.capture-open:active { transform: scale(.98); }
@media (hover: hover) and (pointer: fine) {
  .capture-open:hover {
    background: color-mix(in srgb, var(--accent) 16%, transparent);
    border-color: var(--accent);
  }
}
.capture-composer {
  margin-bottom: 0;
  display: grid;
  gap: 12px;
  padding: 14px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  animation: fade-up var(--dur-slow) var(--ease);
}
.composer-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
.composer-title,
.matcher-title {
  margin: 0;
  font-size: var(--fs-body);
  line-height: 1.25;
  font-weight: 650;
  letter-spacing: -.01em;
}
.capture {
  display: flex;
  gap: 8px;
  align-items: center;
  margin-bottom: 14px;
}
.capture-meta { display: grid; gap: 10px; }
.capture-choice { display: grid; gap: 5px; }
.choice-label {
  color: var(--dim);
  font-size: var(--fs-caption);
  font-weight: 600;
  letter-spacing: .02em;
}
.capture-meta .chip-row { gap: 6px; }
.capture-composer .capture-input {
  width: 100%;
  min-width: 0;
  background: var(--raised);
  border: 1px solid var(--line);
  color: var(--text);
  font: inherit;
  padding: 0 14px;
  height: var(--tap);
  border-radius: 12px;
  transition: border-color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.capture-input {
  flex: 1 1 auto;
  min-width: 0;
  background: var(--surface);
  border: 1px solid var(--line);
  color: var(--text);
  font: inherit;
  padding: 0 14px;
  height: var(--tap);
  border-radius: 12px;
  transition: border-color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.capture-input::placeholder { color: var(--dim); }
.capture-input:focus { border-color: var(--accent); outline: none; }
.capture-input:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.capture-add {
  width: 100%;
  min-height: var(--tap);
  padding: 12px 16px;
  border-radius: 12px;
  border: 0;
  background: var(--accent);
  color: var(--on-accent);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font: inherit;
  font-weight: 650;
  cursor: pointer;
  transition: transform var(--dur-fast) var(--ease), filter var(--dur-fast) var(--ease);
}
.capture-add:active { transform: scale(.98); }
@media (hover: hover) and (pointer: fine) { .capture-add:hover { filter: brightness(1.08); } }
/* The composer's save button is full width; the one-line capture rows beside
   an input are not. Those keep the compact square + . */
#addListForm .capture-add,
#quickCaptureForm .capture-add {
  width: var(--tap);
  height: var(--tap);
  padding: 0;
  flex: 0 0 auto;
}

/* A just-added task should be visibly acknowledged even when it lands off the
   matcher's current filter and never appears in the list. */
@keyframes capture-ok { 50% { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 10%, var(--surface)); } }
.capture-input.is-ok { animation: capture-ok var(--dur-slow) var(--ease); }

/* --- matcher -------------------------------------------------------------- */
.matcher {
  margin-bottom: 14px;
  padding: 14px;
  border: 1px solid color-mix(in srgb, var(--accent) 34%, var(--line));
  border-radius: var(--radius);
  background: color-mix(in srgb, var(--accent) 6%, var(--surface));
}
.matcher-head { margin-bottom: 12px; }
.matcher-head p {
  margin: 4px 0 0;
  color: var(--dim);
  font-size: var(--fs-small);
}
.matcher-full { display: grid; gap: 12px; }
.picker-label {
  margin: 0 0 6px;
  font-size: var(--fs-caption);
  color: var(--dim);
  text-transform: uppercase;
  letter-spacing: .07em;
  font-weight: 600;
}

.chip-row { display: flex; flex-wrap: wrap; gap: 8px; }

.chip {
  appearance: none;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: var(--fs-small);
  padding: 10px 14px;
  min-height: var(--tap);
  border-radius: 999px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  line-height: 1;
  transition: background var(--dur) var(--ease),
              border-color var(--dur) var(--ease),
              color var(--dur) var(--ease),
              transform var(--dur-fast) var(--ease);
}
.chip:active { transform: scale(.96); }
.chip.is-on { background: var(--accent); border-color: var(--accent); color: var(--on-accent); font-weight: 650; }
.chip-sm { min-height: 36px; padding: 7px 12px; font-size: var(--fs-caption); }
.chip-energy svg { flex: 0 0 auto; }
.chip-energy.energy-deep  { color: var(--e-deep); }
.chip-energy.energy-light { color: var(--e-light); }
.chip-energy.energy-zero  { color: var(--e-zero); }
/* Keep the energy hue visible when selected — accent fill alone erases the
   metaphor the whole matcher is built on. */
.chip-energy.is-on {
  color: var(--on-accent);
  background: color-mix(in srgb, currentColor 28%, var(--accent));
  border-color: color-mix(in srgb, currentColor 40%, var(--accent));
}
.chip-energy.energy-deep.is-on  { background: color-mix(in srgb, var(--e-deep) 35%, var(--accent)); border-color: var(--e-deep); }
.chip-energy.energy-light.is-on { background: color-mix(in srgb, var(--e-light) 35%, var(--accent)); border-color: var(--e-light); }
.chip-energy.energy-zero.is-on  { background: color-mix(in srgb, var(--e-zero) 30%, var(--accent)); border-color: var(--e-zero); }
@media (hover: hover) and (pointer: fine) {
  .chip:hover:not(.is-on) { border-color: var(--dim); background: var(--raised); }
}

/* The answer to the question the whole app asks, so it reads as a statement
   rather than a caption. */
.match-count {
  margin: 6px 0 10px;
  font-size: var(--fs-small);
  font-weight: 550;
  color: var(--text);
}
.hidden-note { margin: 14px 2px 0; font-size: var(--fs-small); color: var(--dim); }

/* --- task list ------------------------------------------------------------ */
.task-list { display: grid; gap: 8px; }

.task {
  display: flex;
  align-items: center;
  gap: 4px;
  background: var(--surface);
  border: 1px solid transparent;
  border-radius: var(--radius);
  padding: 4px 6px 4px 4px;
  transition: background var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease),
              box-shadow var(--dur-fast) var(--ease),
              transform var(--dur-fast) var(--ease),
              opacity var(--dur) var(--ease);
}
.task.is-selected { border-color: var(--accent); }
/* Keyboard cursor. Distinct from :focus-visible, which lands on the button
   inside the row rather than the row itself. */
.task.is-cursor { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent) inset; }
.task.is-done .task-title { text-decoration: line-through; color: var(--dim); }
@media (hover: hover) and (pointer: fine) {
  .task:hover { border-color: var(--line); box-shadow: var(--shadow-1); }
}

/* Entry cascade. --i is set per card in app.js; the delay is capped there so a
   long list never front-loads a visible wait. */
@keyframes task-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
.task-list.is-fresh .task {
  animation: task-in var(--dur) var(--ease) backwards;
  animation-delay: calc(var(--i, 0) * 45ms);
}

/* Completion: the row acknowledges the tap, then collapses out of the list,
   rather than vanishing between two synchronous renders. */
@keyframes task-out {
  40%  { opacity: .5; transform: scale(.99); }
  100% { opacity: 0; transform: scale(.97); }
}
.task.is-completing {
  animation: task-out var(--dur-slow) var(--ease) forwards;
  pointer-events: none;
}

.task-tick {
  appearance: none;
  border: 0;
  background: transparent;
  color: var(--dim);
  width: var(--tap);
  height: var(--tap);
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  cursor: pointer;
  border-radius: 50%;
  transition: color var(--dur) var(--ease), background var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.task-tick:active { background: rgba(128,128,128,.18); transform: scale(.9); }
.task.is-done .task-tick { color: var(--accent); }
@media (hover: hover) and (pointer: fine) { .task-tick:hover { color: var(--accent); } }

/* The tick draws itself on rather than snapping between two glyphs. */
@keyframes tick-pop { 0% { transform: scale(.7); } 60% { transform: scale(1.12); } 100% { transform: scale(1); } }
.task.is-completing .task-tick { color: var(--accent); animation: tick-pop var(--dur) var(--ease); }

.task-check {
  width: var(--tap);
  height: var(--tap);
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  cursor: pointer;
}
.task-check input { width: 22px; height: 22px; accent-color: var(--accent); }

.task-body {
  appearance: none;
  border: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  text-align: left;
  flex: 1 1 auto;
  min-width: 0;
  display: grid;
  gap: 5px;
  padding: 8px 4px;
  min-height: var(--tap);
  cursor: pointer;
}
.task-title { font-size: 1.0625rem; font-weight: 550; line-height: 1.3; overflow-wrap: anywhere; letter-spacing: -.006em; }
.task-meta { display: flex; flex-wrap: wrap; gap: 5px; align-items: center; }

.badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: var(--fs-caption);
  line-height: 1;
  padding: 4px 8px;
  border-radius: 999px;
  background: var(--raised);
  color: var(--dim);
  white-space: nowrap;
}
.badge-energy.energy-deep  { color: var(--e-deep); }
.badge-energy.energy-light { color: var(--e-light); }
.badge-energy.energy-zero  { color: var(--e-zero); }
.badge-guess { font-style: italic; opacity: .8; }
.badge-due { color: var(--accent); }
.badge-pin { color: var(--accent); padding: 4px 6px; }

.task-action {
  appearance: none;
  border: 0;
  background: transparent;
  color: var(--dim);
  width: var(--tap);
  height: var(--tap);
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  border-radius: 10px;
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.task-start { color: var(--accent); }
.task-action:active { background: rgba(128,128,128,.18); transform: scale(.9); }
@media (hover: hover) and (pointer: fine) { .task-action:hover { background: rgba(128,128,128,.14); color: var(--text); } }

/* --- groups --------------------------------------------------------------- */
.task-groups { display: grid; gap: 20px; }
.group-head {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 2px 8px;
  font-size: var(--fs-caption);
  font-weight: 650;
  text-transform: uppercase;
  letter-spacing: .07em;
  color: var(--dim);
}
.group-dot { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; }
.group-edit {
  appearance: none;
  margin-left: auto;
  border: 0;
  background: transparent;
  color: var(--dim);
  cursor: pointer;
  padding: 4px 6px;
  border-radius: 8px;
  line-height: 0;
  transition: color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
@media (hover: hover) and (pointer: fine) { .group-edit:hover { color: var(--text); background: rgba(128,128,128,.14); } }

/* --- search & filters ----------------------------------------------------- */
.search-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  margin-bottom: 10px;
}
.search-wrap {
  flex: 1 1 180px;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 8px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 0 12px;
  height: var(--tap);
  transition: border-color var(--dur-fast) var(--ease);
}
.search-actions { display: flex; gap: 8px; flex: 0 0 auto; }
.search-wrap:focus-within { border-color: var(--accent); }
.search-icon { color: var(--dim); line-height: 0; display: inline-flex; }
.search-input {
  flex: 1 1 auto;
  min-width: 0;
  background: transparent;
  border: 0;
  color: var(--text);
  font: inherit;
}
.search-input:focus { outline: none; }
.search-wrap:focus-within { box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 35%, transparent); }
.filter-block { display: grid; gap: 8px; margin-bottom: 12px; }

.inline-toggle {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: var(--tap);
  font-size: var(--fs-small);
  color: var(--dim);
  cursor: pointer;
}
.inline-toggle input { width: 20px; height: 20px; accent-color: var(--accent); }

/* --- done tiles ----------------------------------------------------------- */
.tiles { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; margin-bottom: 20px; }
.tile { background: var(--surface); border-radius: var(--radius); padding: 14px; display: grid; gap: 2px; }
.tile-value { font-size: var(--fs-display); font-weight: 650; font-variant-numeric: tabular-nums; letter-spacing: -.02em; line-height: 1.1; }
.tile-label { font-size: var(--fs-caption); color: var(--dim); }

/* --- empty states --------------------------------------------------------- */
@keyframes fade-up { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
.empty { margin-top: 8px; animation: fade-up var(--dur-slow) var(--ease); }
.empty-art {
  display: grid;
  place-items: center;
  width: 64px;
  height: 64px;
  border-radius: 50%;
  margin-bottom: 12px;
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  color: var(--accent);
}
.welcome h2 { font-size: var(--fs-display); letter-spacing: -.02em; }
.welcome .btn { margin-top: 4px; }

/* --- tab bar -------------------------------------------------------------- */
#tabbar {
  flex: 0 0 auto;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 4px;
  padding: 6px 8px calc(6px + env(safe-area-inset-bottom));
  border-top: 1px solid var(--line);
  background: var(--bg);
  transition: transform var(--dur) var(--ease), opacity var(--dur) var(--ease);
}
body.is-batching #tabbar {
  transform: translateY(110%);
  opacity: 0;
  pointer-events: none;
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
}
.tab {
  appearance: none;
  position: relative;
  border: 0;
  background: transparent;
  color: var(--dim);
  font: inherit;
  font-size: var(--fs-caption);
  display: grid;
  justify-items: center;
  gap: 3px;
  padding: 6px 0;
  min-height: var(--tap);
  border-radius: 10px;
  cursor: pointer;
  line-height: 1;
  transition: color var(--dur) var(--ease);
}
.tab span:first-child { line-height: 0; transition: transform var(--dur) var(--ease); }
.tab.is-active { color: var(--accent); font-weight: 650; }
.tab.is-active span:first-child { transform: translateY(-1px); }
/* Colour alone cannot carry the active state — it is invisible to a
   colour-blind user and to anyone in bright sun. Weight plus a rule under the
   label say the same thing three ways. */
.tab.is-active::after {
  content: '';
  position: absolute;
  bottom: 2px;
  width: 18px;
  height: 2px;
  border-radius: 2px;
  background: var(--accent);
  animation: fade-up var(--dur) var(--ease);
}
.tab:active { background: rgba(128,128,128,.14); }
@media (hover: hover) and (pointer: fine) { .tab:hover { color: var(--text); } }

/* --- sheets --------------------------------------------------------------- */
.sheet-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,.55);
  display: flex;
  align-items: flex-end;
  z-index: 40;
  transition: opacity var(--dur) var(--ease);
}
@keyframes backdrop-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes sheet-in { from { transform: translateY(14px); opacity: .6; } to { transform: none; opacity: 1; } }
.sheet-backdrop:not([hidden]) { animation: backdrop-in var(--dur) var(--ease); }
.sheet-backdrop:not([hidden]) .sheet { animation: sheet-in var(--dur-slow) var(--ease); }

#confirmSheet { z-index: 55; }
.sheet-confirm { max-width: 480px; margin: 0 auto; }
.confirm-body {
  margin: 4px 0 8px;
  color: var(--dim);
  font-size: var(--fs-body);
  line-height: 1.45;
}

.sheet {
  background: var(--surface);
  width: 100%;
  border-radius: var(--radius) var(--radius) 0 0;
  padding: var(--pad);
  padding-bottom: calc(var(--pad) + env(safe-area-inset-bottom));
  max-height: 88%;
  overflow-y: auto;
  box-shadow: var(--shadow-2);
}
.sheet-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
.sheet-head h2 { margin: 0; font-size: var(--fs-title); letter-spacing: -.01em; }
.sheet-foot { margin-top: var(--pad); display: flex; gap: .5rem; align-items: center; font-size: var(--fs-small); }
.sheet-foot a { color: var(--dim); }
#appVersion { margin-left: auto; font-variant-numeric: tabular-nums; }

.row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 0;
  border-bottom: 1px solid var(--line);
  min-height: var(--tap);
}
.row:last-of-type { border-bottom: 0; }
.row > span { display: grid; gap: 2px; }
.row small { font-size: var(--fs-caption); }
.row input[type="checkbox"] { width: 24px; height: 24px; flex: 0 0 auto; accent-color: var(--accent); }
.row-stack { display: grid; justify-items: stretch; gap: 10px; }

.seg { display: flex; gap: 4px; background: var(--raised); padding: 4px; border-radius: 12px; }
.seg button {
  appearance: none;
  flex: 1 1 0;
  border: 0;
  background: transparent;
  color: var(--dim);
  font: inherit;
  font-size: var(--fs-small);
  padding: 9px 4px;
  min-height: 40px;
  border-radius: 9px;
  cursor: pointer;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.seg button.is-on { background: var(--surface); color: var(--text); font-weight: 650; box-shadow: var(--shadow-1); }

.data-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.data-actions .btn { flex: 1 1 auto; padding: 10px 12px; }

/* --- task editor fields --------------------------------------------------- */
.field { display: grid; gap: 6px; margin: 14px 0; }
.field-label { font-size: var(--fs-caption); color: var(--dim); text-transform: uppercase; letter-spacing: .06em; font-weight: 600; }
.field-row { display: flex; gap: 10px; }
.field-half { flex: 1 1 0; min-width: 0; }

.text-input {
  width: 100%;
  background: var(--raised);
  border: 1px solid var(--line);
  color: var(--text);
  font: inherit;
  padding: 11px 12px;
  min-height: var(--tap);
  border-radius: 12px;
  transition: border-color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
textarea.text-input { resize: vertical; min-height: 64px; }
.text-input:focus { border-color: var(--accent); outline: none; }
.text-input:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Errors point at the field that failed, and say so in words underneath. */
@keyframes shake { 10%,90% { transform: translateX(-2px); } 30%,70% { transform: translateX(3px); } 50% { transform: translateX(-3px); } }
.text-input.is-invalid,
.capture-input.is-invalid {
  border-color: var(--danger);
  animation: shake var(--dur-slow) var(--ease);
}
.field-error { font-size: var(--fs-small); color: var(--danger); }
.field-hint { font-size: var(--fs-caption); color: var(--dim); }

.minutes-wrap { display: flex; align-items: center; gap: 8px; font-size: var(--fs-small); }
.minutes-input { width: 92px; }

.energy-picker { display: grid; gap: 8px; }
.energy-opt {
  appearance: none;
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-areas: 'icon label' 'icon desc';
  align-items: center;
  gap: 2px 12px;
  text-align: left;
  border: 1px solid var(--line);
  background: var(--raised);
  color: var(--text);
  font: inherit;
  padding: 12px 14px;
  min-height: var(--tap);
  border-radius: 12px;
  cursor: pointer;
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease), transform var(--dur-fast) var(--ease);
}
.energy-opt:active { transform: scale(.99); }
.energy-opt svg { grid-area: icon; }
.energy-opt-label { grid-area: label; font-weight: 650; }
.energy-opt-desc { grid-area: desc; font-size: var(--fs-caption); color: var(--dim); }
.energy-opt.energy-deep  svg { color: var(--e-deep); }
.energy-opt.energy-light svg { color: var(--e-light); }
.energy-opt.energy-zero  svg { color: var(--e-zero); }
.energy-opt.is-on { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 14%, var(--raised)); }

.sheet-actions { display: flex; gap: 10px; margin-top: 18px; }
.sheet-actions .btn { flex: 1 1 0; }

/* --- batch bar ------------------------------------------------------------ */
.batch-bar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 45;
  background: var(--surface);
  border-top: 1px solid var(--line);
  padding: 10px var(--pad) calc(10px + env(safe-area-inset-bottom));
  display: grid;
  gap: 8px;
  box-shadow: 0 -6px 24px rgba(0,0,0,.3);
  animation: sheet-in var(--dur) var(--ease);
}
.batch-bar[hidden] { display: none; }
body.is-batching .screen { padding-bottom: 160px; }
body.is-batching #app { padding-bottom: 0; }
.batch-count { margin: 0; font-size: var(--fs-small); color: var(--dim); }
.batch-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.batch-actions .btn { flex: 1 1 auto; padding: 10px 12px; font-size: var(--fs-small); }
.batch-picker { display: flex; flex-wrap: wrap; gap: 8px; padding-top: 4px; animation: fade-up var(--dur) var(--ease); }
.batch-picker[hidden] { display: none; }

/* --- focus ---------------------------------------------------------------- */
.focus {
  position: fixed;
  inset: 0;
  z-index: 50;
  background: var(--bg);
  display: flex;
  flex-direction: column;
  padding: env(safe-area-inset-top) var(--pad) calc(var(--pad) + env(safe-area-inset-bottom));
  animation: fade-up var(--dur-slow) var(--ease);
}
.focus[hidden] { display: none; }
.focus-head { flex: 0 0 auto; padding: 6px 0; }
.focus-body {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  text-align: center;
  min-height: 0;
}
.focus-list { margin: 0; font-size: var(--fs-caption); text-transform: uppercase; letter-spacing: .08em; font-weight: 600; }
.focus-title { margin: 0; font-size: var(--fs-display); font-weight: 650; line-height: 1.2; letter-spacing: -.02em; overflow-wrap: anywhere; }
.focus-clock {
  margin: 10px 0 0;
  font-size: clamp(3.25rem, 18vw, 4.5rem);
  font-weight: 300;
  font-variant-numeric: tabular-nums;
  letter-spacing: -.03em;
  line-height: 1;
  transition: color var(--dur) var(--ease);
}
.focus.is-running .focus-clock { color: var(--accent); }
/* A running timer needs a sign of life that is not the digits changing, for
   anyone glancing at it from across the room. */
@keyframes breathe { 50% { opacity: .82; } }
.focus.is-running .focus-clock { animation: breathe 2.4s ease-in-out infinite; }
.focus-adjust { display: flex; gap: 10px; }
.focus-prompt { margin: 6px 0 0; color: var(--accent); font-weight: 650; animation: fade-up var(--dur) var(--ease); }
.focus-actions { flex: 0 0 auto; display: grid; gap: 10px; }
.focus-row { display: flex; gap: 10px; }

/* --- floating pills ------------------------------------------------------- */
.pill {
  position: fixed;
  left: 50%;
  border: 0;
  border-radius: 999px;
  padding: 12px 20px;
  font: inherit;
  font-size: var(--fs-small);
  cursor: pointer;
  z-index: 60;
  box-shadow: var(--shadow-2);
  transform: translateX(-50%);
}
.pill[hidden] { display: none; }
@keyframes pill-in { from { opacity: 0; transform: translate(-50%, 12px); } to { opacity: 1; transform: translateX(-50%); } }
.pill:not([hidden]) { animation: pill-in var(--dur) var(--ease); }

.update-toast { bottom: calc(18px + env(safe-area-inset-bottom)); background: var(--accent); color: var(--on-accent); }
.install-hint { bottom: calc(74px + env(safe-area-inset-bottom)); background: var(--surface); color: var(--text); }
.undo-bar {
  bottom: calc(72px + env(safe-area-inset-bottom));
  background: var(--raised);
  color: var(--text);
  display: flex;
  gap: 14px;
  align-items: center;
  border: 1px solid var(--line);
}
body.is-batching .undo-bar { bottom: calc(140px + env(safe-area-inset-bottom)); }
.undo-action { color: var(--accent); font-weight: 650; }

#toast, #syncStatus {
  position: fixed;
  left: 50%;
  transform: translateX(-50%);
  top: calc(12px + env(safe-area-inset-top));
  background: rgba(0,0,0,.85);
  color: #fff;
  padding: 10px 16px;
  border-radius: 999px;
  font-size: var(--fs-small);
  z-index: 70;
  pointer-events: none;
}
#toast[hidden], #syncStatus[hidden] { display: none; }
#toast:not([hidden]) { animation: pill-in var(--dur) var(--ease); }

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* --- keyboard shortcut reference ------------------------------------------ */
.keys { display: grid; gap: 10px; margin-top: 4px; }
.keys-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; font-size: var(--fs-small); }
kbd {
  font: inherit;
  font-size: var(--fs-caption);
  background: var(--raised);
  border: 1px solid var(--line);
  border-bottom-width: 2px;
  border-radius: 6px;
  padding: 3px 7px;
  color: var(--text);
}

/* Wider screens: keep the reading column narrow rather than stretching rows
   the full width of a tablet. Side-by-side nav appears from tablet up. */
@media (min-width: 620px) {
  .screen > * { max-width: 620px; margin-left: auto; margin-right: auto; }
  .tiles { grid-template-columns: repeat(4, 1fr); }
  .focus-title { font-size: 2.25rem; }
  .sheet { border-radius: var(--radius); margin: 24px auto; max-width: 520px; max-height: min(88%, 720px); }
  .sheet-backdrop { align-items: center; padding: 16px; }
}

@media (min-width: 900px) {
  #app {
    display: grid;
    grid-template-columns: 200px 1fr;
    grid-template-rows: auto 1fr;
    max-width: 1100px;
    margin: 0 auto;
  }
  #appBar { grid-column: 1 / -1; }
  #tabbar {
    grid-column: 1;
    grid-row: 2;
    display: flex;
    flex-direction: column;
    justify-content: flex-start;
    gap: 6px;
    border-top: 0;
    border-right: 1px solid var(--line);
    padding: 12px 10px calc(12px + env(safe-area-inset-bottom));
  }
  .tab {
    grid-template-columns: auto 1fr;
    justify-items: start;
    align-items: center;
    gap: 10px;
    padding: 12px 14px;
    text-align: left;
  }
  .tab.is-active::after { display: none; }
  .tab.is-active { background: color-mix(in srgb, var(--accent) 14%, transparent); }
  .screen { grid-column: 2; grid-row: 2; }
}

/* Very small phones: the chip rows are the first thing to overflow. */
@media (max-width: 360px) {
  :root { --pad: 12px; }
  .chip { padding: 10px 11px; font-size: var(--fs-caption); }
  .task-title { font-size: 1rem; }
  .screen-title { font-size: 1.45rem; }
  .search-actions .btn { padding: 10px 12px; }
}

/* Short or narrow screens — a 4" Android is in the target audience, and there
   the header stack alone pushed every task below the fold. The screen title
   duplicates the active tab label exactly, so on these sizes it is hidden
   visually and kept for screen readers, which orient by heading. Chip
   min-height is deliberately untouched: 44px is the touch-target floor. */
@media (max-width: 360px), (max-height: 640px) {
  .screen-head {
    position: absolute;
    width: 1px; height: 1px;
    margin: 0; padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
  .matcher { padding: 10px; margin-bottom: 10px; }
  .matcher-full { gap: 8px; }
  .matcher-head { margin-bottom: 6px; }
  .capture { margin-bottom: 10px; }
}

:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }

/* One switch for every animation above. Transitions are not merely shortened
   to zero — state changes must still be visible, they just arrive instantly. */
@media (prefers-reduced-motion: reduce) {
  :root { --dur-fast: 0.01ms; --dur: 0.01ms; --dur-slow: 0.01ms; }
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
}
:root[data-reduce-motion="1"] { --dur-fast: 0.01ms; --dur: 0.01ms; --dur-slow: 0.01ms; }
:root[data-reduce-motion="1"] * , :root[data-reduce-motion="1"] *::before, :root[data-reduce-motion="1"] *::after {
  animation-duration: .01ms !important;
  animation-iteration-count: 1 !important;
  transition-duration: .01ms !important;
}
:root[data-reduce-motion="1"] { scroll-behavior: auto; }

@media print {
  #tabbar, #appBar button, .capture, .matcher, .batch-bar, .pill, .focus, .screen-lede, .app-subtitle { display: none !important; }
  body, .screen { height: auto; overflow: visible; }
  .task { break-inside: avoid; border: 1px solid #ccc; }
}


/* --- inline capture parsing + tappable badges ----------------------------- */
.capture-hint {
  margin: -6px 2px 10px;
  font-size: var(--fs-caption);
  line-height: 1.45;
}
.capture-hint b { font-weight: 650; color: var(--text); font-variant-numeric: tabular-nums; }

.capture-preview {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
  margin: -4px 2px 12px;
  padding: 10px 12px;
  border-radius: 12px;
  background: color-mix(in srgb, var(--accent) 8%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--accent) 30%, var(--line));
  animation: fade-up var(--dur) var(--ease);
}
.capture-preview[hidden] { display: none; }
.preview-title { font-weight: 600; margin-right: 2px; overflow-wrap: anywhere; }
.badge-parsed {
  background: color-mix(in srgb, var(--accent) 22%, var(--raised));
  color: var(--text);
  font-weight: 600;
}

/* A badge that is also a control. It has to read as tappable without turning
   the row into a wall of buttons, so the affordance is a dotted underline and
   a press response rather than a full button chrome. */
.badge-tap {
  appearance: none;
  border: 0;
  font: inherit;
  font-size: var(--fs-caption);
  cursor: pointer;
  text-decoration: underline dotted color-mix(in srgb, currentColor 45%, transparent);
  text-underline-offset: 2px;
  /* 44px targets side by side would push the title off a small screen; these
     stay compact and are backed by the full editor and keyboard for anyone who
     cannot hit them. */
  min-height: 28px;
  transition: background var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.badge-tap:active { transform: scale(.94); }
@media (hover: hover) and (pointer: fine) {
  .badge-tap:hover { background: color-mix(in srgb, var(--accent) 22%, var(--raised)); }
}


/* Swipe-to-finish. The row fills from the left as you drag rather than sliding
   away, so the title never moves out from under the finger. Low-alpha fill so
   the text it passes under stays readable. */
.task { position: relative; overflow: hidden; }
.task::before {
  content: '';
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: var(--swipe, 0px);
  background: color-mix(in srgb, var(--accent) 26%, transparent);
  pointer-events: none;
  z-index: 0;
}
.task.is-armed::before { background: color-mix(in srgb, var(--accent) 42%, transparent); }
.task > * { position: relative; z-index: 1; }
/* No transition while the finger is down — it must track the drag exactly. */
.task.is-swiping { transition: none; }
.task.is-swiping .task-body { user-select: none; }
.task.is-armed .task-tick { color: var(--accent); transform: scale(1.12); }


/* .task-body used to BE the button. It cannot be any more: the time and energy
   badges are buttons now, and a button inside a button is invalid HTML — the
   parser silently hoists the inner ones out, which flattened the whole row.
   The title is the button; the badges sit beside it. */
.task-body {
  flex: 1 1 auto;
  min-width: 0;
  display: grid;
  gap: 5px;
  padding: 8px 4px;
}
.task-open {
  appearance: none;
  border: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  text-align: left;
  padding: 0;
  min-height: 28px;
  width: 100%;
  cursor: pointer;
  border-radius: 6px;
}

/* >>> addon-styles */
/* <<< addon-styles */
