:root {
  --bg: #faf7f2;
  --surface: #ffffff;
  --ink: #2e2a26;
  --ink-soft: #6b6459;
  --ink-faint: #a49b8c;
  --accent: #c97b4a;
  --accent-soft: #f0ded0;
  --border: #ece5da;
  --done-bg: #f4f1ea;
  --snackbar-bg: #34302b;
  --snackbar-ink: #f7f3ec;
  --shadow: 0 1px 2px rgba(60, 45, 25, 0.05);
  --shadow-lift: 0 2px 4px rgba(60, 45, 25, 0.06), 0 8px 20px rgba(60, 45, 25, 0.07);
  --radius: 14px;
  --radius-sm: 10px;
  color-scheme: light;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #191714;
    --surface: #262320;
    --ink: #ece7de;
    --ink-soft: #a89f92;
    --ink-faint: #726a5e;
    --accent: #e0996b;
    --accent-soft: #3a2e24;
    --border: #3a352f;
    --done-bg: #201e1b;
    --snackbar-bg: #3d3831;
    --snackbar-ink: #f2ede4;
    --shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
    --shadow-lift: 0 2px 4px rgba(0, 0, 0, 0.3), 0 8px 20px rgba(0, 0, 0, 0.32);
    color-scheme: dark;
  }
}

* {
  box-sizing: border-box;
}

html, body {
  height: 100%;
}

body {
  margin: 0;
  background: var(--bg);
  background-image: radial-gradient(
    120% 60% at 50% 0%,
    color-mix(in srgb, var(--accent) 5%, transparent) 0%,
    transparent 60%
  );
  background-repeat: no-repeat;
  background-attachment: fixed;
  color: var(--ink);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  overscroll-behavior-y: contain;
}

/* Announced to screen readers, invisible to everyone else. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* One visible, consistent focus ring for everything reachable by keyboard. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 8px;
}

.app {
  max-width: 560px;
  margin: 0 auto;
  min-height: 100dvh;
  padding: env(safe-area-inset-top, 0) 20px calc(env(safe-area-inset-bottom, 0) + 32px);
  display: flex;
  flex-direction: column;
}

/* Topbar */

.topbar {
  padding: 10px 4px 18px;
  text-align: center;
}

/* Its own row rather than floating beside the stats: at 320px there is no
   room for centred stats flanked by buttons, and they collided. */
.topbar-actions {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 2px;
  margin-bottom: 6px;
}

.icon-btn {
  width: 36px;
  height: 36px;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: var(--ink-faint);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: color 0.15s ease, background 0.15s ease;
}

.icon-btn:hover {
  color: var(--accent);
  background: var(--accent-soft);
}

.icon-btn[hidden] {
  display: none;
}

/* The install button only appears when installing is actually possible, so
   it can afford to draw the eye. */
.install-btn {
  color: var(--accent);
}

/* Add to Home Screen walkthrough — iOS Safari has no install API */

.ios-install {
  position: relative;
  background: var(--accent-soft);
  border-radius: var(--radius);
  padding: 16px 18px;
  margin: 4px 0 20px;
}

.ios-install[hidden] {
  display: none;
}

.ios-install-title {
  margin: 0 0 10px;
  font-size: 15px;
  font-weight: 600;
  color: var(--ink);
}

.ios-install-steps {
  margin: 0;
  padding-left: 20px;
  color: var(--ink-soft);
  font-size: 14px;
  line-height: 1.7;
}

.ios-glyph {
  display: inline-flex;
  vertical-align: -3px;
  color: var(--accent);
}

.ios-step-label {
  font-weight: 600;
  color: var(--ink);
}

.ios-install-dismiss {
  margin-top: 12px;
  border: none;
  background: var(--accent);
  color: #fff;
  font-family: inherit;
  font-size: 14px;
  font-weight: 600;
  padding: 8px 14px;
  border-radius: 12px;
  cursor: pointer;
}

.stats {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
}

/* Number and label on one line: the counts are reassurance, not a scoreboard,
   and stacking them made two big digits the first thing on the page. */
