/* Task rows, editing surfaces, and task-state animations. */

/* One line per task: completion control, truncated title, due chip.
   Notes render as a subdued second line; edit mode (notes, due date,
   reorder, delete) swaps in when the title is clicked. */
.task-row {
  display: block;
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--color-border-muted);
}

.task-row:last-child { border-bottom: 0; }

/* Completion control sits outside edit mode so toggling stays one click. */
/* Completion toggle: custom SVG, the icon is the whole control — no
   button chrome. pathLength=100 on both shapes makes dash math work
   in percentages: unchecked is a full ring (dasharray 100 100); the
   checked state opens a top-right gap (84 16, matching Lucide's
   circle-check-big) while the check draws through it and breaks out
   of the circle. Hover previews the click: an open task fades its
   ring; a completed task fades only its check. */
.task-complete-form { display: contents; }
.task-complete {
  min-height: 0;
  padding: var(--space-2);
  flex-shrink: 0;
  align-self: flex-start;
  /* Negative margins cancel the vertical padding in layout, so the
     hit target grows without moving the icon off the text line. */
  margin-block: calc(-1 * var(--space-2));
}
.task-complete-toggle {
  display: block;
  width: 1.25rem;
  height: 1.25rem;
  /* Optically center the icon on the text's line box: half the
     leftover leading (1.45em line height minus the 1.25rem icon). */
  margin-block-start: calc((1.45em - 1.25rem) / 2);
}
/* The toggle has its own SVG hover feedback; keep the shared quiet-control
   hover rule from painting a background behind the icon. */
.task-complete.quiet:hover { background: none; }
.task-complete-ring,
.task-complete-check {
  transition: opacity 120ms ease;
}
/* Explicit full-circle dasharray: the default (none) cannot
   interpolate with the checked state's 84 16, which would make the
   closing gap snap instead of animating. */
.task-complete-ring {
  stroke-dasharray: 100 100;
}
/* The check starts fully un-drawn (offset = its whole length). */
.task-complete-check {
  stroke-dasharray: 100;
  stroke-dashoffset: 100;
}
.task-frame-content.completed .task-complete-ring {
  stroke-dasharray: 84 16;
}
.task-frame-content.completed .task-complete-check {
  stroke-dashoffset: 0;
}
/* The check is included even though it's invisible in a settled
   unchecked state: while an un-completion animation erases it under
   the cursor, it must fade gray along with the ring. */
.task-complete:hover .task-complete-ring,
.task-complete:focus-within .task-complete-ring,
.task-complete:hover .task-complete-check,
.task-complete:focus-within .task-complete-check { opacity: 0.35; }
.task-frame-content.completed .task-complete:hover .task-complete-check,
.task-frame-content.completed .task-complete:focus-within .task-complete-check { opacity: 0.35; }
/* Press feedback: unfade while pressed. After completion the row is
   replaced under the cursor and :hover re-matches late; landing back
   on the faded state then reads as releasing the press rather than as
   a flicker. The completed-scoped variant must out-rank the completed
   hover rule above. */
.task-complete:active .task-complete-ring,
.task-complete:active .task-complete-check,
.task-frame-content.completed .task-complete:active .task-complete-check { opacity: 1; }

/* Toggle animation. The task-transition controller applies the
   completion-optimistic class to the existing row on click, so keyframe
   animations begin immediately without waiting for the server response.
   Ordinary renders stay static; the server sends only settled state. */
@keyframes task-ring-open {
  from { stroke-dasharray: 100 100; }
}
@keyframes task-ring-close {
  from { stroke-dasharray: 84 16; }
}
@keyframes task-check-draw {
  from { stroke-dashoffset: 100; }
}
@keyframes task-check-undraw {
  from { stroke-dashoffset: 0; }
  to { stroke-dashoffset: 100; }
}
.task-frame-content.completion-optimistic.completed .task-complete-ring {
  animation: task-ring-open 250ms ease;
}
.task-frame-content.completion-optimistic:not(.completed) .task-complete-ring {
  animation: task-ring-close 250ms ease;
}
.task-frame-content.completion-optimistic.completed .task-complete-check {
  animation: task-check-draw 250ms ease;
}
.task-frame-content.completion-optimistic:not(.completed) .task-complete-check {
  animation: task-check-undraw 250ms ease;
}
@keyframes task-strike-draw {
  from { background-size: 0 1px; }
}
@keyframes task-strike-erase {
  from { background-size: 100% 1px; }
}
.task-frame-content.completion-optimistic.completed .task-title-strike {
  animation: task-strike-draw 250ms ease;
}
.task-frame-content.completion-optimistic:not(.completed) .task-title-strike {
  animation: task-strike-erase 250ms ease;
}
@media (prefers-reduced-motion: reduce) {
  .task-complete-ring,
  .task-complete-check,
  .task-frame-content.completion-optimistic .task-title-strike { animation: none; }
  .task-frame-content { transition: none; }
}

.task-frame { display: block; }
/* The mode wrappers are structural only: keeping their children as direct
   flex items preserves the row layout while hidden keeps the inactive mode
   out of layout and the accessibility tree. */
.task-frame-content > [data-task-edit-target="display"],
.task-frame-content > [data-task-edit-target="editor"] { display: contents; }
.task-frame-content > [data-task-edit-target="display"][hidden],
.task-frame-content > [data-task-edit-target="editor"][hidden] { display: none; }
.task-frame-content {
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
  transition: color 250ms ease;
}
.task-main { flex: 1; min-width: 0; }

