  :root{
    --ground:#F7F7F3;
    --surface:#FFFFFF;
    --surface-sunken:#EFEFE9;
    --ink:#1C1E1B;
    --ink-soft:#5B5F58;
    --ink-faint:#8B8F86;
    --line:#E3E3DB;
    --line-strong:#CBCBC0;
    --accent:#2B5A55;
    --accent-strong:#1E433F;
    --accent-soft:#DCE8E5;
    --urgent:#B84D2C;
    --urgent-soft:#F4DED3;
    --ondeck:#B8850F;
    --ondeck-soft:#F3E4C2;
    --delegate:#6B5CA5;
    --delegate-soft:#E7E2F4;
    --someday:#83866F;
    --someday-soft:#E7E7DA;
    --done:#3F7A54;
    --done-soft:#DCEBE0;
    --due-soon-bg:#E2F0D9;
    --due-soon-border:#96C67D;
    --due-today-bg:#FCEEBE;
    --due-today-border:#E3B93E;
    --overdue-bg:#F5C0B2;
    --overdue-border:#C23B2A;
    --cat-0:#2a78d6;
    --cat-1:#eb6834;
    --cat-2:#1baf7a;
    --cat-3:#eda100;
    --cat-4:#e87ba4;
    --cat-5:#008300;
    --cat-6:#4a3aa7;
    --cat-7:#e34948;
    --shadow:0 1px 2px rgba(28,30,27,.05), 0 8px 24px rgba(28,30,27,.07);
    --font-display:'Fraunces', Georgia, 'Iowan Old Style', serif;
    --font-body:'Public Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
    --font-mono:'IBM Plex Mono', 'SFMono-Regular', Consolas, monospace;
  }
  @media (prefers-color-scheme: dark){
    :root:not([data-theme="light"]){
      --ground:#14160F;
      --surface:#1B1E17;
      --surface-sunken:#20241C;
      --ink:#ECEDE6;
      --ink-soft:#A3A79A;
      --ink-faint:#6E7266;
      --line:#2C3026;
      --line-strong:#3B4033;
      --accent:#7FB0A6;
      --accent-strong:#9FC7BE;
      --accent-soft:#22332F;
      --urgent:#E2916A;
      --urgent-soft:#3B2A20;
      --ondeck:#D9A64B;
      --ondeck-soft:#3A2F13;
      --delegate:#B4A6DE;
      --delegate-soft:#2E2A42;
      --someday:#A2A68E;
      --someday-soft:#292C21;
      --done:#8FCBA1;
      --done-soft:#1F2F24;
      --due-soon-bg:#1F2C1B;
      --due-soon-border:#40602F;
      --due-today-bg:#3A331A;
      --due-today-border:#6B5A26;
      --overdue-bg:#4A211B;
      --overdue-border:#83382A;
      --cat-0:#3987e5;
      --cat-1:#d95926;
      --cat-2:#199e70;
      --cat-3:#c98500;
      --cat-4:#d55181;
      --cat-5:#008300;
      --cat-6:#9085e9;
      --cat-7:#e66767;
      --shadow:0 1px 2px rgba(0,0,0,.3), 0 8px 24px rgba(0,0,0,.35);
    }
  }
  :root[data-theme="dark"]{
    --ground:#14160F;
    --surface:#1B1E17;
    --surface-sunken:#20241C;
    --ink:#ECEDE6;
    --ink-soft:#A3A79A;
    --ink-faint:#6E7266;
    --line:#2C3026;
    --line-strong:#3B4033;
    --accent:#7FB0A6;
    --accent-strong:#9FC7BE;
    --accent-soft:#22332F;
    --urgent:#E2916A;
    --urgent-soft:#3B2A20;
    --ondeck:#D9A64B;
    --ondeck-soft:#3A2F13;
    --delegate:#B4A6DE;
    --delegate-soft:#2E2A42;
    --someday:#A2A68E;
    --someday-soft:#292C21;
    --done:#8FCBA1;
    --done-soft:#1F2F24;
    --due-soon-bg:#1F2C1B;
    --due-soon-border:#40602F;
    --due-today-bg:#3A331A;
    --due-today-border:#6B5A26;
    --overdue-bg:#4A211B;
    --overdue-border:#83382A;
    --cat-0:#3987e5;
    --cat-1:#d95926;
    --cat-2:#199e70;
    --cat-3:#c98500;
    --cat-4:#d55181;
    --cat-5:#008300;
    --cat-6:#9085e9;
    --cat-7:#e66767;
    --shadow:0 1px 2px rgba(0,0,0,.3), 0 8px 24px rgba(0,0,0,.35);
  }

  *,*::before,*::after{box-sizing:border-box;}
  /* overflow-x:hidden on html+body is a deliberate safety net, per Bryan's
     report that the whole page was scrolling sideways on his phone,
     2026-09-04 - the actual cause (the quick-add row not wrapping on a
     narrow screen, below) is fixed too, but this guarantees the page body
     itself can never scroll horizontally even if some future element
     misbehaves the same way. Containers that intentionally scroll
     sideways (.filter-chips, .view-toggle) set their own overflow-x:auto
     and are unaffected - an ancestor's overflow-x only clips overflow at
     that ancestor's own box, it doesn't reach into a descendant that
     declares its own scrolling context. */
  html{-webkit-text-size-adjust:100%;overflow-x:hidden;}
  body{
    margin:0;
    overflow-x:hidden;
    background:var(--ground);
    color:var(--ink);
    font-family:var(--font-body);
    font-size:15px;
    line-height:1.5;
    -webkit-font-smoothing:antialiased;
  }
  @media (prefers-reduced-motion: reduce){
    *,*::before,*::after{animation-duration:.001ms !important;animation-iteration-count:1 !important;transition-duration:.001ms !important;}
  }
  a{color:inherit;}
  button{font-family:inherit;}
  :focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:4px;}

  #app{max-width:1080px;margin:0 auto;padding:28px 20px 80px;}

  /* ---------- Header ---------- */
  .topbar{display:flex;align-items:flex-end;justify-content:space-between;gap:24px;flex-wrap:wrap;margin-bottom:22px;}
  .eyebrow{font-family:var(--font-mono);font-size:11px;letter-spacing:.09em;text-transform:uppercase;color:var(--ink-faint);margin:0 0 6px;}
  .eyebrow span{color:var(--ink-soft);}
  h1#greetingText{font-family:var(--font-display);font-weight:600;font-size:clamp(1.5rem,1.15rem + 1.6vw,2.15rem);margin:0;text-wrap:balance;letter-spacing:-.01em;}
  .quickadd{display:flex;gap:8px;flex:1 1 380px;max-width:520px;}
  .quickadd input[type="text"],.quickadd input:not([type]){
    flex:1;min-width:0;border:1px solid var(--line-strong);background:var(--surface);color:var(--ink);
    border-radius:10px;padding:11px 14px;font-size:15px;font-family:var(--font-body);
  }
  .quickadd input::placeholder{color:var(--ink-faint);}
  /* Root cause of the sideways-scrolling page Bryan reported on his phone,
     2026-09-04: .quickadd had no flex-wrap, so the text input plus all 3
     buttons (Add/Details/Import) were forced onto one unbreakable row - on
     a phone-width screen their combined minimum widths don't fit, so the
     row (and with it the page) overflowed sideways instead of wrapping.
     Below a phone-ish breakpoint, the input now takes its own full-width
     row and the three buttons share the row underneath. */
  @media (max-width:560px){
    .quickadd{flex-wrap:wrap;}
    .quickadd input[type="text"]{flex:1 1 100%;}
    .quickadd .btn-primary,.quickadd .btn-ghost{flex:1;}
  }
  /* Dragging a file (photo/PDF) over the quick-add box or the Add button -
     opens a new task with it attached, per Bryan's request, 2026-09-03. */
  .quickadd input[type="text"].file-drop-hover{border-color:var(--accent);background:var(--accent-soft);outline:2px dashed var(--accent);outline-offset:2px;}
  #quickAddSubmitBtn.file-drop-hover{outline:2px dashed var(--ground);outline-offset:2px;}
  .btn-primary{background:var(--accent);color:var(--ground);border:1px solid var(--accent);border-radius:10px;padding:11px 16px;font-weight:600;font-size:14px;cursor:pointer;white-space:nowrap;}
  .btn-primary:hover{background:var(--accent-strong);border-color:var(--accent-strong);}
  .btn-ghost{background:transparent;border:1px solid var(--line-strong);color:var(--ink-soft);border-radius:10px;padding:11px 14px;font-size:14px;cursor:pointer;white-space:nowrap;}
  .btn-ghost:hover{border-color:var(--ink-faint);color:var(--ink);}
  .link-btn{background:none;border:none;color:var(--accent);font-size:13px;font-weight:600;cursor:pointer;padding:6px 0;}

  /* Search (🔍 icon that expands into a text input) - collapsed state is
     just the icon button; .search-wrap[data-open="true"] grows the input
     open via a width transition rather than swapping visibility outright,
     so it doesn't jump. Per Bryan's request, 2026-09-11. */
  .search-wrap{display:flex;align-items:center;gap:2px;flex:none;}
  .search-toggle-btn{font-size:15px;}
  .search-input{width:0;min-width:0;opacity:0;border:1px solid transparent;background:transparent;padding:8px 0;font-size:13.5px;font-family:var(--font-body);color:var(--ink);border-radius:9px;transition:width .18s ease, opacity .12s ease, padding .18s ease, border-color .18s ease;}
  .search-wrap[data-open="true"] .search-input{width:190px;opacity:1;padding:8px 10px;border-color:var(--line-strong);background:var(--surface);}
  @media (max-width:560px){
    .search-wrap[data-open="true"] .search-input{width:44vw;}
  }

  /* ---------- Target panel ---------- */
  .target-panel{background:var(--accent-soft);border:1px solid var(--accent);border-radius:16px;padding:16px 18px 18px;margin-bottom:18px;}
  .target-head{display:flex;align-items:flex-end;justify-content:space-between;gap:12px;flex-wrap:wrap;margin-bottom:12px;}
  .target-head .eyebrow{color:var(--accent-strong);margin-bottom:4px;}
  .target-head h2{font-family:var(--font-display);font-weight:600;font-size:clamp(1.05rem,.95rem + .5vw,1.3rem);margin:0;color:var(--ink);text-wrap:balance;}
  .target-progress{font-family:var(--font-mono);font-size:11.5px;font-weight:600;color:var(--accent-strong);white-space:nowrap;}
  .target-progress.all-done{color:var(--done);}
  .target-slots{display:grid;grid-template-columns:repeat(3,1fr);gap:10px;align-items:start;}
  @media (max-width:680px){.target-slots{grid-template-columns:1fr;}}
  .target-slot{display:flex;align-items:flex-start;gap:8px;background:var(--surface);border:1px solid var(--line);border-radius:12px;padding:10px 11px;min-height:44px;}
  .target-slot.done{background:var(--done-soft);border-color:var(--done);}
  .target-slot.empty{border:1.5px dashed var(--line-strong);background:transparent;color:var(--accent-strong);font-weight:600;font-size:13px;justify-content:center;align-items:center;cursor:pointer;padding:14px 11px;}
  .target-slot.empty:hover{border-color:var(--accent);background:var(--surface);}
  .target-slot .task-check{margin-top:2px;}
  .target-slot-title{flex:1;min-width:0;font-weight:600;font-size:13.5px;line-height:1.35;overflow-wrap:break-word;word-break:break-word;white-space:normal;padding-top:2px;cursor:pointer;}
  .target-slot-title.done{text-decoration:line-through;color:var(--ink-faint);font-weight:500;}
  .target-slot .icon-btn{margin-top:1px;}

  /* ---------- Follow-up banner ---------- */
  .followup-banner{display:flex;align-items:center;gap:10px;background:var(--delegate-soft);border:1px solid var(--delegate);color:var(--ink);border-radius:12px;padding:12px 16px;margin-bottom:18px;font-size:13.5px;}
  .followup-banner strong{font-weight:700;}
  .followup-banner .dot{width:7px;height:7px;border-radius:50%;background:var(--delegate);flex:none;}
  .followup-banner button{margin-left:auto;background:var(--delegate);color:#fff;border:none;border-radius:8px;padding:7px 12px;font-size:12.5px;font-weight:600;cursor:pointer;white-space:nowrap;}

  /* ---------- Controls ---------- */
  /* View toggle (List/Tiles/Priority Level) and the category chips row are
     stacked, chips-row always on its own full-width line below the toggle -
     on a narrow/mobile screen the three view buttons alone can run close to
     the full viewport width, which used to leave the category chips
     squeezed into almost no space next to them. Per Bryan's request,
     2026-09-04. */
  .controls{display:flex;flex-direction:column;align-items:stretch;gap:10px;margin-bottom:18px;}
  .view-toggle{display:inline-flex;align-self:flex-start;max-width:100%;overflow-x:auto;background:var(--surface-sunken);border:1px solid var(--line);border-radius:10px;padding:3px;gap:2px;}
  .view-btn{flex:none;border:none;background:transparent;color:var(--ink-soft);font-size:13px;font-weight:600;padding:7px 13px;border-radius:8px;cursor:pointer;white-space:nowrap;}
  .view-btn.active{background:var(--surface);color:var(--ink);box-shadow:var(--shadow);}
  .chips-row{display:flex;align-items:center;gap:7px;width:100%;min-width:0;}
  .filter-chips{display:flex;gap:7px;overflow-x:auto;padding-bottom:2px;max-width:100%;flex:1;min-width:0;}
  .filter-chips::-webkit-scrollbar{height:5px;}
  .chip{flex:none;border:1px solid var(--line-strong);background:var(--surface);color:var(--ink-soft);font-size:12.5px;font-weight:600;padding:6px 12px;border-radius:999px;cursor:pointer;white-space:nowrap;}
  .chip.active{background:var(--ink);color:var(--ground);border-color:var(--ink);}
  /* Longer label ("Add/Change Category" vs. the old "+ Category") per
     Bryan's request, 2026-09-04 - overrides .chip's white-space:nowrap and
     drops the font size a notch so it wraps onto a couple of short lines
     instead of becoming one very wide pill next to the category chips. */
  .chip-add{flex:none;border-style:dashed;border-color:var(--line-strong);background:transparent;color:var(--ink-faint);white-space:normal;text-align:center;line-height:1.25;font-size:11px;max-width:88px;padding:6px 10px;}
  .chip-add:hover{border-color:var(--accent);color:var(--accent);}
  .cat-dot{display:inline-block;width:7px;height:7px;border-radius:50%;background:var(--cc);margin-right:5px;vertical-align:middle;flex:none;}
  /* touch-action:pan-x (not none) - lets a touch swipe over a chip scroll
     the horizontally-overflowing filter-chips row natively on mobile.
     Drag-to-reorder itself is mouse/pen-only (see makeSortable's
     pointerType guard) so it never fights that native scroll - previously
     touch-action:none blocked ALL touch gestures starting on a chip,
     including a plain swipe meant to reveal chips off the right edge,
     which is what Bryan reported on his phone, 2026-09-04. */
  .chip-cat{background:color-mix(in oklab, var(--cc) 15%, var(--surface));border-color:color-mix(in oklab, var(--cc) 55%, var(--line-strong));color:var(--ink);cursor:grab;touch-action:pan-x;user-select:none;transition:transform .12s ease, opacity .12s ease, background .12s ease, box-shadow .12s ease;}
  .chip-cat.active{background:color-mix(in oklab, var(--cc) 32%, var(--surface));border-color:var(--cc);color:var(--ink);}
  .chip-cat.dragging{cursor:grabbing;position:relative;z-index:5;box-shadow:var(--shadow);}
  /* A task row being dragged toward the category chips: the chip directly
     under the pointer grows, fills solid with its own category color, and
     gets a shadow, so it's obvious which category will receive the drop.
     Other chips stay fully visible (Bryan's 2026-09-04 correction - an
     earlier pass made them shrink/fade to near-nothing, which he did not
     want; only the hovered chip should stand out, nothing should
     disappear). */
  .chip-cat.drop-hover{transform:scale(1.22);background:var(--cc);border-color:var(--cc);color:#fff;box-shadow:0 6px 18px rgba(0,0,0,.35);outline:none;position:relative;z-index:6;}
  .chip-cat.drop-hover .cat-dot{background:#fff;}
  .chip-hint{font-size:11px;color:var(--ink-faint);margin:-10px 0 14px 2px;}
  .quad-key{display:flex;flex-wrap:wrap;align-items:center;gap:14px;margin:0 0 18px 2px;}
  .quad-key-label{font-family:var(--font-mono);font-size:11px;letter-spacing:.09em;text-transform:uppercase;color:var(--ink-faint);flex:none;}
  .quad-key-item{display:inline-flex;align-items:center;gap:6px;font-size:12.5px;color:var(--ink-soft);white-space:nowrap;}

  /* ---------- Reassigned person tiles ---------- */
  /* Only shown when filtered to Reassigned (the "Delegated" filter, renamed
     in the UI) - one tile per person tasks have been reassigned to, plus an
     "All" tile, across the top of that screen so Bryan can narrow straight
     to one person. Per Bryan's request, 2026-09-04. */
  .person-tiles{display:flex;flex-wrap:wrap;gap:8px;margin:0 0 16px;}
  .person-tile{display:inline-flex;align-items:center;gap:7px;border:1px solid var(--line-strong);background:var(--surface);color:var(--ink-soft);font-size:13px;font-weight:600;padding:9px 13px;border-radius:11px;cursor:pointer;white-space:nowrap;box-shadow:var(--shadow);}
  .person-tile:hover{border-color:var(--delegate);color:var(--ink);}
  .person-tile.active{background:var(--delegate);border-color:var(--delegate);color:#fff;}
  .person-tile-count{font-family:var(--font-mono);font-size:10.5px;font-weight:700;background:var(--surface-sunken);color:var(--ink-faint);padding:2px 7px;border-radius:999px;}
  .person-tile.active .person-tile-count{background:rgba(255,255,255,.28);color:#fff;}

  /* ---------- Task row ---------- */
  .task-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px;}
  .task-row{background:var(--surface);border:1px solid var(--line);border-radius:12px;padding:11px 13px;box-shadow:var(--shadow);}
  .task-row.compact{padding:8px 10px;box-shadow:none;}
  .task-row.dragging{cursor:grabbing;position:relative;z-index:6;box-shadow:0 4px 18px rgba(28,30,27,.18);opacity:.97;}
  .task-row.due-soon{background:var(--due-soon-bg);border-color:var(--due-soon-border);}
  .task-row.due-today{background:var(--due-today-bg);border-color:var(--due-today-border);}
  .task-row.overdue-row{background:var(--overdue-bg);border-color:var(--overdue-border);}
  /* Briefly highlights a task just added via quick-add's "Add" button, so
     Bryan can see where it landed - a pulsing accent-colored glow for 10
     seconds (see highlightNewTask()). Layers on top of any due-date row
     shading rather than replacing it. Per Bryan's request, 2026-09-04. */
  .task-row.task-row-highlight{outline:2.5px solid var(--accent);outline-offset:2px;box-shadow:0 0 0 5px var(--accent-soft), var(--shadow);animation:task-highlight-pulse 1.3s ease-in-out infinite;}
  @keyframes task-highlight-pulse{0%,100%{box-shadow:0 0 0 4px var(--accent-soft), var(--shadow);}50%{box-shadow:0 0 0 8px var(--accent-soft), var(--shadow);}}
  /* Cross-container native drag (task row -> Target Tasks / a category chip
     / a Priority Level box) - separate from the pointer-based same-list
     .dragging class above, which is used by the ⠿-handle reorder drag. */
  .task-row.row-dragging{opacity:.4;}
  .quad-box.drop-hover{outline:2px dashed var(--accent);outline-offset:-2px;}
  .target-slot.drop-hover{outline:2px solid var(--accent);outline-offset:1px;}
  .task-main{display:flex;align-items:flex-start;gap:10px;}
  .drag-handle{flex:none;cursor:grab;color:var(--ink-faint);font-size:13px;line-height:1;padding:4px 1px;margin-top:2px;touch-action:none;user-select:none;letter-spacing:-1px;}
  .drag-handle:hover{color:var(--ink-soft);}
  .task-row.compact .drag-handle{margin-top:1px;}
  .task-check{flex:none;width:20px;height:20px;border-radius:6px;border:1.5px solid var(--line-strong);background:var(--surface);cursor:pointer;display:flex;align-items:center;justify-content:center;margin-top:1px;color:transparent;}
  .task-check.done{background:var(--done);border-color:var(--done);color:#fff;}
  .q-chip{flex:none;font-family:var(--font-mono);font-size:9.5px;font-weight:700;letter-spacing:.02em;padding:2.5px 5px;border-radius:5px;line-height:1.2;margin-top:1px;white-space:nowrap;}
  .task-body{flex:1;min-width:0;}
  .task-title-row{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap;}
  .task-title{font-weight:600;font-size:14.5px;cursor:pointer;}
  .task-title.done{color:var(--ink-faint);text-decoration:line-through;font-weight:500;}
  .task-meta{display:flex;flex-wrap:wrap;gap:6px;margin-top:5px;align-items:center;}
  .pill{font-family:var(--font-mono);font-size:10.5px;letter-spacing:.03em;padding:2.5px 7px;border-radius:6px;font-weight:500;}
  .pill-cat{background:color-mix(in oklab, var(--cc, var(--ink-soft)) 20%, var(--surface-sunken));color:var(--ink);}
  .pill-recur{background:var(--accent-soft);color:var(--accent-strong);}
  .pill-delegate{background:var(--delegate-soft);color:var(--delegate);}
  .pill-due{background:var(--surface-sunken);color:var(--ink-soft);}
  /* Follow-up date pill uses the same green/yellow/red tiers as the
     due-date row shading below - green a day before the follow-up date,
     yellow the day of, red once it's past. Per Bryan's request,
     2026-09-04. */
  .pill-due.due-soon{background:var(--due-soon-bg);color:var(--due-soon-border);}
  .pill-due.due-today{background:var(--due-today-bg);color:var(--due-today-border);}
  .pill-due.overdue{background:var(--overdue-bg);color:var(--overdue-border);}
  .pill-target{background:var(--accent);color:var(--ground);font-weight:700;}
  .pill-sub{background:var(--surface-sunken);color:var(--ink-soft);}
  .task-due{flex:none;align-self:center;font-family:var(--font-mono);font-size:11px;font-weight:600;color:var(--ink-soft);white-space:nowrap;text-align:right;cursor:pointer;}
  .task-due.overdue{color:var(--urgent);}
  .task-due:hover{color:var(--accent-strong);text-decoration:underline;}
  /* Inline due-date calendar: clicking a task row's due-date badge opens a
     small calendar popup right there, so Bryan can change or clear a due
     date without opening the full task editor. Built as our own popup
     rather than relying on a native date input's browser-picker (that
     route turned out to open an editable field first, not a calendar, in
     the artifact preview's sandboxed frame - see 2026-09-04 notes) so the
     click always goes straight to a calendar, nothing else. */
  .due-cal-popup{position:fixed;z-index:90;background:var(--surface);border:1px solid var(--line-strong);border-radius:12px;box-shadow:var(--shadow);padding:10px 10px 8px;width:220px;}
  .due-cal-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:6px;}
  .due-cal-nav{border:none;background:transparent;color:var(--ink-soft);cursor:pointer;font-size:13px;padding:2px 7px;border-radius:6px;line-height:1.4;}
  .due-cal-nav:hover{background:var(--surface-sunken);color:var(--ink);}
  .due-cal-title{font-family:var(--font-mono);font-size:11.5px;font-weight:700;color:var(--ink);}
  .due-cal-grid{display:grid;grid-template-columns:repeat(7,1fr);gap:2px;}
  .due-cal-wd{font-family:var(--font-mono);font-size:9.5px;color:var(--ink-faint);text-align:center;padding-bottom:3px;}
  .due-cal-day{border:none;background:transparent;color:var(--ink);cursor:pointer;font-size:12px;padding:5px 0;border-radius:6px;text-align:center;}
  .due-cal-day:hover{background:var(--surface-sunken);}
  .due-cal-day.other-month{color:var(--ink-faint);opacity:.45;}
  .due-cal-day.today{outline:1.5px solid var(--accent);outline-offset:-1.5px;}
  .due-cal-day.selected{background:var(--accent);color:var(--ground);font-weight:700;}
  .due-cal-foot{margin-top:6px;padding-top:6px;border-top:1px solid var(--line);text-align:center;}
  .due-cal-clear{border:none;background:transparent;color:var(--urgent);cursor:pointer;font-size:11.5px;font-family:var(--font-mono);padding:4px;}
  .due-cal-clear:hover{text-decoration:underline;}
  .row-actions{display:flex;gap:4px;flex:none;}
  .icon-btn{border:none;background:transparent;color:var(--ink-faint);cursor:pointer;padding:4px;border-radius:6px;font-size:14px;line-height:1;}
  .icon-btn:hover{color:var(--ink);background:var(--surface-sunken);}
  .subtask-panel{margin:9px 0 2px 30px;padding:9px 0 2px;border-top:1px dashed var(--line);}
  .subtask-item{display:flex;align-items:center;gap:8px;font-size:13px;padding:3px 0;}
  .subtask-item input[type="checkbox"]{accent-color:var(--accent);width:15px;height:15px;}
  .subtask-item label{flex:1;}
  .subtask-item.done label{color:var(--ink-faint);text-decoration:line-through;}
  /* Drag handle + remove button for the inline subtask checklist shown by
     expanding a task row's "☑ N/M" pill - same visual language as the
     editor's own .subtask-drag-handle, and the same .icon-btn look as the
     row-level delete button, just scoped to .subtask-item. Reorders are
     confined to the one task's own .subtask-panel (see
     wireInlineSubtaskDrag). Per Bryan's request, 2026-09-11.*/
  .subtask-item .subtask-drag-handle{font-size:13px;}
  .subtask-item .subtask-remove{border:none;background:transparent;color:var(--ink-faint);cursor:pointer;padding:2px 4px;border-radius:6px;font-size:12px;line-height:1;flex:none;}
  .subtask-item .subtask-remove:hover{color:var(--urgent);background:var(--surface-sunken);}
  .subtask-item.dragging{position:relative;z-index:6;background:var(--surface-sunken);border-radius:8px;box-shadow:0 4px 14px rgba(28,30,27,.18);}
  /* Per-task "Completed steps" / "Deleted steps" archives inside an
     expanded subtask panel - checked-off and deleted steps drop out of the
     working checklist into these collapsed sections, same idea as the
     page-level Show completed / Show deleted lists. Per Bryan's request,
     2026-09-22. */
  .subtask-archive-list .subtask-edit-row{margin:3px 0;}
  .subtask-archive-list .subtask-edit-row input[type="text"]{color:var(--ink-faint);text-decoration:line-through;}
  .subtask-all-done{font-size:12.5px;color:var(--done);padding:3px 0;}
  .subtask-archive{margin-top:6px;}
  .subtask-archive-toggle{background:none;border:none;color:var(--ink-faint);font-size:11.5px;font-weight:600;cursor:pointer;padding:3px 0;font-family:var(--font-mono);letter-spacing:.02em;}
  .subtask-archive-toggle:hover{color:var(--accent);}
  .subtask-archive-list{margin:2px 0 4px;padding:4px 8px;background:var(--surface-sunken);border-radius:8px;}
  .subtask-archive-list .subtask-item{color:var(--ink-faint);}
  .subtask-trash-item .st-title{flex:1;}
  .subtask-trash-item button{border:none;background:none;color:var(--ink-soft);font-size:11px;font-weight:600;cursor:pointer;white-space:nowrap;padding:2px 4px;}
  .subtask-trash-item button:hover{color:var(--accent);}
  .subtask-trash-item button.st-purge:hover{color:var(--urgent);}
  .empty-state{color:var(--ink-faint);font-size:13.5px;padding:26px 4px;text-align:center;}

  /* ---------- Tiles view ---------- */
  .tile-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(270px,1fr));gap:16px;align-items:start;}
  .tile-card{background:var(--surface);border:1px solid var(--line);border-radius:14px;box-shadow:var(--shadow);overflow:hidden;}
  .tile-head{display:flex;align-items:center;gap:8px;padding:13px 15px;border-bottom:1px solid var(--line);}
  .tile-head .cdot{width:10px;height:10px;border-radius:3px;flex:none;}
  .tile-head h3{font-family:var(--font-display);font-weight:600;font-size:16px;margin:0;flex:1;}
  .tile-count{font-family:var(--font-mono);font-size:11px;color:var(--ink-faint);}
  .tile-body{padding:10px;display:flex;flex-direction:column;gap:7px;}

  /* ---------- Quadrant view ---------- */
  .quad-grid{display:grid;grid-template-columns:1fr 1fr;gap:14px;}
  @media (max-width:700px){.quad-grid{grid-template-columns:1fr;}}
  .quad-box{border-radius:14px;border:1px solid var(--line);overflow:hidden;background:var(--surface);}
  .quad-head{padding:12px 15px;display:flex;align-items:baseline;justify-content:space-between;gap:10px;}
  .quad-head h3{font-family:var(--font-display);font-weight:600;font-size:15.5px;margin:0;}
  .quad-head p{margin:2px 0 0;font-size:11.5px;color:var(--ink-soft);}
  .quad-count{font-family:var(--font-mono);font-size:11px;}
  .quad-body{padding:8px 10px 12px;max-height:340px;overflow-y:auto;display:flex;flex-direction:column;gap:6px;}

  /* ---------- Completed ---------- */
  .completed-section{margin-top:26px;border-top:1px solid var(--line);padding-top:14px;}
  #completedList{list-style:none;margin:10px 0 0;padding:0;display:flex;flex-direction:column;gap:6px;}
  .completed-row{display:flex;align-items:center;gap:8px;font-size:13px;color:var(--ink-faint);background:var(--surface-sunken);border-radius:9px;padding:8px 10px;}
  .completed-row .ct{flex:1;text-decoration:line-through;}
  .completed-row button{border:none;background:none;color:var(--ink-soft);font-size:11.5px;font-weight:600;cursor:pointer;white-space:nowrap;}
  .completed-row button:hover{color:var(--accent);}
  /* Deleted-items ("Trash") rows reuse .completed-row's layout, but the
     title isn't struck through (it wasn't completed, just deleted), and
     "Delete forever" hovers red as a mild warning rather than the usual
     green. Per Bryan's request, 2026-09-11. */
  .trash-row .ct{text-decoration:none;}
  .trash-context{color:var(--ink-faint);font-style:italic;}
  .trash-when{font-family:var(--font-mono);font-size:10.5px;color:var(--ink-faint);margin-left:6px;}
  .trash-row .trash-purge-btn:hover{color:var(--urgent);}

  /* ---------- Overlay / editor ---------- */
  .overlay{position:fixed;inset:0;background:rgba(20,22,17,.44);display:flex;align-items:flex-start;justify-content:center;padding:5vh 16px;overflow-y:auto;z-index:20;}
  .editor-card{background:var(--surface);border-radius:16px;max-width:520px;width:100%;padding:22px 22px 20px;box-shadow:var(--shadow);}
  .editor-card h2{font-family:var(--font-display);font-weight:600;font-size:19px;margin:0 0 16px;}
  .field{margin-bottom:14px;}
  .field label.flabel{display:block;font-size:11.5px;font-weight:600;letter-spacing:.03em;text-transform:uppercase;color:var(--ink-soft);margin-bottom:6px;font-family:var(--font-mono);}
  .field input[type="text"],.field input[type="date"],.field input[type="number"],.field select,.field textarea{
    width:100%;border:1px solid var(--line-strong);background:var(--ground);color:var(--ink);border-radius:9px;padding:9px 11px;font-size:14px;font-family:var(--font-body);
  }
  .field textarea{resize:vertical;min-height:56px;}
  .row2{display:flex;gap:10px;}
  .row2>*{flex:1;}
  .quad-preview{margin-top:8px;font-size:12.5px;color:var(--ink-soft);text-align:right;}
  .quad-preview b{color:var(--ink);}
  .radiogroup{display:flex;gap:8px;}
  .radio-btn{flex:1;border:1.5px solid var(--line-strong);background:var(--surface);color:var(--ink-soft);border-radius:9px;padding:9px 8px;font-size:13px;font-weight:600;cursor:pointer;text-align:center;}
  .radio-btn[data-on="true"]{border-color:var(--ink);background:var(--ink);color:var(--ground);}
  .weekday-row{display:flex;gap:5px;margin-top:8px;}
  .wd-btn{flex:1;border:1.5px solid var(--line-strong);background:var(--surface);color:var(--ink-soft);border-radius:7px;padding:7px 0;font-size:12px;font-weight:700;cursor:pointer;}
  .wd-btn[data-on="true"]{background:var(--accent);border-color:var(--accent);color:#fff;}
  .checkline{display:flex;align-items:center;gap:8px;font-size:13.5px;font-weight:600;cursor:pointer;}
  .checkline input{width:16px;height:16px;accent-color:var(--delegate);}
  .subtask-edit-row{display:flex;align-items:center;gap:7px;margin-bottom:5px;}
  .subtask-edit-row input[type="text"]{flex:1;}
  .subtask-edit-row button{border:none;background:none;color:var(--ink-faint);cursor:pointer;font-size:14px;}
  /* Drag handle for manually reordering subtasks within the task editor -
     same visual language and vertical pointer-drag pattern as the task
     row's ⠿ handle (wireTaskDrag), just scoped to .subtask-edit-row inside
     #subtaskEditList. Per Bryan's request, 2026-09-11. */
  .subtask-drag-handle{flex:none;cursor:grab;color:var(--ink-faint);font-size:12px;line-height:1;padding:2px 1px;touch-action:none;user-select:none;letter-spacing:-1px;}
  .subtask-drag-handle:hover{color:var(--ink-soft);}
  .subtask-edit-row.dragging{position:relative;z-index:6;background:var(--surface-sunken);border-radius:8px;box-shadow:0 4px 14px rgba(28,30,27,.18);}
  .add-subtask-row{display:flex;gap:7px;margin-top:4px;}
  .add-subtask-row input{flex:1;}
  .editor-actions{display:flex;justify-content:space-between;align-items:center;margin-top:18px;gap:10px;}
  .editor-actions .right{display:flex;gap:8px;}
  .danger-btn{background:none;border:1px solid var(--line-strong);color:var(--ink-faint);border-radius:9px;padding:9px 13px;font-size:13px;font-weight:600;cursor:pointer;}
  .danger-btn.confirming{border-color:var(--urgent);color:var(--urgent);background:var(--urgent-soft);}
  [hidden]{display:none !important;}
  .example-tag{background:var(--surface-sunken);color:var(--ink-faint);font-family:var(--font-mono);font-size:9.5px;letter-spacing:.05em;text-transform:uppercase;padding:2px 6px;border-radius:5px;}
  .seed-banner{display:flex;align-items:center;gap:10px;justify-content:space-between;background:var(--surface-sunken);border:1px dashed var(--line-strong);border-radius:12px;padding:10px 14px;margin-bottom:16px;font-size:13px;color:var(--ink-soft);}
  .seed-banner button{border:1px solid var(--line-strong);background:var(--surface);color:var(--ink);border-radius:8px;padding:7px 11px;font-size:12.5px;font-weight:600;cursor:pointer;white-space:nowrap;}
  .picker-list{max-height:280px;overflow-y:auto;display:flex;flex-direction:column;gap:6px;margin-top:8px;}
  .picker-item{display:flex;align-items:center;gap:8px;padding:9px 10px;border:1px solid var(--line);border-radius:9px;cursor:pointer;background:var(--surface);text-align:left;width:100%;font-size:13.5px;color:var(--ink);}
  .picker-item:hover{border-color:var(--accent);background:var(--accent-soft);}
  .picker-item .pill{flex:none;}
  .picker-item .ptitle{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
  .category-color-list{display:flex;flex-direction:column;gap:12px;max-height:300px;overflow-y:auto;margin-top:8px;}
  .cat-color-row{display:flex;align-items:center;justify-content:space-between;gap:12px;}
  .cat-color-name{font-size:13.5px;font-weight:600;flex:none;min-width:90px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
  .swatch-row{display:flex;gap:6px;flex-wrap:wrap;justify-content:flex-end;}
  .swatch{width:22px;height:22px;border-radius:50%;border:2px solid transparent;cursor:pointer;padding:0;flex:none;}
  .swatch[data-selected="true"]{border-color:var(--ink);}
  .cat-row-right{display:flex;align-items:center;gap:8px;flex:none;}
  .cat-delete-btn{flex:none;font-size:13px;}
  .cat-delete-btn[data-confirm="true"]{color:var(--urgent);background:var(--urgent-soft);}
  .cat-delete-btn[disabled]{opacity:.35;cursor:not-allowed;}
  #categoryColorList .cat-name-input{border:none;background:transparent;font:inherit;font-weight:600;font-size:13.5px;color:var(--ink);padding:3px 5px;border-radius:6px;min-width:70px;flex:none;width:100px;}
  #categoryColorList .cat-name-input:hover{background:var(--surface-sunken);}
  #categoryColorList .cat-name-input:focus{background:var(--surface-sunken);outline:none;box-shadow:0 0 0 1.5px var(--accent);}

  /* ---------- Import ---------- */
  #importText{width:100%;border:1px solid var(--line-strong);background:var(--ground);color:var(--ink);border-radius:9px;padding:10px 12px;font-size:13.5px;font-family:var(--font-body);resize:vertical;min-height:120px;}
  .qpick-row{display:flex;gap:5px;}
  .qpick-btn{flex:1;border:1.5px solid var(--line-strong);background:var(--surface);color:var(--ink-faint);border-radius:8px;padding:8px 4px;font-size:11px;font-weight:700;cursor:pointer;text-align:center;font-family:var(--font-mono);}
  .qpick-btn[data-on="true"]{border-color:var(--qc);background:var(--qc-soft);color:var(--qc);}
  .qpick-row.small .qpick-btn{padding:6px 3px;font-size:10px;border-radius:6px;}
  .import-rows{max-height:380px;overflow-y:auto;display:flex;flex-direction:column;gap:8px;margin-top:6px;}
  .import-row{display:flex;align-items:center;gap:7px;}
  .import-row-title{flex:1;min-width:0;border:1px solid var(--line-strong);background:var(--ground);color:var(--ink);border-radius:8px;padding:8px 10px;font-size:13px;font-family:var(--font-body);}
  .import-row .qpick-row{flex:none;width:132px;}
  .import-row-cat{flex:none;width:118px;border:1px solid var(--line-strong);background:var(--ground);color:var(--ink);border-radius:8px;padding:8px 6px;font-size:12px;font-family:var(--font-body);}

  /* ---------- Carryover (yesterday's Top 3) prompt ---------- */
  .carryover-list{display:flex;flex-direction:column;gap:8px;max-height:400px;overflow-y:auto;}
  .carryover-row{display:flex;align-items:center;gap:8px;padding:10px 11px;border:1px solid var(--line);border-radius:10px;background:var(--surface);flex-wrap:wrap;}
  .carryover-title{flex:1;min-width:120px;font-weight:600;font-size:13.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
  .carryover-actions{display:flex;gap:6px;flex:none;margin-left:auto;}
  .carryover-actions button{border:1px solid var(--line-strong);background:var(--surface);color:var(--ink-soft);border-radius:8px;padding:6px 9px;font-size:11.5px;font-weight:600;cursor:pointer;white-space:nowrap;font-family:var(--font-body);}
  .carryover-actions button:hover{border-color:var(--accent);color:var(--accent-strong);}
  .carryover-actions button[disabled]{opacity:.4;cursor:not-allowed;}
  .carryover-actions button[disabled]:hover{border-color:var(--line-strong);color:var(--ink-soft);}
  .carryover-actions .done-btn{border-color:var(--done);color:var(--done);}
  .carryover-actions .done-btn:hover{background:var(--done-soft);border-color:var(--done);color:var(--done);}

  /* ---------- Photo attachments ---------- */
  .attach-strip{display:flex;flex-wrap:wrap;gap:4px;margin-top:6px;}
  .attach-thumb-wrap{position:relative;flex:none;line-height:0;}
  .attach-thumb{width:30px;height:30px;border-radius:7px;object-fit:cover;border:1px solid var(--line);cursor:pointer;background:var(--surface-sunken);display:block;}
  .attach-thumb-more{width:30px;height:30px;border-radius:7px;background:var(--surface-sunken);color:var(--ink-soft);font-size:10.5px;font-weight:700;display:flex;align-items:center;justify-content:center;border:1px solid var(--line);cursor:pointer;font-family:var(--font-mono);}
  .attach-pdf-tag{position:absolute;bottom:-2px;right:-2px;background:var(--ink);color:var(--ground);font-family:var(--font-mono);font-size:6.5px;font-weight:700;padding:1px 3px;border-radius:4px;line-height:1.2;pointer-events:none;}
  /* File drop straight onto a task row (Finder/Photos/Dropbox etc. dragged in)
     - distinguished from the app's own row-reorder/cross-container drags by
     checking dataTransfer.types for "Files", so the two systems never
     collide. Per Bryan's request, 2026-09-03. */
  .task-row.file-drop-hover{outline:2px dashed var(--accent);outline-offset:-2px;background:var(--accent-soft);}

  .photo-dropzone{border:1.5px dashed var(--line-strong);border-radius:12px;padding:14px 12px;text-align:center;color:var(--ink-faint);font-size:12.5px;cursor:pointer;margin-bottom:10px;}
  .photo-dropzone u{text-decoration:underline;color:var(--ink-soft);}
  .photo-dropzone.drag-over{border-color:var(--accent);background:var(--accent-soft);color:var(--accent-strong);}
  .photo-status{font-size:11.5px;color:var(--ink-faint);margin:-4px 0 10px;}
  .photo-status.err{color:var(--urgent);}

  /* Floating confirmation for file drops handled outside the task editor
     (a photo dropped straight on a task row) - the editor's own
     #photoStatus line is hidden whenever the editor isn't open, so
     without this a row-drop success or failure had no visible feedback
     at all. Per code-review request, 2026-09-03. */
  .global-toast{position:fixed;left:50%;bottom:28px;transform:translateX(-50%) translateY(8px);background:var(--ink);color:var(--ground);padding:10px 16px;border-radius:10px;font-size:12.5px;font-weight:600;box-shadow:0 8px 24px rgba(0,0,0,.3);z-index:80;max-width:min(90vw,420px);text-align:center;opacity:0;pointer-events:none;transition:opacity .18s ease,transform .18s ease;}
  .global-toast.show{opacity:1;transform:translateX(-50%) translateY(0);}
  .global-toast.err{background:var(--urgent);color:#fff;}
  /* #undoToast is a second, independent toast (see markup) just for the
     one-tap "Undo" affordance after deleting a task/subtask - laid out as
     a row (message + button) rather than centered text, and its button
     only becomes clickable while it's actually shown (pointer-events
     follow .show, same as the toast itself). Per Bryan's request,
     2026-09-11. */
  .undo-toast{display:flex;align-items:center;gap:12px;padding:9px 10px 9px 16px;}
  .undo-toast.show{pointer-events:auto;}
  .undo-toast button{flex:none;border:none;background:rgba(255,255,255,.16);color:var(--ground);font-size:12px;font-weight:700;padding:6px 12px;border-radius:7px;cursor:pointer;}
  .undo-toast button:hover{background:rgba(255,255,255,.28);}
  .photo-grid{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:4px;}
  .photo-tile{position:relative;width:60px;height:60px;border-radius:10px;overflow:hidden;border:1px solid var(--line);background:var(--surface-sunken);flex:none;}
  .photo-tile img{width:100%;height:100%;object-fit:cover;display:block;cursor:pointer;}
  .photo-tile.uploading{display:flex;align-items:center;justify-content:center;font-size:8.5px;color:var(--ink-faint);text-align:center;padding:4px;}
  .photo-remove{position:absolute;top:2px;right:2px;width:17px;height:17px;border-radius:50%;background:rgba(20,22,17,.68);color:#fff;border:none;font-size:10.5px;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center;padding:0;}
  .photo-pdf-tag{position:absolute;bottom:2px;left:2px;background:var(--ink);color:var(--ground);font-family:var(--font-mono);font-size:7px;font-weight:700;padding:1px 4px;border-radius:4px;pointer-events:none;}

  /* ---------- Lightbox (view an attached photo) ---------- */
  #lightboxOverlay{align-items:center;background:rgba(10,11,9,.85);z-index:40;}
  .lightbox-img{max-width:100%;max-height:80vh;border-radius:8px;box-shadow:0 10px 40px rgba(0,0,0,.5);background:#111;display:block;}
  .lightbox-close,.lightbox-nav{position:fixed;background:rgba(255,255,255,.14);border:none;color:#fff;border-radius:50%;cursor:pointer;display:flex;align-items:center;justify-content:center;}
  .lightbox-close{top:20px;right:20px;width:36px;height:36px;font-size:15px;}
  .lightbox-nav{top:50%;transform:translateY(-50%);width:44px;height:44px;font-size:19px;}
  .lightbox-nav.prev{left:20px;}
  .lightbox-nav.next{right:20px;}
  .lightbox-close:hover,.lightbox-nav:hover{background:rgba(255,255,255,.26);}
  .lightbox-caption{position:fixed;bottom:22px;left:50%;transform:translateX(-50%);color:#fff;font-size:12.5px;background:rgba(0,0,0,.45);padding:6px 14px;border-radius:999px;max-width:80vw;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