.stat {
  display: flex;
  align-items: baseline;
  gap: 6px;
}

.stat-num {
  font-size: 19px;
  font-weight: 600;
  line-height: 1.1;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}

.stat-label {
  font-size: 13px;
  color: var(--ink-faint);
  letter-spacing: 0.01em;
}

.stat-divider {
  width: 1px;
  height: 14px;
  background: var(--border);
}

.tagline {
  margin: 10px 0 0;
  font-size: 13.5px;
  color: var(--ink-faint);
  letter-spacing: 0.01em;
}

/* Main */

.main {
  flex: 1;
  display: flex;
  flex-direction: column;
}

.add-form {
  display: flex;
  gap: 9px;
  margin-bottom: 16px;
}

#taskInput {
  flex: 1;
  min-width: 0;
  border: 1px solid var(--border);
  background: var(--surface);
  border-radius: var(--radius);
  padding: 13px 16px;
  font-family: inherit;
  font-size: 16px;
  color: var(--ink);
  outline: none;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

#taskInput::placeholder {
  color: var(--ink-faint);
}

#taskInput:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

.add-btn {
  flex-shrink: 0;
  width: 46px;
  height: 46px;
  border: none;
  border-radius: 50%;
  background: var(--accent);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: transform 0.1s ease, opacity 0.15s ease;
}

.add-btn:active {
  transform: scale(0.92);
}

.add-btn:disabled {
  opacity: 0.35;
  cursor: default;
}

.add-btn:disabled:active {
  transform: none;
}

/* Task list */

.task-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 7px;
}

/* A hairline carries the card edge; the shadow only suggests lift. In dark
   mode the shadow does nothing at all, so without this the cards vanished
   into the page. */
.task-item {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 11px 12px;
  box-shadow: var(--shadow);
  animation: enter 0.22s ease;
  transition: box-shadow 0.18s ease, border-color 0.18s ease, transform 0.18s ease;
}

@media (hover: hover) and (pointer: fine) {
  .task-item:hover {
    border-color: color-mix(in srgb, var(--accent) 30%, var(--border));
    box-shadow: var(--shadow-lift);
  }
}

@keyframes enter {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: translateY(0); }
}

/* Duration is mirrored by LEAVE_MS in app.js. */
.task-item.leaving {
  animation: leave 0.2s ease forwards;
  pointer-events: none;
}

@keyframes leave {
  to { opacity: 0; transform: translateY(-4px) scale(0.98); }
}

/* Reordering */

.drag-handle,
.drag-handle-spacer {
  flex-shrink: 0;
  width: 20px;
  height: 23px;
  margin-top: 1px;
}

.drag-handle {
  border: none;
  background: transparent;
  padding: 0;
  color: var(--ink-faint);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: grab;
  /* Opts this one element out of the scroller so a vertical drag here is a
     drag, not a page scroll. */
  touch-action: none;
  transition: color 0.15s ease;
}

.drag-handle:hover {
  color: var(--accent);
}

.drag-handle:active {
  cursor: grabbing;
}

/* Lifted out of flow so it tracks the pointer without disturbing the list. */
.task-item.dragging {
  position: fixed;
  z-index: 20;
  margin: 0;
  animation: none;
  cursor: grabbing;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.22);
}

.task-placeholder {
  list-style: none;
  box-sizing: border-box;
  border: 2px dashed var(--border);
  border-radius: var(--radius);
  background: transparent;
}

body.is-dragging {
  user-select: none;
  -webkit-user-select: none;
  cursor: grabbing;
}

.check-btn {
  flex-shrink: 0;
  width: 23px;
  height: 23px;
  border-radius: 50%;
  border: 1.5px solid color-mix(in srgb, var(--ink-faint) 55%, transparent);
  background: transparent;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-top: 1px;
  padding: 0;
  transition: border-color 0.15s ease, background 0.15s ease;
}

.check-btn:hover {
  border-color: var(--accent);
}

.check-btn svg {
  opacity: 0;
  transform: scale(0.5);
  transition: opacity 0.14s ease, transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1);
  color: #fff;
}