.task-line {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  min-width: 0;
}

.task-title {
  display: flex;
  align-items: baseline;
  flex: 1;
  min-width: 0;
  overflow: hidden;
  color: var(--color-text);
  text-decoration: none;
}

.task-title-strike {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* A quiet affordance that appears with the same hover/focus treatment as
   the underline. The title remains the target, so the icon is informative
   rather than a second, smaller hit area. */
.task-edit-icon {
  flex-shrink: 0;
  width: 0.875rem;
  height: 0.875rem;
  margin-inline-start: var(--space-2);
  opacity: 0;
  transition: opacity 120ms ease;
}
.task-title:hover .task-edit-icon,
.task-title:focus-visible .task-edit-icon { opacity: 1; }
/* The completion strike as a background line instead of native
   line-through, so it can animate. It lives on an inline wrapper so
   the line is exactly as long as the text, not the flex-grown title
   box. Pinned at both states (0% and 100%) so the keyframes
   interpolate numerically. */
.task-title-strike {
  background-image: linear-gradient(currentColor, currentColor);
  background-repeat: no-repeat;
  /* Dropped slightly below the line-box middle so the bar clears
     the crossbars of letters like t instead of fusing with them. */
  background-position: left calc(50% + 2px);
  background-size: 0 1px;
}

.task-title:hover,
.task-title:focus-visible { text-decoration: underline; }

.due-chip {
  flex-shrink: 0;
  font-size: 0.8125rem;
  padding: 0 var(--space-2);
  border-radius: var(--radius-sm);
  color: var(--color-text-muted);
  background: var(--color-surface-muted);
  border: 1px solid var(--color-border-muted);
}

.task-notes {
  margin: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--color-text-muted);
  font-size: 0.8125rem;
}

.task-frame-content.completed { color: var(--color-text-muted); }
.task-frame-content.completed .task-title-strike {
  background-size: 100% 1px;
}
.due-chip.completed.overdue {
  color: var(--color-text-muted);
  background: var(--color-surface-muted);
  border-color: var(--color-border-muted);
  font-weight: normal;
}

/* Edit mode keeps every control in one cohesive surface: completion on the
   left, title/details in the middle, and secondary actions at the bottom. */
.task-edit-layout {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
}
.task-edit-layout .task-complete {
  margin-block: 0;
  margin-inline: calc(-1 * var(--space-2)) 0;
}
.task-edit { flex: 1; min-width: 0; }
.task-edit-surface {
  padding: var(--space-2);
  border: 1px solid var(--color-border-muted);
  border-radius: var(--radius-md);
  background: var(--color-surface-muted);
}
.task-edit-form { gap: var(--space-3); }
.task-title-edit {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  min-width: 0;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
}
.task-title-edit input {
  width: 100%;
  min-width: 0;
  margin: 0;
  border: 0;
  background: transparent;
}
.task-title-edit:has(input:focus-visible) {
  outline: 3px solid var(--color-focus);
  outline-offset: 2px;
}
.task-title-edit input:focus-visible { outline: none; }
.task-title-actions {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-1);
}
.task-title-button,
.task-action-button {
  min-height: 0;
  padding: var(--space-2);
  line-height: 1;
}

.task-title-button .icon,
.task-action-button .icon {
  width: 1rem;
  height: 1rem;
}
.task-edit-topline {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--space-3);
}
.edit-field label { display: block; }
.task-due-field input { width: 100%; }
.task-notes-field textarea {
  display: block;
  width: 100%;
  resize: vertical;
}
.task-secondary-actions {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-3);
  padding-top: var(--space-2);
  border-top: 1px solid var(--color-border-muted);
}
.reorder-actions { display: flex; gap: var(--space-1); flex-wrap: wrap; }
.task-delete { color: var(--color-danger-text); }
.task-delete:hover { background: var(--color-danger-bg); }
.due-chip.overdue {
  color: var(--color-danger-text);
  background: var(--color-danger-bg);
  border-color: var(--color-danger-border);
  font-weight: 600;
}
.due-chip.due-today {
  color: var(--color-warning);
  background: var(--color-surface);
  border-color: var(--color-warning);
  font-weight: 600;
}

.rollup-actions form { display: flex; gap: var(--space-2); align-items: end; flex-wrap: wrap; }
.rollup-actions label { display: block; }

.empty-state {
  padding: var(--space-5) var(--space-4);
  text-align: center;
  color: var(--color-text-muted);
  background: var(--color-surface-muted);
  border: 1px dashed var(--color-border);
  border-radius: var(--radius-md);
}

.empty-state p:first-child {
  margin-top: 0;
  font-weight: 600;
  color: var(--color-text);
}

.empty-state p:last-child { margin-bottom: 0; }

/* Completed group: a small visual break, then a subdued heading and
   the same row layout as the in-progress list. The list is
   re-styled as a list of completed tasks; individual rows carry the
   same .completed modifier on their frame as before. */
.completed-section {
  margin-top: var(--space-4);
}
.completed-heading {
  margin: 0 0 var(--space-2) 0;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--color-text-muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.completed-task-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

/* All-done placeholder: a single line that fills the open-list slot
   so the open section still renders its <ul> shell and streams can
   target it cleanly. */
.task-list > .all-done {
  color: var(--color-text-muted);
  padding: var(--space-2) 0;
}