.task-item.done .check-btn svg {
  opacity: 1;
  transform: scale(1);
}

/* A button so editing is keyboard-reachable, styled to read as plain text. */
.task-text {
  flex: 1;
  min-width: 0;
  border: none;
  background: none;
  margin: 0;
  padding: 1px 0 0;
  font-family: inherit;
  font-size: 15.5px;
  line-height: 1.45;
  color: inherit;
  text-align: left;
  overflow-wrap: anywhere;
  cursor: text;
}

/* A task that carries a link: the label opens it, the host says where. */
/* Label and host as explicit flex children. As plain inline text the host's
   nowrap width made the browser break the label mid-phrase, even with room
   for both; this way the label keeps its natural width and the host drops to
   its own line only when it genuinely has to. */
.task-link {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  column-gap: 7px;
  text-decoration: none;
  color: var(--accent);
  cursor: pointer;
}

.task-link-label {
  min-width: 0;
  overflow-wrap: break-word;
  text-decoration: underline;
  text-decoration-color: color-mix(in srgb, var(--accent) 35%, transparent);
  text-underline-offset: 2px;
}

.task-link:hover .task-link-label {
  text-decoration-color: var(--accent);
}

.task-link-host {
  flex-shrink: 0;
  font-size: 11.5px;
  color: var(--ink-faint);
  white-space: nowrap;
}

.task-item.done .task-link,
.task-item.done .task-link-label {
  color: var(--ink-faint);
  text-decoration-color: var(--ink-faint);
}

.edit-btn {
  flex-shrink: 0;
  border: none;
  background: transparent;
  color: var(--ink-faint);
  cursor: pointer;
  padding: 2px;
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: color 0.15s ease;
}

.edit-btn:hover {
  color: var(--accent);
}

.task-item.done .task-text {
  color: var(--ink-faint);
  text-decoration: line-through;
  text-decoration-color: var(--ink-faint);
}

.task-edit {
  flex: 1;
  min-width: 0;
  border: none;
  border-bottom: 1px solid var(--accent);
  background: none;
  padding: 0 0 1px;
  font-family: inherit;
  font-size: 15.5px;
  line-height: 1.45;
  color: var(--ink);
  outline: none;
}

.delete-btn {
  flex-shrink: 0;
  border: none;
  background: transparent;
  color: var(--ink-faint);
  cursor: pointer;
  padding: 2px;
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: color 0.15s ease;
}

.delete-btn:hover {
  color: var(--accent);
}

/* Where there is a real pointer, the destructive control stays out of the way
   until the row is actually under it. Touch devices keep it visible, since
   there is no hover to reveal it with. */
@media (hover: hover) and (pointer: fine) {
  .delete-btn,
  .edit-btn {
    opacity: 0;
    transition: opacity 0.15s ease, color 0.15s ease;
  }

  .task-item:hover .delete-btn,
  .task-item:hover .edit-btn,
  .task-item:focus-within .delete-btn,
  .task-item:focus-within .edit-btn,
  .delete-btn:focus-visible,
  .edit-btn:focus-visible {
    opacity: 1;
  }
}

/* Empty state */

.empty-state {
  text-align: center;
  color: var(--ink-faint);
  font-size: 14.5px;
  line-height: 1.6;
  margin-top: 44px;
  padding: 0 24px;
}

.empty-state[hidden] {
  display: none;
}

/* Done section */

.done-section {
  margin-top: 22px;
}

.done-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.done-toggle {
  display: flex;
  align-items: center;
  gap: 6px;
  border: none;
  background: none;
  font-family: inherit;
  color: var(--ink-faint);
  font-size: 13px;
  cursor: pointer;
  padding: 8px 2px;
}

.clear-done-btn {
  border: none;
  background: none;
  font-family: inherit;
  color: var(--ink-faint);
  font-size: 13px;
  cursor: pointer;
  padding: 8px 2px;
  transition: color 0.15s ease;
}

.clear-done-btn:hover {
  color: var(--accent);
}

.clear-done-btn[hidden] {
  display: none;
}

.chevron {
  transition: transform 0.15s ease;
}

.done-toggle[aria-expanded="true"] .chevron {
  transform: rotate(90deg);
}

.done-list {
  margin-top: 10px;
}

.done-list .task-item {
  background: transparent;
  box-shadow: none;
  border-color: var(--border);
}

@media (hover: hover) and (pointer: fine) {
  .done-list .task-item:hover {
    background: var(--done-bg);
    box-shadow: none;
    border-color: var(--border);
  }
}

/* The filled check was the most saturated thing on the page, on the rows
   that matter least. */
.task-item.done .check-btn {
  background: color-mix(in srgb, var(--accent) 62%, transparent);
  border-color: transparent;
}

/* Import banner */

.import-banner {
  background: var(--accent-soft);
  border-radius: var(--radius);
  padding: 14px 16px;
  margin: 4px 0 20px;
}

.import-banner p {
  margin: 0 0 10px;
  font-size: 14px;
  color: var(--ink);
}

.import-banner-actions {
  display: flex;
  gap: 10px;
}

.import-btn {
  border: none;
  background: var(--accent);
  color: #fff;
  font-family: inherit;
  font-size: 14px;
  font-weight: 600;
  padding: 8px 14px;
  border-radius: 12px;
  cursor: pointer;
}

.import-dismiss-btn {
  border: none;
  background: transparent;
  color: var(--ink-soft);
  font-family: inherit;
  font-size: 14px;
  padding: 8px 14px;
  cursor: pointer;
}

.import-banner[hidden] {
  display: none;
}

/* Version stamp */

.app-footer {
  margin-top: auto;
  padding-top: 28px;
  text-align: center;
}

.app-version {
  margin: 0;
  font-size: 11px;
  letter-spacing: 0.04em;
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
}

/* Cheer — the big centred celebration on completing something */

.cheer {
  position: fixed;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%) scale(0.8);
  background: var(--accent);
  color: #fff;
  padding: 28px 34px;
  border-radius: 28px;
  font-size: clamp(22px, 6vw, 30px);
  font-weight: 700;
  line-height: 1.3;
  /* Anchored at left:50%, so shrink-to-fit would only ever offer it half the
     viewport. Size to the content and clamp against the full width instead. */
  width: max-content;
  max-width: calc(100% - 48px);
  text-align: center;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease, transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
  box-shadow: 0 16px 40px rgba(0, 0, 0, 0.28);
  z-index: 10;
}

.cheer.show {
  opacity: 1;
  transform: translate(-50%, -50%) scale(1);
}

/* Snackbar — quiet, actionable messages like undo */

.snackbar {
  position: fixed;
  left: 50%;
  bottom: calc(env(safe-area-inset-bottom, 0px) + 20px);
  transform: translate(-50%, 12px);
  display: flex;
  align-items: center;
  gap: 14px;
  width: max-content;
  max-width: calc(100% - 32px);
  padding: 12px 12px 12px 18px;
  border-radius: 14px;
  background: var(--snackbar-bg);
  color: var(--snackbar-ink);
  font-size: 14px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
  opacity: 0;
  /* visibility keeps the hidden snackbar out of the tab order entirely */
  visibility: hidden;
  transition: opacity 0.2s ease, transform 0.2s ease, visibility 0s linear 0.2s;
  z-index: 11;
}

.snackbar.show {
  opacity: 1;
  visibility: visible;
  transform: translate(-50%, 0);
  transition: opacity 0.2s ease, transform 0.2s ease, visibility 0s;
}

.snackbar-action {
  flex-shrink: 0;
  border: none;
  background: rgba(255, 255, 255, 0.12);
  color: inherit;
  font-family: inherit;
  font-size: 14px;
  font-weight: 600;
  padding: 6px 12px;
  border-radius: 9px;
  cursor: pointer;
  transition: background 0.15s ease;
}

.snackbar-action:hover {
  background: rgba(255, 255, 255, 0.22);
}

.snackbar-action[hidden] {
  display: none;
}

@media (min-width: 480px) {
  .topbar { padding-top: 22px; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}
