﻿/* TaskBite design system - originally ported from design/taskbite-admin.html.
   That mockup is a reference snapshot, not a source: it is never served or
   built, and does not need to be kept in sync with this file.
   Tokens: Space Grotesk (display), Inter (body), IBM Plex Mono (mono). Amber accent. */

/* ============================================================================
   THEME TOKENS - THE ONE PLACE TO CHANGE COLOURS
   ----------------------------------------------------------------------------
   Every colour in this stylesheet resolves to a token below. To retheme the
   app, or to add a third theme, you only ever touch this block: copy the whole
   :root body, paste it under a new selector, and change the values.

     :root                      the light theme (also the fallback)
     :root[data-theme="dark"]   the dark theme

   To add your own, e.g. a high-contrast one:

     :root[data-theme="contrast"]{ ...same token names, your values... }

   then add its name to THEMES in public/js/theme.js and it joins the switcher.
   Nothing outside this block needs to know a theme exists.

   The `data-theme` attribute is written onto <html> by theme.js before paint.
   ==========================================================================*/

  :root{
    color-scheme:light;

    /* -- Surfaces ---------------------------------------------------------
       --page-bg is the canvas behind the cards. --bg is the subtle fill used
       for hovers and inset areas inside panels. --sunken is deeper still
       (reply threads, wells). */
    --page-bg:#F6F7F9;
    --bg:#F4F5F7;
    --sunken:#EFEDE8;
    --panel:#FFFFFF;

    /* -- Lines ------------------------------------------------------------
       --line-strong is the hover/focus border; it must stay visible against
       --panel in every theme. */
    --line:#E7E9EC;
    --line-soft:#F0F1F3;
    --line-strong:#C9C9C2;
    /* Borders on small controls (checkboxes, radios) which sit on --panel. */
    --control-line:#C9CDD4;

    /* -- Type -------------------------------------------------------------
       --heading is the page/card title colour. It is the token that carries
       most of the dark theme's character (it goes lavender there), so it is
       deliberately separate from --ink. */
    --ink:#101317;
    --heading:#101317;
    --text:#3A404A;
    /* Every task title, in every list. One colour: read or unread, open or
       completed, dashboard or project page. Only the weight varies. */
    --task-ink:#323232;
    --muted:#6E7581;
    --faint:#A6ADB8;

    /* -- Primary action ---------------------------------------------------
       "+ New task" and every .btn.dark. Black in light, coral in dark. */
    --accent:#101317;
    --accent-hover:#26292F;
    --accent-fg:#FFFFFF;

    /* -- Inverse chrome ---------------------------------------------------
       Components that are deliberately a dark slab on a light page: the toast,
       the bulk-action bar, code blocks. These must NOT follow --ink, or they
       invert into white slabs in the dark theme. */
    --inverse-bg:#101317;
    --inverse-bg-soft:#20242B;
    --inverse-fg:#FFFFFF;
    --inverse-fg-dim:#C4CBD6;
    --inverse-line:#333A44;

    /* -- Accent ramps -----------------------------------------------------
       Each ramp is tint (background) / base / deep (text on tint) / line
       (border on tint). */
    --amber:#F59E2D;
    --amber-deep:#C97C15;
    --amber-tint:#FEF3E0;
    --amber-line:#F5DCB0;
    --amber-hover:#FCE9CC;
    --green:#2F9E5C;
    --green-tint:#E2F4E9;
    --green-deep:#237347;
    --green-line:#BFE6CE;
    --blue:#4E8DF5;
    --blue-tint:#E8F0FE;
    --blue-deep:#2D62C4;
    --blue-line:#C7D7F0;
    --pink:#F06292;
    --pink-tint:#FCE7EF;
    --red:#DE5151;
    --red-tint:#FBEAEA;
    --red-deep:#C6455B;
    --violet:#8B5CF6;
    --violet-tint:#F1EAFE;
    --rainbow:linear-gradient(90deg,#F59E2D,#F06292,#8B5CF6,#4E8DF5,#2F9E5C);

    /* -- Task rows --------------------------------------------------------
       Rows are discrete capsules, not divider-separated lines. --row-radius
       999px gives the pill; drop it to 12px for a card look. */
    --row-bg:#FFFFFF;
    --row-bg-hover:#FAFAFB;
    --row-line:#E7E9EC;
    --row-radius:999px;
    --row-gap:8px;
    /* The ring on a row that wants attention (unread / flagged). */
    --row-flag-line:#F59E2D;

    /* -- Highlighted widget box ------------------------------------------
       Change ONLY --widget-tint to recolour the box; the sheen sits on top of
       whatever you pick and is theme-independent. Alternatives from the
       design: #F3A6FF (orchid), #DFF8FF (ice), #CAF4CC (mint). */
    --widget-tint:#CAF4CC;
    --widget-sheen:linear-gradient(164deg, #ffffff0d 12%, #f3a6ff14 34%, #f3a6ff1f 38%, #00c4ff26 60%, #35c83826 89%);
    --widget-ink:#0F2B18;
    --widget-muted:#3F6B4C;
    --widget-row-bg:#FFFFFF;
    --widget-row-line:#B7E6BA;
    /* Rows and buttons sitting ON the tint need their own ink - the page's
       --task-ink follows the theme and would go light-on-light here. */
    --widget-row-ink:#323232;
    --widget-btn-bg:#FFFFFF;
    --widget-btn-fg:#101317;

    /* -- Stat cards -------------------------------------------------------
       The headline numbers read as a quieter layer than the widgets below
       them, so they get a translucent fill rather than the solid --panel: the
       page tints through. Alpha, not a flat colour, so one value works on any
       --page-bg you switch to. */
    --stat-bg:rgba(255,255,255,.55);
    --stat-line:rgba(16,19,23,.06);

    /* -- Shape ------------------------------------------------------------
       Geometry, not colour, so the dark block does not restate these. */
    --btn-radius:32px;
    --side-radius:18px;
    --side-inset:14px;
    --side-width:236px;

    /* -- Misc controls ----------------------------------------------------*/
    /* Stopwatch. Amber here; violet and pink in the dark theme. */
    --timer-bg:var(--amber-tint);
    --timer-line:var(--amber);
    --timer-ink:var(--amber-deep);
    --timer-clock:var(--ink);

    --switch-off:#D7DAD2;
    --star-on:#F59E2D;
    --scrim:rgba(16,19,23,.30);
    /* Frosted glass behind an open popover. Tinted toward the page rather than
       darkened, so what is behind it stays legible as context. */
    --scrim-glass:rgba(255,255,255,.55);
    --scrim-blur:2px;

    /* -- Elevation --------------------------------------------------------*/
    --shadow-card:0 1px 2px rgba(16,19,23,.04);
    --shadow-pop:0 1px 2px rgba(16,19,23,.05), 0 16px 40px -20px rgba(16,19,23,.18);
    --shadow-menu:0 12px 32px -12px rgba(16,19,23,.22);
    --shadow-fab:0 8px 22px rgba(16,19,23,.16);
    --shadow-fab-hover:0 12px 28px rgba(16,19,23,.20);
    --shadow-focus:0 4px 16px -8px rgba(16,19,23,.14);
  }

  /* ==========================================================================
     DARK - same token names, dark values. Nothing else in the file changes.
     ========================================================================*/
  :root[data-theme="dark"]{
    color-scheme:dark;

    --page-bg:#2A2438;
    --bg:#332C45;
    --sunken:#241F30;
    --panel:#312A43;

    --line:#3E3652;
    --line-soft:#39314C;
    --line-strong:#584D72;
    --control-line:#584D72;

    --ink:#F2EEF9;
    --heading:#B9A5F0;
    --text:#CFC8DE;
    --task-ink:#EDE9F5;
    --muted:#9C94B0;
    --faint:#7E7694;

    --accent:#F0647B;
    --accent-hover:#F47B8F;
    --accent-fg:#FFFFFF;

    /* In dark the "inverse" slabs stay dark - they just deepen so they still
       read as a distinct layer above the page. */
    --inverse-bg:#1B1626;
    --inverse-bg-soft:#241F30;
    --inverse-fg:#F2EEF9;
    --inverse-fg-dim:#A79FBC;
    --inverse-line:#3E3652;

    --amber:#F5A93F;
    --amber-deep:#F0DCB4;
    --amber-tint:#4A3A22;
    --amber-line:#6B5330;
    --amber-hover:#5A4529;
    --green:#4CB97A;
    --green-tint:#1F3D2C;
    --green-deep:#9FE0BB;
    --green-line:#2E5A42;
    --blue:#6FA3F7;
    --blue-tint:#23304F;
    --blue-deep:#A8C8FB;
    --blue-line:#354870;
    --pink:#F387AE;
    --pink-tint:#432433;
    --red:#F0647B;
    --red-tint:#43222B;
    --red-deep:#F79FB0;
    --violet:#A78BFA;
    --violet-tint:#332A52;

    --row-bg:#3A3350;
    --row-bg-hover:#443C5C;
    --row-line:#3A3350;
    --row-flag-line:#F0526B;

    /* The Priorities box in dark: a violet slab. One value to change. */
    --widget-tint:#8C7BC6;
    --widget-ink:#FFFFFF;
    /* Bright enough to clear 3:1 against the tint as well as against the
       deeper row fill - it is used on both. */
    --widget-muted:#EFEAFB;
    /* Rows sit deeper than the tint so white titles carry. #7E68BC against
       white is 4.6:1 - the row had to darken as the ink went white, or the
       pair would have landed at 3.6:1 and read softer, not sharper. */
    --widget-row-bg:#7E68BC;
    --widget-row-line:#7E68BC;
    --widget-row-ink:#FFFFFF;
    --widget-btn-bg:#FFFFFF;
    --widget-btn-fg:#1B1626;

    /* Lightening the page rather than a flat fill, so the stat row stays a
       layer above the canvas without competing with the widgets. */
    --stat-bg:rgb(126 135 179 / 3%);
    --stat-line:rgba(255,255,255,.07);

    --timer-bg:#463A66;
    --timer-line:#6D5CA0;
    --timer-ink:#F2A0B6;
    --timer-clock:#EFEAFB;

    --switch-off:#4A4160;
    --star-on:#F5A93F;
    --scrim:rgba(10,7,16,.55);
    /* Same idea inverted: a white frost over a dark page would read as fog. */
    --scrim-glass:rgba(20,15,30,.55);
    --scrim-blur:2px;

    --shadow-card:0 1px 2px rgba(0,0,0,.30);
    --shadow-pop:0 1px 2px rgba(0,0,0,.35), 0 16px 40px -20px rgba(0,0,0,.70);
    --shadow-menu:0 12px 32px -12px rgba(0,0,0,.70);
    --shadow-fab:0 8px 22px rgba(0,0,0,.45);
    --shadow-fab-hover:0 12px 28px rgba(0,0,0,.55);
    --shadow-focus:0 4px 16px -8px rgba(0,0,0,.50);
  }
  *{ box-sizing:border-box; }
  body{
    margin:0; background:var(--page-bg); color:var(--text);
    font-family:'Inter',sans-serif; font-size:14px; line-height:1.5;
    -webkit-font-smoothing:antialiased;
  }
  h1,h2,h3{ font-family:'Space Grotesk',sans-serif; color:var(--heading); margin:0; letter-spacing:-.01em; }
  a{ color:inherit; text-decoration:none; }
  button{ font-family:'Inter',sans-serif; cursor:pointer; }
  .mono{ font-family:'IBM Plex Mono',monospace; }
  ::selection{ background:var(--amber); color:#fff; }
  a:focus-visible,button:focus-visible,input:focus-visible,textarea:focus-visible{
    outline:2px solid var(--blue); outline-offset:2px; border-radius:4px;
  }

  /* ============ APP SHELL ============ */
  /* Room for the sidebar plus the gap it now floats in, on both sides of it. */
  .app{ min-height:100vh; padding-left:calc(var(--side-width) + var(--side-inset) * 2); }

  /* ---------- SIDEBAR (fixed: always in view, out of flow -> no empty space) ---------- */
  /* The sidebar is a floating panel, not a wall: inset from the top and left
     so the page shows around it, with the rainbow strip rounding into its top
     corners. overflow-y:auto is what clips the strip to the radius. */
  .side{
    position:fixed; top:var(--side-inset); left:var(--side-inset);
    width:var(--side-width); height:calc(100vh - var(--side-inset) * 2); z-index:40;
    overflow-y:auto; background:var(--panel);
    border:1px solid var(--line); border-radius:var(--side-radius);
    box-shadow:var(--shadow-pop);
    display:flex; flex-direction:column; padding:0 12px 16px;
  }
  .side::before{ content:""; display:block; height:3px; background:var(--rainbow); margin:0 -12px 0; flex:none; }
  .side-logo{
    display:flex; align-items:center; gap:9px; padding:18px 8px 20px;
    font-family:'Space Grotesk',sans-serif; font-weight:700; font-size:17px; color:var(--ink);
  }
  .side-logo svg{ width:26px; height:26px; flex:none; }
  .side .sect{
    font-family:'IBM Plex Mono',monospace; font-size:10px; letter-spacing:.08em;
    color:var(--faint); padding:16px 10px 6px;
  }
  .snav{ display:flex; flex-direction:column; gap:1px; }
  /* Plain nav links only - Dashboard, Activity. Deliberately NOT the client
     tree: `.snav a` is (0,1,1) and every component in the tree is a single
     class at (0,1,0), so an unscoped rule here silently outranks .client-row,
     .proj-link and .proj-add on every property they share, and their sizes
     never take. Excluding .clients-nav makes that a structural impossibility
     rather than a specificity race nobody remembers to check.

     The tree components are self-contained (display, padding, radius, border,
     colour and their own hover/active states), so they need nothing from here. */
  .snav:not(.clients-nav) a{
    display:flex; align-items:center; gap:10px;
    font-size:13.5px; font-weight:500; color:var(--text);
    padding:8px 10px; border-radius:8px; border:1px solid transparent;
  }
  .snav:not(.clients-nav) a:hover{ background:var(--bg); }
  .snav:not(.clients-nav) a.active{ background:var(--bg); border-color:var(--line); color:var(--ink); font-weight:600; }
  .snav .ic{ width:16px; text-align:center; opacity:.75; }
  .snav .pd{ width:8px; height:8px; border-radius:50%; flex:none; }
  .snav .count{
    margin-left:auto; font-family:'IBM Plex Mono',monospace; font-size:10.5px;
    color:var(--muted); background:var(--bg); border:1px solid var(--line);
    border-radius:999px; padding:1px 7px;
  }
  .snav .count.hot{ background:var(--amber-tint); border-color:var(--amber-line); color:var(--amber-deep); font-weight:600; }

  /* clients with nested projects */
  .clients-nav{ gap:2px; }
  /* The client is a grouping label, the project is the thing you actually open.
     So the client line steps down in size and weight, and the project steps up
     - the tree reads project-first, which is how it is used. */
  .client-row{
    display:flex; align-items:center; gap:9px; width:100%;
    border:1px solid transparent; background:none; cursor:pointer;
    font-size:11.5px; font-weight:600; color:var(--muted);
    text-transform:uppercase; letter-spacing:.06em;
    padding:7px 10px; border-radius:8px; text-align:left;
  }
  .client-row:hover{ background:var(--bg); color:var(--ink); }
  /* Right-aligned, where the count used to sit. A drawn chevron rather than a
     ▾ glyph: at this size the glyph rendered as a filled blob and sat off the
     optical centre. Collapsed, it points right. */
  .client-row .caret{
    margin-left:auto; width:15px; height:15px; color:var(--faint);
    stroke-width:2; transition:transform .18s; flex:none;
  }
  .client-group:not(.open) .client-row .caret{ transform:rotate(-90deg); }
  .client-row .pd{ width:8px; height:8px; border-radius:50%; flex:none; }
  .client-row .cname{ min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .client-projects{ display:none; flex-direction:column; gap:1px; padding:2px 0 6px 6px; }
  .client-group.open .client-projects{ display:flex; }
  .proj-link{
    display:flex; align-items:center; gap:9px; font-size:14px; font-weight:500; color:var(--text);
    padding:7px 10px; border-radius:7px; border:1px solid transparent;
  }
  .proj-link:hover{ background:var(--bg); }
  .proj-link.active{ background:var(--bg); border-color:var(--line); color:var(--ink); font-weight:600; }
  .proj-link .dot{ width:5px; height:5px; border-radius:50%; background:var(--faint); flex:none; }
  .proj-add,.client-add{
    display:flex; align-items:center; gap:9px; font-size:12.5px; color:var(--faint);
    padding:7px 10px; border-radius:7px;
  }
  /* Sits at nav-link size and weight: it is a top-level action alongside
     Dashboard and Activity, not a child of the tree the way "New project" is.
     Carries its own --text because it used to inherit that from `.snav a`, and
     that rule no longer reaches into the tree. */
  .client-add{ margin-top:4px; font-size:13.5px; font-weight:500; color:var(--text); }
  .client-add:hover{ color:var(--ink); background:var(--bg); }
  /* "New project" is a link, not a row: it sits inside the project list but
     must not compete with the projects themselves, so it loses the hover fill
     and picks up an underline instead. */
  .proj-add{
    font-size:11px; gap:6px; padding:4px 10px; align-self:flex-start;
    opacity:.7; transition:opacity .12s ease;
  }
  /* Fades rather than taking a dimmer colour: --faint is already the faintest
     token, and this has to stay quiet in both themes. */
  .proj-add:hover{
    color:var(--faint); background:none; opacity:1;
    text-decoration:underline; text-underline-offset:2px;
  }
  /* Activity is pinned to the bottom of the tree rather than trailing the
     client list: it carries the auto margin, so it sits directly above the rule
     that separates the profile footer, however short or long the tree is. */
  .side-extra{ margin-top:auto; }
  .side-foot{ border-top:1px solid var(--line); padding-top:12px; margin-top:8px; }
  .me{
    display:flex; align-items:center; gap:10px; padding:8px 10px; border-radius:8px;
  }
  .me:hover{ background:var(--bg); }
  .me small{ display:block; color:var(--muted); font-size:11px; }
  .me b{ font-size:13px; color:var(--ink); }
  .signout{ display:block; width:100%; text-align:left; background:none; border:0; padding:7px 10px; margin:2px 0 0; border-radius:8px; cursor:pointer; font-family:inherit; font-size:12.5px; color:var(--muted); }
  .signout:hover{ background:var(--bg); color:var(--ink); }

  .av{
    width:28px; height:28px; border-radius:50%; flex:none;
    display:inline-flex; align-items:center; justify-content:center;
    font-size:11px; font-weight:700; color:#fff;
    font-family:'Space Grotesk',sans-serif;
  }
  .av.sm{ width:24px; height:24px; font-size:10px; }  .av.a1{ background:var(--inverse-bg); }
  .av.a2{ background:var(--blue); }
  .av.a3{ background:var(--pink); }
  .av.a4{ background:var(--violet); }

  /* ---------- MAIN ---------- */
  .main{ padding:0 32px 56px; min-width:0; }

  /* Priorities floating button (project & client pages): bottom-right, opens a
     popup just above it, right-aligned to the button. */
  .prio-fab{ position:fixed; right:24px; bottom:24px; z-index:60; }
  .prio-fab-btn{
    list-style:none; cursor:pointer; display:inline-flex; align-items:center; gap:8px;
    padding:11px 20px; border-radius:999px; background:var(--panel); color:var(--ink);
    border:1.5px solid var(--amber); font-weight:600; font-size:14px; white-space:nowrap;
    box-shadow:0 8px 22px rgba(0,0,0,.16); transition:box-shadow .12s ease, border-color .12s ease;
  }
  .prio-fab-btn::-webkit-details-marker{ display:none; }
  .prio-fab-btn:hover{ box-shadow:0 12px 28px rgba(0,0,0,.20); }
  .prio-fab-count{
    min-width:20px; height:20px; padding:0 6px; border-radius:10px;
    background:var(--amber); color:#3a2a00; font-size:11px; font-weight:700;
    display:inline-flex; align-items:center; justify-content:center;
  }
  .prio-fab-count[hidden]{ display:none; }
  .prio-fab-pop{
    position:absolute; right:0; bottom:calc(100% + 12px); width:360px; max-width:calc(100vw - 40px);
  }
  .prio-fab-pop .card{ max-height:min(70vh, 560px); overflow:auto; box-shadow:0 16px 40px rgba(0,0,0,.20); }
  .prio-fab[open] .prio-fab-btn{ border-color:var(--amber-deep); }
  @media (max-width:620px){ .prio-fab-pop{ width:calc(100vw - 40px); } }
  .topbar{
    display:flex; align-items:center; justify-content:space-between; gap:16px;
    padding:18px 0 16px; border-bottom:1px solid var(--line); margin-bottom:26px;
  }
  .crumb{ font-family:'IBM Plex Mono',monospace; font-size:11px; letter-spacing:.04em; color:var(--muted); }
  .crumb b{ color:var(--ink); font-weight:600; }
  .crumb a:hover{ color:var(--ink); }
  /* Notifications and search on the left, the sections on the right. The
     client portal still runs a breadcrumb through the same bar, hence the auto
     margin rather than changing .topbar itself. */
  .top-left{ display:flex; gap:10px; align-items:center; min-width:0; }
  .top-actions{ display:flex; gap:6px; align-items:center; margin-left:auto; }
  .toplink{
    font-size:13px; font-weight:600; color:var(--muted);
    padding:7px 11px; border-radius:9px; white-space:nowrap;
  }
  .toplink:hover{ color:var(--ink); background:var(--bg); }
  .toplink.active{ color:var(--ink); background:var(--bg); }

  /* ---------- STOPWATCH ----------
     Hidden until something is running, so the bar costs nothing on a page where
     nobody is tracking. Amber while running, quiet while paused, so a forgotten
     timer is visible from across the room. */
  .timer-bar{
    display:none; align-items:center; gap:9px; margin-left:auto; flex:none;
    padding:5px 6px 5px 13px; border-radius:var(--btn-radius);
    border:1px solid var(--timer-line); background:var(--timer-bg);
    max-width:min(46vw, 420px);
  }
  .timer-bar[data-state="running"], .timer-bar[data-state="paused"]{ display:flex; }
  .timer-bar[data-state="paused"]{ border-color:var(--line); background:var(--bg); }
  .timer-task{
    font-size:12.5px; font-weight:600; color:var(--timer-ink);
    min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  }
  .timer-bar[data-state="paused"] .timer-task{ color:var(--muted); }
  .timer-clock{
    font-size:13px; font-weight:600; color:var(--timer-clock);
    font-variant-numeric:tabular-nums; flex:none;
  }
  .timer-btn{
    display:inline-flex; align-items:center; justify-content:center; flex:none;
    width:26px; height:26px; border-radius:50%; border:none; line-height:1;
    background:transparent; color:var(--timer-ink); font-size:11px;
  }
  .timer-bar[data-state="paused"] .timer-btn{ color:var(--muted); }
  .timer-btn:hover{ background:var(--panel); color:var(--ink); }
  .timer-x{ font-size:12px; opacity:.6; }
  .timer-x:hover{ color:var(--red); opacity:1; }

  /* ---------- TASK PICKER ----------
     Start tracking anything without navigating to find it first. */
  .timer-pick{ position:relative; flex:none; margin-left:6px; }
  .timer-pick-btn{
    list-style:none; cursor:pointer; display:inline-flex; align-items:center; gap:6px;
    padding:7px 13px; border-radius:var(--btn-radius);
    border:1px solid var(--line); background:var(--panel);
    font-size:12px; font-weight:600; color:var(--muted); white-space:nowrap;
  }
  .timer-pick-btn::-webkit-details-marker{ display:none; }
  .timer-pick-btn:hover{ color:var(--ink); border-color:var(--line-strong); }
  .timer-pick[open] .timer-pick-btn{ color:var(--ink); border-color:var(--amber); }
  /* The label goes once a timer is running - the bar beside it is already wide,
     and the icon alone still reads as "start something else". */
  .timer-bar[data-state="running"] ~ .timer-pick .tp-label,
  .timer-bar[data-state="paused"] ~ .timer-pick .tp-label{ display:none; }

  .timer-pick-pop{
    position:absolute; right:0; top:calc(100% + 8px); z-index:70; width:380px;
    max-width:calc(100vw - 32px);
    background:var(--panel); border:1px solid var(--line); border-radius:14px;
    box-shadow:var(--shadow-menu); overflow:hidden;
  }
  .tp-head{ padding:10px; border-bottom:1px solid var(--line-soft); display:flex; flex-direction:column; gap:8px; }
  .tp-search, .tp-select{
    width:100%; font-family:inherit; font-size:13px; color:var(--ink);
    background:var(--bg); border:1px solid var(--line); border-radius:9px; padding:8px 10px;
  }
  .tp-search:focus, .tp-select:focus{ outline:none; border-color:var(--line-strong); }
  .tp-filters{ display:flex; gap:8px; }
  .tp-list{ max-height:min(52vh, 380px); overflow-y:auto; padding:5px; }
  .tp-row{
    display:flex; align-items:center; gap:9px; width:100%; text-align:left;
    border:none; background:none; padding:8px 9px; border-radius:9px; cursor:pointer;
  }
  .tp-row:hover{ background:var(--bg); }
  .tp-text{ flex:1; min-width:0; font-size:13px; color:var(--task-ink); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .tp-text small{ display:block; font-size:10.5px; color:var(--faint); overflow:hidden; text-overflow:ellipsis; }
  .tp-mine{
    flex:none; font-family:'IBM Plex Mono',monospace; font-size:8.5px; font-weight:700;
    color:var(--amber-deep); background:var(--amber-tint); border-radius:999px; padding:2px 6px;
  }
  .tp-play{ flex:none; font-size:9px; color:var(--faint); }
  .tp-row:hover .tp-play{ color:var(--amber); }
  .tp-note{ padding:16px; text-align:center; font-size:12.5px; color:var(--muted); }
  /* Client / project narrowing under the activity chips. Reuses .tp-select so
     the two filter surfaces in the app look like one idea. */
  .feed-narrow{
    display:flex; align-items:center; gap:8px; flex-wrap:wrap;
    padding:0 18px 12px; border-bottom:1px solid var(--line-soft);
  }
  .feed-narrow .tp-select{ width:auto; min-width:170px; flex:0 1 220px; }
  .tp-foot{ padding:8px 12px; border-top:1px solid var(--line-soft); font-size:11px; color:var(--faint); }
  @media (max-width:720px){ .timer-pick-pop{ width:calc(100vw - 32px); } }

  /* Play button on a task row. Quiet until the row is hovered, like the other
     row controls, so a list of tasks is not a wall of buttons. */
  .timer-start{
    display:inline-flex; align-items:center; justify-content:center;
    width:22px; height:22px; border-radius:50%; border:none; flex:none;
    background:transparent; color:var(--faint); font-size:9px; line-height:1;
    opacity:0; transition:opacity .12s ease, color .12s ease, background .12s ease;
  }
  .row-task:hover .timer-start,
  .timer-start:focus-visible{ opacity:1; }
  .timer-start:hover{ background:var(--amber-tint); color:var(--amber-deep); }
  /* Already tracking this task: stays lit, and says so. */
  .timer-start.on{ opacity:1; color:var(--amber); }

  /* Theme switch. Shows the icon for the theme you'd get by pressing it: the
     moon while you're in the light theme, the sun while you're in the dark. */
  .theme-btn{
    display:inline-flex; align-items:center; justify-content:center;
    width:34px; height:34px; margin-left:4px; flex:none;
    border:1px solid var(--line); border-radius:var(--btn-radius);
    background:var(--panel); color:var(--muted); cursor:pointer;
    transition:color .15s, border-color .15s, background .15s;
  }
  .theme-btn:hover{ color:var(--ink); border-color:var(--line-strong); background:var(--bg); }
  .theme-ic{ width:16px; height:16px; }
  .theme-ic-sun{ display:none; }
  [data-theme="dark"] .theme-ic-sun{ display:block; }
  [data-theme="dark"] .theme-ic-moon{ display:none; }

  /* One icon weight everywhere, inheriting the text colour beside it. */
  .ico{ width:16px; height:16px; flex:none; }
  /* Page actions belong with the page title, below the rule, so they never
     collide with the topbar's own. */
  .head-actions{
    display:flex; gap:10px; align-items:center; justify-content:flex-end;
    flex:none; flex-wrap:wrap;
  }
  /* Only the .greet blocks that carry actions become a row; the rest are a
     plain heading and paragraph and must stay stacked. */
  .greet.with-actions{ display:flex; align-items:flex-start; justify-content:space-between; gap:20px; }
  /* Actions on a page with no heading to sit beside. */
  .head-actions.alone{ margin-bottom:20px; }
  .search-wrap{ position:relative; }
  .search{
    display:flex; align-items:center; gap:8px;
    background:var(--panel); border:1px solid var(--line); border-radius:9px;
    padding:8px 12px; font-size:13px; color:var(--faint); min-width:260px;
    transition:border-color .15s, box-shadow .15s;
  }
  .search-wrap:focus-within .search{ border-color:var(--line-strong); box-shadow:0 4px 16px -8px rgba(16,19,23,.14); }
  .search-input{
    flex:1; min-width:0; border:none; background:transparent; outline:none;
    font-family:'Inter',sans-serif; font-size:13px; color:var(--ink);
  }
  .search-input::placeholder{ color:var(--faint); }
  .search kbd{
    flex:none; font-family:'IBM Plex Mono',monospace; font-size:10px;
    border:1px solid var(--line); border-radius:5px; padding:1px 5px; color:var(--muted); background:var(--bg);
  }
  /* Results drop in under the box. */
  .search-pop{
    position:absolute; top:calc(100% + 6px); left:0; right:0; z-index:60;
    background:var(--panel); border:1px solid var(--line); border-radius:11px;
    box-shadow:0 12px 32px -12px rgba(16,19,23,.22); overflow:hidden; padding:5px;
    max-height:min(60vh,380px); overflow-y:auto;
  }
  .search-res{
    display:flex; align-items:baseline; gap:9px; padding:9px 11px; border-radius:8px;
    cursor:pointer; text-decoration:none; color:inherit;
  }
  .search-res:hover,.search-res.active{ background:var(--bg); }
  .search-res .num{ font-family:'IBM Plex Mono',monospace; font-size:10.5px; color:var(--faint); flex:none; }
  .search-res .txt{ min-width:0; }
  .search-res .rt{ display:block; font-size:13.5px; font-weight:500; color:var(--task-ink); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
  .search-res .rm{ display:block; font-family:'IBM Plex Mono',monospace; font-size:10.5px; color:var(--faint); margin-top:2px; }
  .search-note{ padding:12px 12px; font-size:12.5px; color:var(--muted); text-align:center; }

  .btn{
    display:inline-flex; align-items:center; gap:7px;
    font-size:13px; font-weight:600; border-radius:var(--btn-radius); padding:9px 15px;
    border:1px solid var(--line); background:var(--panel); color:var(--ink);
    transition:border-color .15s, transform .12s;
  }
  .btn:hover{ border-color:var(--line-strong); }
  /* The one filled action on a page. Black in the light theme, coral in dark -
     it follows --accent, never --ink, which is a text colour. */
  .btn.dark{ background:var(--accent); color:var(--accent-fg); border-color:var(--accent); }
  .btn.dark:hover{ background:var(--accent-hover); border-color:var(--accent-hover); }
  .btn.sm{ padding:6px 11px; font-size:12.5px; border-radius:var(--btn-radius); }
  /* A button that holds a state rather than firing once: the dot fills and the
     whole thing warms up when it's on. */
  .btn.toggle .toggle-dot{
    width:8px; height:8px; border-radius:50%; flex:none;
    border:1.5px solid var(--faint); background:transparent;
  }
  .btn.toggle.on{ background:var(--amber-tint); border-color:var(--amber-line); color:var(--amber-deep); }
  .btn.toggle.on .toggle-dot{ border-color:var(--amber); background:var(--amber); }
  .btn[disabled]{ opacity:.55; pointer-events:none; }

  /* pills */
  .pill{
    font-family:'IBM Plex Mono',monospace; font-size:10px; font-weight:600; letter-spacing:.03em;
    padding:3px 9px; border-radius:999px; white-space:nowrap;
  }
  .pill.new{ background:var(--blue-tint); color:var(--blue-deep); }
  .pill.todo{ background:var(--blue-tint); color:var(--blue-deep); }
  .pill.doing{ background:var(--amber-tint); color:var(--amber-deep); }
  .pill.done{ background:var(--green-tint); color:var(--green-deep); }
  .pill.hold{ background:var(--line-soft); color:var(--muted); }
  .pill.hidden{ background:var(--red-tint); color:var(--red); }
  .pill.client{ background:var(--green-tint); color:var(--green-deep); }

  .card{
    background:var(--panel); border:1px solid var(--line); border-radius:14px;
    box-shadow:var(--shadow-card);
  }

  /* page switching */
  .page{ display:none; }
  .page.active{ display:block; animation:pgIn .18s ease; }
  @keyframes pgIn{ from{ opacity:0; transform:translateY(4px);} to{ opacity:1; transform:none;} }
  @media (prefers-reduced-motion: reduce){ .page.active{ animation:none; } }

  /* ============ DASHBOARD ============ */
  .greet{ margin-bottom:24px; }
  .greet h1{ font-size:24px; margin-bottom:3px; }
  .greet p{ margin:0; color:var(--muted); font-size:13.5px; }
  .stat-grid{ display:grid; grid-template-columns:repeat(4,1fr); gap:14px; margin-bottom:26px; }
  /* Quieter than a widget: a translucent fill the page tints through, a hairline
     instead of a border, and no lift. The numbers are reference, not the work. */
  .stat-card{
    padding:14px 16px;
    background:var(--stat-bg); border-color:var(--stat-line); box-shadow:none;
  }
  .stat-card .lbl{ font-family:'IBM Plex Mono',monospace; font-size:9px; letter-spacing:.07em; color:var(--muted); margin-bottom:6px; }
  .stat-card b{ font-family:'Space Grotesk',sans-serif; font-size:21px; color:var(--ink); display:block; line-height:1; }
  .stat-card .sub{ font-size:11px; color:var(--muted); margin-top:5px; }
  /* New replies, when there are any. The figure takes the flag colour but the
     card keeps its hairline: the ring means "this row is waiting on you" in the
     lists, and a stat is a number to read, not a thing to act on. */
  .stat-card.hot b,.stat-card.hot .lbl{ color:var(--row-flag-line); }
  .stat-card .sub.up{ color:var(--green-deep); }
  .stat-card .sub.warn{ color:var(--amber-deep); }

  .dash-cols{ display:grid; grid-template-columns:1.6fr 1fr; gap:20px; align-items:start; }
  /* No rule under the header: the capsule rows below already separate
     themselves, so a divider would only add noise. */
  .card-h{
    display:flex; align-items:center; justify-content:space-between;
    padding:16px 18px 10px;
  }
  .card-h h3{ font-size:15.5px; }
  /* Capsules need air from the card's own edge. */
  .card-body{ padding:0 12px 12px; }
  .card-h a{ font-size:12.5px; font-weight:600; color:var(--muted); }
  .card-h a:hover{ color:var(--ink); }

  /* A row is a discrete capsule, not a line in a table: its own fill, its own
     ring, and air between it and the next one. --row-radius drives the shape
     (999px = pill, 12px = card) and --row-gap the spacing - both in the token
     block at the top. */
  .row-task{
    display:flex; align-items:center; gap:12px;
    padding:9px 12px 9px 14px;
    background:var(--row-bg); border:1px solid var(--row-line);
    border-radius:var(--row-radius); margin-bottom:var(--row-gap);
    cursor:pointer;
    transition:background .12s ease, border-color .12s ease;
  }
  .row-task:last-child{ margin-bottom:0; }
  .row-task:hover{ background:var(--row-bg-hover); border-color:var(--line-strong); }
  /* A task carrying something new wears the ring, not a dot. The whole row is
     the signal, which leaves the colour dot free to mean "which client".
     --row-flag-line is amber in light, pink in dark. */
  .row-task.unread{ border-color:var(--row-flag-line); }
  .row-task.unread:hover{ border-color:var(--row-flag-line); }
  /* Client heading in a list sorted "By client" - a band, not a row: it isn't
     clickable and shouldn't read like a task. */
  .row-group{
    display:flex; align-items:center; gap:9px;
    padding:8px 12px 8px 14px; background:var(--bg);
    border-radius:8px; margin:2px 0 var(--row-gap);
  }
  .row-group .pd{ width:8px; height:8px; border-radius:50%; flex:none; }
  .row-group .rg-name{
    font-size:11px; font-weight:700; letter-spacing:.05em;
    text-transform:uppercase; color:var(--muted);
  }
  .row-group .n{ font-family:'IBM Plex Mono',monospace; font-size:10.5px; color:var(--faint); }
  .row-task .pd{ width:8px; height:8px; border-radius:50%; flex:none; }
  /* Title over its own meta line, so the row reads title-first and the
     reference details sit under it rather than competing. */
  .rt-main{ display:flex; flex-direction:column; gap:0; min-width:0; flex:1; }
  .row-task .t{ font-size:14px; font-weight:500; color:var(--task-ink); min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .row-task .meta{
    display:flex; align-items:center; gap:6px; flex-wrap:wrap;
    font-size:11px; color:var(--faint);
  }
  .row-task .meta a{ color:var(--faint); }
  .row-task .meta a:hover{ color:var(--text); text-decoration:underline; text-underline-offset:2px; }
  /* Client swatch on the meta line. Sits on the text baseline rather than
     flexed, so it never stretches the line height. */
  .meta-client{ display:inline-flex; align-items:center; gap:5px; }
  .cdot{
    width:7px; height:7px; border-radius:50%; flex:none;
    box-shadow:0 0 0 1.5px var(--row-bg);
  }
  .meta-client:hover .cdot{ box-shadow:0 0 0 1.5px var(--row-bg), 0 0 0 3px var(--line); }
  .card-tint .cdot{ box-shadow:0 0 0 1.5px var(--widget-row-bg); }
  .row-task .pill{ flex:none; }
  /* Fixed columns so My-tasks rows line up like a table too. */
  .row-task .rt-right{ display:flex; align-items:center; gap:10px; flex:none; margin-left:auto; }
  .row-task .rt-right .tcol{ flex:none; display:flex; align-items:center; justify-content:flex-start; }
  .row-task .rt-right .tcol-timer{ width:22px; justify-content:center; }
  .row-task .rt-right .tcol-status{ width:104px; }
  .row-task .rt-right .tcol-due{ width:58px; }
  .row-task .rt-right .tcol-star{ width:20px; }
  /* The add-to-priorities star lives at the very end of the row. */
  .row-task .rt-right .tcol-pin{ width:22px; justify-content:center; }

  /* Row remove (Priorities, and taking a row off the attention list): quiet
     until you hover the row, then a subtle × that turns red on hover - inline
     with the rest of the row's controls. */
  .prio-drop .row-task .prio-x{
    flex:none; border:none; background:none; cursor:pointer;
    padding:4px; border-radius:7px; line-height:0; color:var(--faint);
    opacity:0; transition:opacity .12s ease, color .12s ease, background .12s ease;
  }
  .prio-drop .row-task:hover .prio-x,.prio-drop .row-task .prio-x:focus-visible{ opacity:1; }
  .prio-drop .row-task .prio-x:hover{ color:var(--red); background:var(--red-tint); }
  .prio-drop .row-task .prio-x svg{ width:14px; height:14px; }

  /* Read / unread. Matches the project task list: read rows sit at 500 (not a
     lighter 400), unread step up to 650. The dot still carries the "look at
     these" signal, so weight parity with the project pages doesn't lose it. */
  .row-task .t{ font-weight:500; }
  .row-task.unread .t{ font-weight:650; }

  .pill.new{ background:var(--amber-tint,#fef3e2); color:var(--amber,#b4740f); border:1px solid var(--amber-line); }

  /* ---------- HIGHLIGHTED WIDGET BOX ----------
     A flat tint with a fixed sheen laid over it. To recolour the box you change
     ONE value - --widget-tint in the token block - and the sheen stays put.
     The design's alternatives: #F3A6FF (orchid), #DFF8FF (ice), #CAF4CC (mint).

     background-color carries the tint and background-image the sheen, so they
     are independent: neither shorthand overwrites the other. */
  .card-tint{
    background-color:var(--widget-tint);
    background-image:var(--widget-sheen);
    border-color:transparent;
    box-shadow:var(--shadow-card);
  }
  .card-tint h3{ color:var(--widget-ink); }
  .prio-hint{ font-size:11.5px; color:var(--muted); }
  .card-tint .prio-hint{ color:var(--widget-muted); }
  .card-tint .row-task{
    background:var(--widget-row-bg); border-color:var(--widget-row-line);
  }
  .card-tint .row-task:hover{ border-color:var(--widget-ink); }
  /* ...but the attention ring outranks the widget's own line colour. Without
     these two, .card-tint .row-task above repaints the border of an unread row
     - same specificity as .row-task.unread, and it comes later - so a task with
     something new on it looked identical to a read one inside the Priorities
     widget. It still shows correctly in the floating rail, which is a plain
     .card, which is what made the difference easy to miss. */
  .card-tint .row-task.unread{ border-color:var(--row-flag-line); }
  .card-tint .row-task.unread:hover{ border-color:var(--row-flag-line); }
  .card-tint .row-task .t{ color:var(--widget-row-ink); }
  .card-tint .row-task .meta,.card-tint .row-task .meta a{ color:var(--widget-muted); }
  /* The Clear button sits on the tint, so it needs its own solid ground. */
  .card-tint .btn{
    background:var(--widget-btn-bg); border-color:transparent; color:var(--widget-btn-fg);
  }
  .card-tint .btn:hover{ border-color:var(--widget-btn-fg); }
  /* --faint is tuned for the page, not for a coloured slab. */
  .card-tint .grip, .card-tint .drag-row .grip{ color:var(--widget-muted); }
  .card-tint .drag-row:hover .grip{ color:var(--widget-ink); }

  /* "Needs your attention" is the one warm card on the page: the card itself is
     the flag, so its rows carry no dots - bold is what marks the unseen ones. */

  /* Sidebar "(2 new)" badge */
  .proj-link.has-unread{ font-weight:650; color:var(--ink); }
  .new-badge{
    margin-left:auto; font-size:10px; font-weight:700; letter-spacing:.02em;
    background:var(--amber,#f59e2d); color:#fff; border-radius:999px;
    padding:1px 7px; white-space:nowrap;
  }

  /* ---- Drag to reorder (pointer events: mouse + touch) ---- */
  .drag-row{ position:relative; }
  .drag-row .grip{
    cursor:grab; color:var(--faint); font-size:15px; letter-spacing:-2px;
    flex:none; user-select:none; padding:6px 6px 6px 2px; margin:-6px 0;
    /* Without this a touch-drag scrolls the page instead of moving the row. */
    touch-action:none;
  }
  .drag-row .grip:hover{ color:var(--text); }
  .drag-row .grip:active{ cursor:grabbing; }
  .drag-row.dragging{ opacity:.5; background:var(--bg); }
  /* Stop the page text-selecting under a finger/mouse mid-drag. */
  body.is-dragging{ user-select:none; -webkit-user-select:none; }
  body.is-dragging *{ cursor:grabbing !important; }

  /* The Priorities drop zone reads as a target while empty. */
  .prio-drop{ min-height:54px; }
  body.is-dragging .prio-drop{ outline:2px dashed var(--line); outline-offset:-6px; border-radius:10px; }

  .star-on{ color:var(--amber,#b4740f); border-color:var(--amber-line); }

  /* Fragment being fetched - dim rather than blank, so nothing jumps. */
  .is-loading{ opacity:.55; transition:opacity .12s ease; }

  /* ---- Draggable dashboard widgets ---- */
  .wcol{ display:flex; flex-direction:column; gap:20px; min-width:0; }
  /* The full-width strips. They always hold a (hidden) drop hint, so key the
     spacing off a real widget - an unused zone then costs no vertical space. */
  .wcol-top:has(.widget){ margin-bottom:20px; }
  .wcol-bottom:has(.widget){ margin-top:20px; }
  .widget{ position:relative; min-width:0; }
  .widget > .grip.widget-grip{
    position:absolute; top:10px; left:-16px; opacity:0;
    transition:opacity .12s ease; z-index:5;
  }
  .widget:hover > .grip.widget-grip{ opacity:1; }

  /* ---- Widget height: drag the bottom edge, reset to grow with content ----
     A widget with no saved height is left alone entirely - it grows as its
     content does, which is the default and what "reset height" restores. */
  .widget.sized{ height:var(--wh); }
  .widget.sized > .card{ height:100%; display:flex; flex-direction:column; }
  .widget.sized > .card > .card-h{ flex:none; }
  /* The one scrolling region per card. Everything else stays put. */
  .widget.sized .card-body{ flex:1 1 auto; min-height:0; overflow-y:auto; }
  .widget.sized > .stat-grid{ height:100%; overflow-y:auto; margin-bottom:0; }

  /* The resize bar hangs over the widget's bottom edge, so an unsized widget
     pays nothing in layout for it. */
  .wresize{
    position:absolute; left:0; right:0; bottom:-10px; height:20px; z-index:6;
    display:flex; align-items:center; justify-content:center; gap:10px;
    opacity:0; transition:opacity .12s ease;
  }
  .widget:hover .wresize,.widget.resizing .wresize{ opacity:1; }
  .wresize-bar{
    width:46px; height:4px; border-radius:999px; background:var(--line);
    cursor:ns-resize; touch-action:none;
  }
  .wresize-bar:hover,.widget.resizing .wresize-bar{ background:var(--amber); }
  /* Only worth offering once there is a height to clear. */
  .wresize-reset{
    display:none; border:1px solid var(--line); background:var(--panel);
    font-family:'IBM Plex Mono',monospace; font-size:9.5px; color:var(--muted);
    border-radius:999px; padding:2px 9px; line-height:1.4;
  }
  .wresize-reset:hover{ border-color:var(--amber); color:var(--ink); }
  .widget.sized .wresize-reset{ display:inline-block; }
  /* Mid-drag the pointer is nowhere near the bar - keep the cursor honest. */
  body.is-resizing,body.is-resizing *{ cursor:ns-resize !important; user-select:none; }
  /* A height that didn't save would otherwise only be noticed on reload. */
  .widget.save-failed{ outline:2px solid var(--red); outline-offset:5px; border-radius:14px; }

  /* While moving a widget, show where the zones are. */
  body.dragging-widget .wcol{ outline:2px dashed var(--line); outline-offset:8px; border-radius:12px; }
  body.dragging-widget .widget > .grip.widget-grip{ opacity:1; }

  /* An empty zone has no height of its own, so it would be impossible to drop
     into. The hint gives it a target while a drag is in progress. */
  .wcol-hint{
    display:none; padding:22px; text-align:center; color:var(--faint);
    font-size:12px; border:1px dashed var(--line); border-radius:12px;
  }
  body.dragging-widget .wcol-hint{ display:block; }

  /* ---- SortableJS state classes ---- */
  /* The gap left where the row will land. */
  .drag-ghost{ opacity:.35; }
  .drag-ghost .card,.drag-ghost.card{ outline:2px dashed var(--amber,#f59e2d); }
  /* The element under the cursor while dragging. */
  .drag-active{ opacity:.95; }
  .drag-chosen{ cursor:grabbing; }
  body.is-dragging{ user-select:none; -webkit-user-select:none; }

  /* On narrow screens the columns stack, so the handles come inside the card
     rather than hanging off the left edge. */
  @media (max-width: 900px){
    .widget > .grip.widget-grip{ left:2px; top:6px; opacity:1; }
  }
  .sortable.saved{ box-shadow:inset 3px 0 0 var(--green); }
  .sortable.save-failed{ box-shadow:inset 3px 0 0 var(--red,#e5484d); }
  .sortable.save-failed::after{
    content:'Order could not be saved - reload and try again';
    display:block; padding:8px 18px; font-size:11.5px; color:var(--red,#e5484d);
  }

  /* Pin a task onto Priorities */
  .pin-btn{
    background:none; border:none; cursor:pointer; color:var(--faint);
    font-size:14px; line-height:1; padding:2px 4px;
  }
  .pin-btn:hover{ color:var(--amber,#f59e2d); }
  /* A prioritised task keeps its star, filled amber, rather than losing it. */
  .pin-btn.on{ color:var(--amber,#f59e2d); }

  /* Priorities rows keep the title from stretching the flex row */
  .row-task .t{ min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }

  /* Task rows with unseen comments read as unread, same as the dashboard. */
  .tline.has-unread .t{ font-weight:650; }
  .tline .new-badge{ margin-left:8px; }

  /* My tasks status filter */
  .status-filter{ display:flex; flex-wrap:wrap; gap:6px; }
  .status-filter .fchip{
    font-size:11.5px; font-weight:600; color:var(--muted); text-decoration:none;
    padding:3px 9px; border:1px solid var(--line); border-radius:999px; background:var(--panel);
    display:inline-flex; align-items:center; gap:5px; white-space:nowrap;
  }
  .status-filter .fchip:hover{ background:var(--bg); color:var(--ink); }
  .status-filter .fchip.on{ background:var(--accent); border-color:var(--accent); color:var(--accent-fg); }
  .status-filter .fchip b{ font-size:10px; opacity:.75; }
  /* Completed is an archive, not a working state - set apart from the rest. */
  .status-filter .fchip.archive{
    margin-left:8px; border-style:dashed; color:var(--faint);
  }
  .status-filter .fchip.archive:hover{ color:var(--text); border-style:solid; }
  .status-filter .fchip.archive.on{
    background:var(--bg); border-style:solid; border-color:var(--line); color:var(--ink);
  }
  /* Updates stands out in amber so a caught-up-or-not glance is instant. */
  .status-filter .fchip-updates{ background:var(--amber-tint,#FEF3E0); border-color:var(--amber-line); color:var(--amber-deep,#B4740F); }
  .status-filter .fchip-updates:hover{ background:var(--amber-hover); color:var(--amber-deep,#B4740F); }
  .status-filter .fchip-updates.on{ background:var(--amber-deep,#B4740F); border-color:var(--amber-deep,#B4740F); color:#fff; }
  /* The "Status" dropdown chip. */
  .fchip-dd{ position:relative; display:inline-block; }
  .fchip-dd > summary{ list-style:none; cursor:pointer; }
  .fchip-dd > summary::-webkit-details-marker{ display:none; }
  .fchip-menu{
    position:absolute; left:0; top:calc(100% + 6px); z-index:40; min-width:160px;
    background:var(--panel); border:1px solid var(--line); border-radius:10px;
    box-shadow:0 12px 32px -12px rgba(16,19,23,.22); padding:5px;
    display:flex; flex-direction:column; gap:2px;
  }
  .fchip-opt{
    display:flex; align-items:center; justify-content:space-between; gap:10px;
    padding:6px 10px; border-radius:7px; font-size:12.5px; color:var(--ink); text-decoration:none;
  }
  .fchip-opt:hover,.fchip-opt.on{ background:var(--bg); }
  .fchip-opt b{ font-size:10px; opacity:.7; }
  /* Options you tick rather than pick - the Sort menu, where the axes stack. */
  .fchip-opt.opt-check{ justify-content:flex-start; gap:9px; }
  .opt-check .tick{
    width:14px; height:14px; border-radius:4px; flex:none; position:relative;
    border:1.5px solid var(--control-line);
  }
  .opt-check .tick.on{ background:var(--accent); border-color:var(--accent); }
  .opt-check .tick.on::after{
    content:"\2713"; color:var(--accent-fg); font-size:9px; position:absolute; inset:0;
    display:flex; align-items:center; justify-content:center;
  }

  /* Notification bell */
  /* The popup spans the content column, so it anchors to the topbar rather than
     to the bell itself. The button keeps its own relative context for the count
     badge, which hangs off its corner. */
  .bell-wrap{ position:static; }
  .topbar{ position:relative; }
  .bell-btn{
    position:relative; display:flex; align-items:center; justify-content:center;
    background:none; border:1px solid var(--line); cursor:pointer;
    width:34px; height:34px; padding:0; border-radius:9px; color:var(--muted);
  }
  .bell-btn:hover{ background:var(--bg); color:var(--ink); }
  .bell-btn .ico{ width:17px; height:17px; }
  /* A quick ring + badge pop when the count goes up, so a new notification is
     noticed without a reload. */
  @keyframes bellRing {
    0%,100%{ transform:rotate(0); }
    10%{ transform:rotate(-16deg); } 22%{ transform:rotate(13deg); }
    34%{ transform:rotate(-10deg); } 46%{ transform:rotate(7deg); }
    58%{ transform:rotate(-4deg); } 70%{ transform:rotate(2deg); }
  }
  @keyframes bellPop { 0%{ transform:scale(.5); } 55%{ transform:scale(1.3); } 100%{ transform:scale(1); } }
  .bell-ring .ico{ animation:bellRing .8s ease; transform-origin:top center; }
  .bell-ring .bell-count{ animation:bellPop .5s ease; }
  @media (prefers-reduced-motion: reduce){ .bell-ring .ico,.bell-ring .bell-count{ animation:none; } }
  .bell-count{
    position:absolute; top:-5px; right:-5px; min-width:16px; height:16px; padding:0 4px;
    background:var(--red,#e5484d); color:#fff; border-radius:999px;
    font-size:10px; font-weight:700; line-height:16px; text-align:center;
  }
  .bell-pop{
    /* Runs the width of the content column, anchored to the topbar rather than
       to the bell. These entries carry whole messages now, and a 440px column
       wrapped every one of them. */
    position:absolute; left:0; right:0; top:calc(100% - 4px);
    max-height:min(74vh, 620px); overflow:auto;
    background:var(--panel); border:1px solid var(--line); border-radius:14px;
    box-shadow:var(--shadow-pop); z-index:60; display:none;
  }
  .bell-pop.open{ display:block; }
  .bell-pop .bell-h{
    display:flex; align-items:center; justify-content:space-between;
    padding:11px 14px; border-bottom:1px solid var(--line-soft);
  }
  .bell-pop .bell-h b{ font-size:12.5px; }
  /* A row keeps its place until it's dismissed, so it carries the layout and
     the × sits beside the link rather than inside it. */
  .bell-row{ display:flex; align-items:center; gap:6px; border-bottom:1px solid var(--line-soft); }
  .bell-row:last-child{ border-bottom:none; }
  .bell-row:hover{ background:var(--bg); }
  .bell-item{ display:block; flex:1; min-width:0; padding:11px 4px 11px 14px; text-decoration:none; }
  .bell-item .bt{ font-size:13px; font-weight:500; color:var(--ink); display:block; }
  .bell-row.unread .bell-item .bt{ font-weight:650; }
  .bell-item .bm{ display:flex; align-items:center; gap:6px; font-size:11px; color:var(--muted); margin-top:1px; }
  .bell-item .bm .cdot{ width:6px; height:6px; box-shadow:none; }

  /* The filter row sits under the header and above the list, sticky so it stays
     reachable once the list is long enough to scroll. */
  /* Frosted glass over the page while the notifications are open, so the list
     reads as the thing in front rather than one more panel among many. Sits
     under the popup and over everything else, and closes on a click.

     backdrop-filter is progressive: without it the tint alone still separates
     the two layers, just without the blur. */
  .bell-scrim{
    position:fixed; inset:0; z-index:58; display:none;
    background:var(--scrim-glass);
    -webkit-backdrop-filter:blur(var(--scrim-blur));
    backdrop-filter:blur(var(--scrim-blur));
  }
  .bell-scrim.open{ display:block; }
  /* The bell stays above the glass while the list is open: it is the way back
     out, so it has to look pressable rather than dimmed with the page. Its own
     click handler closes, so it works as a toggle. */
  .bell-btn.open{
    z-index:61; background:var(--panel); border-color:var(--line-strong); color:var(--ink);
  }
  /* Above the scrim, and above the sidebar it now covers. */
  .bell-pop.open{ z-index:60; }

  /* Layout only - the chips themselves come from .status-filter, which this
     also carries. Sticky so the filters stay reachable once the list scrolls. */
  .bell-filters{
    padding:9px 14px; border-bottom:1px solid var(--line-soft);
    position:sticky; top:0; z-index:2; background:var(--panel);
  }
  /* These are buttons rather than links (they swap the feed in place instead of
     navigating), and a button brings its own borders and font along. */
  .bell-filters .fchip{ cursor:pointer; font-family:inherit; line-height:1.5; }

  /* Messages under the task they arrived on. Indented and ruled so the group
     reads as one thing rather than four loose lines. */
  .bell-thread{
    display:block; margin-top:7px; padding-left:10px;
    border-left:2px solid var(--line);
  }
  .bell-row.unread .bell-thread{ border-left-color:var(--row-flag-line); }
  .bell-msg{ display:block; font-size:11.5px; color:var(--text); margin-bottom:5px; }
  .bell-msg:last-child{ margin-bottom:0; }
  .bell-msg b{ color:var(--ink); font-weight:600; margin-right:6px; }
  .bell-msg i{
    font-family:'IBM Plex Mono',monospace; font-style:normal;
    font-size:9.5px; color:var(--faint);
  }
  .bell-msg span{ display:block; color:var(--muted); margin-top:1px; }
  .bell-more{ display:block; font-size:10.5px; color:var(--faint); margin-top:4px; }
  .bell-x{
    flex:none; border:none; background:none; cursor:pointer; margin-right:8px;
    padding:4px 6px; border-radius:7px; font-size:11px; line-height:1; color:var(--faint);
    opacity:0; transition:opacity .12s ease, color .12s ease, background .12s ease;
  }
  .bell-row:hover .bell-x,.bell-x:focus-visible{ opacity:1; }
  .bell-x:hover{ color:var(--red); background:var(--red-tint); }
  .bell-empty{ padding:22px 14px; text-align:center; color:var(--muted); font-size:12.5px; }

  .feed{ padding:6px 0; }
  .feed-item{ display:flex; gap:12px; padding:11px 18px; }
  .feed-item + .feed-item{ border-top:1px solid var(--line-soft); }
  .feed-item .dotcol{ display:flex; flex-direction:column; align-items:center; padding-top:4px; }
  .feed-item .fdot{ width:8px; height:8px; border-radius:50%; flex:none; }
  .feed-item p{ margin:0; font-size:13px; color:var(--text); }
  .feed-item p b{ color:var(--ink); font-weight:600; }
  .feed-item time{ display:block; font-family:'IBM Plex Mono',monospace; font-size:10px; color:var(--faint); margin-top:3px; }
  .feed-item a:hover{ text-decoration:underline; text-underline-offset:2px; }

  /* How something reached us, not what it was: the chip on an email-sourced
     comment, and the same chip in the activity feed. */
  .via-mail,.via-slack,.via-code{
    display:inline-flex; align-items:center; gap:5px; white-space:nowrap;
    font-family:'IBM Plex Mono',monospace; font-size:9.5px;
    border-radius:999px; padding:1px 8px; margin-left:6px; vertical-align:1px;
  }
  .via-mail{ color:var(--green-deep); background:var(--green-tint); }
  .via-slack{ color:var(--violet); background:var(--violet-tint); }
  .via-code{ color:var(--blue-deep); background:var(--blue-tint); }

  .bar-row{ padding:11px 18px; border-bottom:1px solid var(--line-soft); }
  .bar-row:last-child{ border-bottom:none; }
  .bar-top{ display:flex; justify-content:space-between; font-size:12.5px; margin-bottom:6px; }
  .bar-top b{ color:var(--ink); font-weight:600; display:flex; align-items:center; gap:8px; }
  .bar-top span{ font-family:'IBM Plex Mono',monospace; font-size:11px; color:var(--muted); }
  .bar{ height:6px; border-radius:999px; background:var(--line-soft); overflow:hidden; }
  .bar i{ display:block; height:100%; border-radius:999px; }

  /* ============ PROJECT PAGE ============ */
  .proj-head{ display:flex; align-items:flex-start; justify-content:space-between; gap:20px; margin-bottom:22px; }
  /* The title column takes the room. Without this it shrink-wraps its content,
     which left the description box about a third of the page wide. */
  .proj-head > div:first-child{ flex:1; min-width:0; }
  .proj-head .pd{ width:12px; height:12px; border-radius:50%; display:inline-block; margin-right:10px; }
  .proj-head h1{ font-size:22px; display:flex; align-items:center; }
  .proj-desc{ margin:8px 0 0; font-size:13.5px; color:var(--muted); line-height:1.55; max-width:640px; }
  /* collapsed preview: clamp to 2 lines with a fade */  /* inline rich-text editor */
  /* "Email me" switch in the project header, beside its label. */
  .head-email{ display:inline-flex; align-items:center; gap:8px; }
  .head-email-label{ font-size:13px; color:var(--muted); white-space:nowrap; }

  /* Project members panel: who (beyond owners/admins) can see this project. */
  .proj-members{ display:flex; flex-wrap:wrap; align-items:center; gap:8px; margin:0 0 16px; }
  .pm-label{ font-size:11px; font-weight:600; letter-spacing:.04em; text-transform:uppercase; color:var(--muted); }
  .pm-chip{
    display:inline-flex; align-items:center; gap:6px; padding:4px 8px 4px 6px;
    background:var(--panel); border:1px solid var(--line); border-radius:999px; font-size:12.5px; font-weight:500;
  }
  .pm-x{ border:none; background:none; cursor:pointer; color:var(--muted); font-size:11px; line-height:1; padding:2px; }
  .pm-x:hover{ color:var(--red); }
  .pm-empty{ font-size:12.5px; color:var(--muted); }
  .pm-adddd{ position:relative; }
  .pm-add{ cursor:pointer; font-size:12.5px; font-weight:600; color:var(--ink); list-style:none; padding:4px 8px; border:1px dashed var(--line); border-radius:999px; }
  .pm-adddd[open] .pm-add{ background:var(--panel); }
  .pm-form{ position:absolute; z-index:20; top:calc(100% + 6px); left:0; background:var(--panel); border:1px solid var(--line); border-radius:10px; padding:10px; display:flex; gap:6px; box-shadow:0 8px 24px rgba(0,0,0,.10); }  .proj-meta{ display:flex; gap:10px; flex-wrap:wrap; margin-top:14px; }
  .chip{
    display:inline-flex; align-items:center; gap:7px;
    font-size:12px; font-weight:500; color:var(--muted);
    background:var(--panel); border:1px solid var(--line); border-radius:999px; padding:5px 12px;
  }
  .chip b{ color:var(--ink); font-weight:600; }
  .chip .mono{ font-size:11px; }

  .tabs{ display:flex; gap:2px; border-bottom:1px solid var(--line); margin-bottom:18px; }
  .tab{
    font-size:13.5px; font-weight:600; color:var(--muted);
    padding:9px 14px; border:none; background:none;
    border-bottom:2px solid transparent; margin-bottom:-1px;
  }
  .tab:hover{ color:var(--ink); }
  .tab.active{ color:var(--ink); border-bottom-color:var(--amber); }
  .tab .count{ font-family:'IBM Plex Mono',monospace; font-size:10.5px; color:var(--faint); margin-left:5px; }

  .filters{ display:flex; gap:8px; margin-bottom:14px; align-items:center; }  .unassigned{
    font-family:'IBM Plex Mono',monospace; font-size:10.5px; color:var(--faint);
    border:1px dashed var(--line); border-radius:999px; padding:2px 9px;
  }
  /* view toggle */
  /* selection checkbox on list rows */  .tline.selected{ background:var(--amber-tint); }
  .tline.selected:hover{ background:var(--amber-hover); }

  /* clickable status chip */
  .statuschip{ cursor:pointer; display:inline-flex; align-items:center; gap:5px; user-select:none; }  .statuschip:hover{ filter:brightness(.97); }

  /* status dropdown menu */
  /* ---------- BOARD ---------- */
  .board{ display:grid; grid-template-columns:repeat(4,1fr); gap:14px; align-items:start; }
  .col{ background:var(--bg); border:1px solid var(--line); border-radius:14px; padding:10px; min-height:120px; }
  /* ---------- BULK BAR ---------- */
  @media (max-width:1100px){ .board{ grid-template-columns:repeat(2,1fr); } }

  /* ============ RESPONSIVE ============ */
  /* mobile top bar hidden by default */
  .mtop{ display:none; }
  .side-backdrop{
    display:none; position:fixed; inset:0; background:var(--scrim); z-index:90;
    opacity:0; transition:opacity .2s;
  }

  /* --- TABLET: <= 1000px --- */
  @media (max-width:1000px){
    .stat-grid{ grid-template-columns:repeat(2,1fr); }
    .dash-cols{ grid-template-columns:1fr; }
    .task-grid{ grid-template-columns:1fr; }
    /* meta sidebar of task/invoice/note moves below content, becomes 2-up where it can */    .note-grid{ grid-template-columns:repeat(2,1fr); }
    .main{ padding:0 22px 56px; }
    .filters{ flex-wrap:wrap; }
    .filters .right{ margin-left:0; }
  }

  /* --- MOBILE: <= 720px --- */
  @media (max-width:720px){
    .app{ padding-left:0; }

    /* show mobile bar */
    .mtop{
      display:flex; align-items:center; gap:12px;
      position:sticky; top:0; z-index:60;
      background:var(--panel); border-bottom:1px solid var(--line);
      padding:11px 16px;
    }
    .mtop::before{ content:""; position:absolute; top:0; left:0; right:0; height:3px; background:var(--rainbow); }
    .mburger{ border:none; background:none; font-size:20px; color:var(--ink); padding:2px 4px; line-height:1; }
    .mlogo{ display:flex; align-items:center; gap:8px; font-family:'Space Grotesk',sans-serif; font-weight:700; font-size:16px; color:var(--ink); }
    .mlogo svg{ width:24px; height:24px; }

    /* sidebar becomes slide-in drawer */
    /* As a drawer it goes back to the screen edge - the floating inset only
       makes sense next to the page, not sliding over it. */
    .side{
      position:fixed; top:0; left:0; bottom:0; width:260px; z-index:95;
      transform:translateX(-105%); transition:transform .22s cubic-bezier(.2,.8,.2,1);
      height:100vh; border-radius:0; border:none; border-right:1px solid var(--line);
    }
    body.snav-open .side{ transform:translateX(0); }
    body.snav-open .side-backdrop{ display:block; opacity:1; }

    .main{ padding:0 16px 48px; }
    .topbar{ padding:14px 0 12px; margin-bottom:18px; flex-wrap:wrap; gap:10px; }
    .topbar .search-wrap{ display:none; }
    .top-actions{ width:100%; }
    .top-actions .btn{ flex:1; justify-content:center; }

    /* stack every multi-column grid */
    .stat-grid{ grid-template-columns:1fr 1fr; gap:10px; }
    .stat-card{ padding:14px; }
    .stat-card b{ font-size:22px; }    .note-grid{ grid-template-columns:1fr; }
    .board{ grid-template-columns:1fr; }

    /* project header wraps, and the page actions with it */
    .proj-head{ flex-direction:column; gap:14px; }
    .proj-meta{ gap:8px; }
    .greet.with-actions{ flex-direction:column; gap:14px; }
    .head-actions{ width:100%; justify-content:flex-start; }

    /* invoice document padding down */
    .inv-doc{ padding:22px 18px; }
    .inv-doc .parties{ grid-template-columns:1fr; gap:14px; }

    /* settings inputs full width */
    .set-row{ flex-direction:column; align-items:flex-start; gap:10px; }
    .set-input{ min-width:0; width:100%; }

    /* drawer full width on phones */
    /* greeting a touch smaller */
    .greet h1{ font-size:20px; }

    /* bulk bar spans bottom */
    /* comments: tighten */
    .task-title-row{ flex-wrap:wrap; margin-bottom:16px; }
    .task-title-row h1{ font-size:20px; }
    .task-sub{ margin-left:0; flex-basis:100%; }
    .thread .msg{ font-size:14px; }
    /* meta column stacks under the content on phones, no offset */
    .task-side{ margin-top:0; }

    /* filters horizontal scroll instead of wrap chaos */
    .filters{ flex-wrap:nowrap; overflow-x:auto; padding-bottom:4px; -webkit-overflow-scrolling:touch; }
    .filters::-webkit-scrollbar{ height:0; }  }

  /* --- SMALL PHONE: <= 420px --- */
  @media (max-width:420px){
    .stat-grid{ grid-template-columns:1fr; }
    .preview-bar{ flex-wrap:wrap; }
    .preview-bar .right{ margin-left:0; width:100%; }
    .preview-bar .right .btn{ flex:1; }
  }
  .filters .right{ margin-left:auto; }

  /* The end rows round themselves rather than being clipped by the card: the
     Status dropdown now opens from inside the list head, and overflow:hidden
     would cut it off. */
  .tlist{ overflow:visible; }
  .tlist > :first-child{ border-radius:14px 14px 0 0; }
  .tlist > :last-child{ border-radius:0 0 14px 14px; }
  .tline{
    display:flex; align-items:center; gap:12px;
    padding:12px 16px; border-bottom:1px solid var(--line-soft); cursor:pointer;
  }
  .tline:last-child{ border-bottom:none; }
  .tline:hover{ background:var(--bg); }
  .tline.sub{ padding-left:46px; position:relative; }
  .tline.sub::before{
    content:""; position:absolute; left:26px; top:0; bottom:50%; width:10px;
    border-left:1.5px solid var(--line); border-bottom:1.5px solid var(--line); border-radius:0 0 0 6px;
  }
  .cb{ width:15px; height:15px; border-radius:4px; border:1.5px solid var(--control-line); flex:none; position:relative; }
  .cb.on{ background:var(--green); border-color:var(--green); }
  .cb.on::after{ content:"âœ“"; color:#fff; font-size:9px; position:absolute; inset:0; display:flex; align-items:center; justify-content:center; }
  .tline .t{ font-size:13.5px; font-weight:500; color:var(--task-ink); min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .tline .id{ font-family:'IBM Plex Mono',monospace; font-size:10.5px; color:var(--faint); flex:none; }
  .tline .right{ margin-left:auto; display:flex; align-items:center; gap:12px; flex:none; }
  .tline .time{ font-family:'IBM Plex Mono',monospace; font-size:11px; color:var(--muted); }
  .eye{ font-size:12px; color:var(--faint); }
  /* Fixed columns so the row details line up like a table down the list. */
  .tline .right .tcol{ flex:none; display:flex; align-items:center; justify-content:flex-start; }
  .tline .right .tcol-time{ width:64px; }
  .tline .right .tcol-pin{ width:22px; justify-content:center; }
  .tline .right .tcol-assignee{ width:38px; gap:4px; }
  .tline .right .tcol-status{ width:104px; }
  .tline .right .tcol-due{ width:58px; }
  .tline .right .tcol-star{ width:20px; }
  /* Column-title header row above the task list. On project and client pages it
     doubles as the filter bar: chips sit on the left, where the task titles run,
     column titles stay on the right above their own columns. Padding is even top
     and bottom so the chips and the titles sit centred on the same line. */
  .tline-head{ cursor:default; padding-top:9px; padding-bottom:7px; align-items:center; }
  .tline-head:hover{ background:none; }
  .tline-head .tcol{ font-size:8.5px; letter-spacing:.05em; text-transform:uppercase; color:var(--faint); font-weight:600; }
  .tline-head.tline-filter-head{ padding-top:9px; padding-bottom:9px; border-bottom-color:var(--line); }
  .tline-head .status-filter{ flex:1 1 auto; min-width:0; align-items:center; row-gap:6px; }
  /* Due date chip on task rows; red once it's past and the task isn't done. */
  .due{ font-family:'IBM Plex Mono',monospace; font-size:10.5px; color:var(--muted); white-space:nowrap; flex:none; }
  .due.over{ color:var(--red); font-weight:600; }

  /* ============ TASK PAGE ============ */
  .task-grid{ display:grid; grid-template-columns:1fr 300px; gap:22px; align-items:start; }
  /* Drop the meta column so it lines up with the first content block rather
     than the title above it. */
  .task-side{ margin-top:52px; }
  .task-title-row{ display:flex; align-items:center; gap:13px; margin-bottom:22px; }
  .task-title-row h1{ font-size:27px; line-height:1.2; }
  .task-sub{ font-family:'IBM Plex Mono',monospace; font-size:11px; color:var(--muted); margin-left:auto; flex:none; white-space:nowrap; }

  .block{ margin-bottom:20px; }
  .block-h{
    font-family:'IBM Plex Mono',monospace; font-size:10px; letter-spacing:.08em;
    color:var(--faint); margin-bottom:8px; display:flex; align-items:center; justify-content:space-between;
  }
  .desc{ padding:16px 18px; font-size:13.5px; color:var(--text); }
  .sub-list{ overflow:hidden; }
  .sub-line{ display:flex; align-items:center; gap:11px; padding:10px 16px; border-bottom:1px solid var(--line-soft); }
  .sub-line:last-child{ border-bottom:none; }
  .sub-line .t{ font-size:13px; font-weight:500; color:var(--task-ink); }
  .sub-line .t.strike{ text-decoration:line-through; font-weight:400; }
  .sub-line .right{ margin-left:auto; display:flex; gap:10px; align-items:center; }
  .sub-line .time{ font-family:'IBM Plex Mono',monospace; font-size:10.5px; color:var(--muted); }
  .add-line{
    display:flex; align-items:center; gap:9px; padding:10px 16px;
    color:var(--faint); font-size:13px; border-top:1px dashed var(--line); cursor:text;
  }

  /* comments */
  .thread{ display:flex; flex-direction:column; gap:14px; }
  .cmt{ display:flex; gap:11px; }
  .cmt .body{ min-width:0; flex:1; }
  .cmt .who{ display:flex; align-items:center; gap:8px; margin-bottom:5px; }
  .cmt .who b{ font-size:12.5px; color:var(--muted); font-weight:500; }
  .cmt .who time{ margin-left:auto; font-family:'Inter',sans-serif; font-size:11.5px; color:var(--faint); font-weight:400; flex:none; }
  .cmt .msg{
    background:var(--panel); border:1px solid var(--line); border-radius:4px 12px 12px 12px;
    padding:14px 17px; font-size:15px; line-height:1.6; color:var(--ink);
  }
  /* Amber only flags a comment the reader hasn't seen yet - it fades to plain
     white once the page has been read. */
  .cmt.unseen .msg{ background:var(--amber-tint); border-color:var(--amber-line); }
  /* Paragraph spacing: a lone paragraph sits flush; several get gaps between
     them and nothing after the last. */
  .cmt .msg > p{ margin:0; }
  .cmt .msg > p:not(:only-child){ margin-bottom:10px; }
  .cmt .msg > p:last-child{ margin-bottom:0; }
  .cmt .attach{
    display:inline-flex; align-items:center; gap:7px; margin-top:8px;
    font-size:12px; font-weight:500; color:var(--ink);
    background:var(--bg); border:1px solid var(--line); border-radius:8px; padding:6px 11px;
  }
  .composer{ margin-top:16px; }
  .composer .box{
    background:var(--panel); border:1px solid var(--line); border-radius:12px; overflow:hidden;
    transition:border-color .15s, box-shadow .15s;
  }
  .composer .box:focus-within{ border-color:var(--line-strong); box-shadow:0 4px 16px -8px rgba(16,19,23,.12); }
  .composer textarea{
    width:100%; resize:vertical; min-height:74px; border:none; display:block;
    background:transparent; padding:12px 14px; font-family:'Inter',sans-serif; font-size:14px; color:var(--ink);
  }
  .composer textarea:focus{ outline:none; }
  .composer textarea::placeholder{ color:var(--faint); }
  /* wysiwyg toolbar - hidden until the composer is focused */  /* image dropzone */  .composer .foot{ display:flex; align-items:center; gap:12px; margin-top:9px; }
  .composer .hint{ font-size:11.5px; color:var(--faint); }
  .composer .hint b{ color:var(--green-deep); font-weight:600; }
  .composer .btn{ margin-left:auto; }

  /* comment actions + threaded replies */
  .cmt-actions{ display:flex; align-items:center; gap:14px; margin-top:6px; flex-wrap:wrap; }
  .cmt-actions button{
    border:none; background:none; padding:0; cursor:pointer;
    font-size:11.5px; font-weight:600; color:var(--faint);
  }
  .cmt-actions button:hover{ color:var(--ink); }
  .cmt-actions button.cmt-del:hover{ color:var(--rose-deep, var(--red-deep)); }  .replies-toggle{
    display:inline-flex; align-items:center; gap:7px; margin-top:8px;
    border:none; background:none; padding:0;
    font-size:12px; font-weight:600; color:var(--blue-deep); cursor:pointer;
  }  .replies{ display:none; margin-top:12px; padding:15px 16px; background:var(--sunken); border-radius:12px; }
  .replies.open{ display:flex; flex-direction:column; gap:14px; }
  .replies .cmt .msg{ font-size:13.5px; padding:10px 13px; }
  .replies .av{ width:22px; height:22px; font-size:9px; }

  /* preview url bar on task */
  .preview-bar{
    display:flex; align-items:center; gap:10px;
    background:var(--panel); border:1px solid var(--line); border-radius:10px;
    padding:9px 13px; margin-bottom:20px;
  }
  .preview-bar .k{ font-family:'IBM Plex Mono',monospace; font-size:9.5px; letter-spacing:.06em; color:var(--faint); flex:none; }
  .preview-bar a.url{
    font-family:'IBM Plex Mono',monospace; font-size:12px; color:var(--blue-deep);
    overflow:hidden; text-overflow:ellipsis; white-space:nowrap; min-width:0;
  }
  .preview-bar a.url:hover{ text-decoration:underline; }
  .preview-bar .right{ margin-left:auto; display:flex; gap:6px; flex:none; }

  /* subtask side drawer */

  /* ---- Popups ----
     A native <dialog>: Esc, focus trapping and the backdrop are the browser's
     job, so the only JS behind these is showModal()/close(). --*/
  .modal{
    width:540px; max-width:calc(100vw - 32px); padding:0; overflow:hidden;
    border:1px solid var(--line); border-radius:14px;
    background:var(--panel); color:var(--text); box-shadow:var(--shadow-pop);
  }
  .modal::backdrop{ background:var(--scrim); }
  .modal::before{ content:""; display:block; height:3px; background:var(--rainbow); }
  .modal-h{ display:flex; align-items:center; gap:12px; padding:15px 20px 13px; border-bottom:1px solid var(--line); }
  .modal-h h3{ font-size:15.5px; }
  .modal-h .x{
    margin-left:auto; flex:none; width:30px; height:30px; border-radius:8px;
    border:1px solid var(--line); background:var(--panel); color:var(--muted); font-size:13px;
  }
  .modal-h .x:hover{ color:var(--ink); border-color:var(--line-strong); }
  .modal-err{ padding:10px 20px; background:var(--red-tint); color:var(--red); font-size:12.5px; }
  .modal-body{ padding:0 20px; max-height:min(60vh, 520px); overflow-y:auto; }
  .modal-foot{
    display:flex; justify-content:flex-end; gap:10px;
    padding:14px 20px 18px; border-top:1px solid var(--line);
  }
  .modal .set-input{ max-width:288px; }

  /* Custom confirmation dialog. */
  .confirm-modal{ width:420px; }
  .confirm-modal .modal-body{ padding:20px 22px 4px; }
  .confirm-msg{ margin:0; font-size:14px; line-height:1.55; color:var(--ink); }
  .confirm-again{ display:flex; align-items:center; gap:8px; margin-top:14px; font-size:12.5px; color:var(--muted); cursor:pointer; }
  .confirm-again[hidden]{ display:none; }
  /* [hidden] needs saying out loud here too - a display of its own would win. */
  .confirm-input{
    display:block; width:100%; margin-top:12px; padding:9px 11px;
    border:1px solid var(--line); border-radius:9px;
    font-family:inherit; font-size:13.5px; color:var(--ink); background:var(--panel);
  }
  .confirm-input:focus{ outline:none; border-color:var(--line-strong); }
  .confirm-input[hidden]{ display:none; }
  /* A token is shown exactly once, so it has to be selectable and it has to
     wrap - a 50-character string that scrolls out of its box is one the reader
     can't copy in a single drag. */
  .token-reveal{
    display:block; width:100%; padding:10px 12px; border-radius:9px;
    background:var(--bg); border:1px dashed var(--line-strong);
    font-family:'IBM Plex Mono',monospace; font-size:12.5px; color:var(--ink);
    word-break:break-all; user-select:all;
  }
  /* The project a task is being raised against, when there is nothing to pick. */
  .proj-fixed{ display:flex; align-items:center; gap:9px; font-size:13.5px; color:var(--ink); font-weight:500; }
  .proj-fixed .pd{ width:9px; height:9px; border-radius:50%; flex:none; }

  /* The toggle is a real checkbox wearing the switch; :has() reads its state. */
  label.switch{ display:inline-block; cursor:pointer; }
  label.switch input{ position:absolute; width:0; height:0; opacity:0; }
  label.switch:has(input:not(:checked)){ background:var(--switch-off); }
  label.switch:has(input:not(:checked))::after{ right:auto; left:2px; }

  /* meta sidebar */
  .meta-card{ padding:4px 0; }
  .meta-row{
    display:flex; align-items:center; justify-content:space-between; gap:10px;
    padding:11px 16px; border-bottom:1px solid var(--line-soft);
  }
  .meta-row:last-child{ border-bottom:none; }
  .meta-row .k{ font-size:12px; color:var(--muted); }
  .meta-row .v{ font-size:12.5px; font-weight:600; color:var(--ink); display:flex; align-items:center; gap:7px; }
  .meta-row .v.mono{ font-family:'IBM Plex Mono',monospace; font-weight:600; }
  .switch{ width:34px; height:20px; border-radius:999px; background:var(--green); position:relative; border:none; flex:none; }
  .switch::after{ content:""; position:absolute; top:2px; right:2px; width:16px; height:16px; border-radius:50%; background:#fff; box-shadow:0 1px 2px rgba(0,0,0,.2); }
  .switch.off{ background:var(--switch-off); }
  .switch.off::after{ right:auto; left:2px; }

  .prog{ padding:14px 16px; border-bottom:1px solid var(--line-soft); }
  .prog .top{ display:flex; justify-content:space-between; font-size:12px; margin-bottom:7px; }
  .prog .top b{ font-family:'IBM Plex Mono',monospace; color:var(--ink); }
  .prog .top span{ color:var(--muted); }

  .tentry{ display:flex; flex-wrap:wrap; align-items:center; gap:10px; padding:9px 16px; border-bottom:1px solid var(--line-soft); font-size:12.5px; }
  .tentry:last-child{ border-bottom:none; }
  .tentry .d{ color:var(--text); flex:1; min-width:0; }
  .tentry .d small{ display:block; font-family:'IBM Plex Mono',monospace; font-size:9.5px; color:var(--faint); }
  .tentry .h{
    font-family:'IBM Plex Mono',monospace; font-weight:600; color:var(--ink);
    flex:none; text-align:right; min-width:74px;
  }
  /* Marks an entry the stopwatch produced rather than one typed in by hand.
     The title on the figure carries what the clock actually read. */
  .tentry .h .tracked{
    display:block; font-size:8.5px; font-weight:600; letter-spacing:.06em;
    text-transform:uppercase; color:var(--faint);
  }
  /* Editing a past entry: the row itself is the toggle - there's nothing else
     on it to click, so an Edit button was one target too many. Its form drops
     in underneath, and the open row is tinted so it's clear which one you're
     changing. */
  .tentry-d{ border-bottom:1px solid var(--line-soft); }
  .tentry-d:last-child{ border-bottom:none; }
  .tentry-d > summary.tentry{ border-bottom:none; cursor:pointer; list-style:none; }
  .tentry-d > summary::-webkit-details-marker{ display:none; }
  .tentry-d > summary.tentry:hover{ background:var(--bg); }
  .tentry-d[open] > summary.tentry{ background:var(--bg); }
  .tentry-form{ display:flex; flex-wrap:wrap; align-items:center; gap:8px; padding:2px 16px 12px; }

  /* ============ NOTES ============ */
  .note-grid{ display:grid; grid-template-columns:repeat(3,1fr); gap:16px; }
  .note-card{ padding:18px; cursor:pointer; transition:transform .15s, box-shadow .15s, border-color .15s; }
  .note-card:hover{ transform:translateY(-2px); box-shadow:var(--shadow-pop); border-color:var(--line-strong); }
  .note-card .nico{
    width:36px; height:36px; border-radius:10px; margin-bottom:14px;
    display:flex; align-items:center; justify-content:center; font-size:16px;
  }
  .note-card h3{ font-size:15px; margin-bottom:5px; }
  .note-card p{ margin:0; font-size:12.5px; color:var(--muted); }
  .note-card .nfoot{
    display:flex; align-items:center; gap:8px; margin-top:14px; padding-top:12px;
    border-top:1px solid var(--line-soft);
    font-family:'IBM Plex Mono',monospace; font-size:10px; color:var(--faint);
  }

  /* single note */
  .note-body{ padding:22px 24px; font-size:13.5px; color:var(--text); }
  .note-body h3{ font-size:14px; margin:18px 0 8px; }
  .note-body h3:first-child{ margin-top:0; }
  /* ============ MY TIME ============ */
  .day-h{
    font-family:'IBM Plex Mono',monospace; font-size:10px; letter-spacing:.08em; color:var(--faint);
    display:flex; justify-content:space-between; padding:14px 18px 8px;
  }
  .day-h b{ color:var(--muted); font-weight:600; }
  .te-line{
    display:flex; align-items:center; gap:12px; padding:11px 18px;
    border-top:1px solid var(--line-soft); font-size:13.5px;
  }
  .te-line .pd{ width:8px; height:8px; border-radius:50%; flex:none; }
  .te-line .t{ font-weight:500; color:var(--task-ink); min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .te-line .note{ color:var(--muted); font-size:12.5px; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .te-line .h{ margin-left:auto; font-family:'IBM Plex Mono',monospace; font-weight:600; color:var(--ink); flex:none; }
  .proj-total{ display:flex; align-items:center; justify-content:space-between; gap:10px; padding:12px 18px; border-bottom:1px solid var(--line-soft); flex-wrap:wrap; }
  .proj-total .pt-info{ display:flex; flex-direction:column; gap:2px; }
  .proj-total .pt-info .k{ font-size:13px; font-weight:600; color:var(--ink); }
  .proj-total .pt-info .v{ font-size:12px; color:var(--muted); }
  .proj-total .pt-acts{ display:flex; gap:8px; }
  .report-note{ padding:11px 18px; font-size:11.5px; color:var(--muted); background:var(--bg); }
  /* export report dropdown */  .em-opt{
    display:block; width:100%; text-align:left; border:none; background:none;
    font-size:13px; color:var(--ink); padding:8px 8px; border-radius:8px; cursor:pointer;
  }
  .em-opt:hover{ background:var(--bg); }
  .em-opt.custom{ color:var(--muted); font-weight:600; }
  /* ============ INVOICES ============ */
  .ihead{
    display:grid; grid-template-columns:110px 1.4fr 1fr 100px 110px 40px; gap:12px;
    padding:11px 18px; font-family:'IBM Plex Mono',monospace; font-size:10px; letter-spacing:.06em; color:var(--faint);
    border-bottom:1px solid var(--line);
  }
  .irow{
    display:grid; grid-template-columns:110px 1.4fr 1fr 100px 110px 40px; gap:12px; align-items:center;
    padding:13px 18px; border-bottom:1px solid var(--line-soft); cursor:pointer; font-size:13px;
  }
  .irow:last-child{ border-bottom:none; }
  .irow:hover{ background:var(--bg); }
  .irow .num{ font-family:'IBM Plex Mono',monospace; font-weight:600; color:var(--ink); }
  .irow .cl{ display:flex; align-items:center; gap:9px; font-weight:500; color:var(--ink); }
  .irow .per{ color:var(--muted); }
  .irow .amt{ font-family:'IBM Plex Mono',monospace; font-weight:600; color:var(--ink); text-align:right; }
  .irow .dl{ text-align:center; color:var(--muted); }

  /* invoice document preview */
  .inv-doc{ padding:30px 34px; }
  .inv-doc .brand{ display:flex; justify-content:space-between; align-items:flex-start; margin-bottom:28px; }
  .inv-doc .brand h2{ font-size:20px; }
  .inv-doc .brand .n{ font-family:'IBM Plex Mono',monospace; font-size:11px; color:var(--muted); text-align:right; }
  .inv-doc .parties{ display:grid; grid-template-columns:1fr 1fr; gap:20px; margin-bottom:26px; }
  .inv-doc .party .k{ font-family:'IBM Plex Mono',monospace; font-size:9.5px; letter-spacing:.08em; color:var(--faint); margin-bottom:5px; }
  .inv-doc .party p{ margin:0; font-size:12.5px; color:var(--text); line-height:1.6; }
  .inv-doc .party p b{ color:var(--ink); }
  .inv-t{ width:100%; border-collapse:collapse; font-size:12.5px; }
  .inv-t th{
    text-align:left; font-family:'IBM Plex Mono',monospace; font-size:9.5px; letter-spacing:.06em;
    color:var(--faint); font-weight:600; padding:8px 0; border-bottom:1px solid var(--ink);
  }
  .inv-t th:last-child,.inv-t td:last-child{ text-align:right; }
  .inv-t td{ padding:10px 0; border-bottom:1px solid var(--line-soft); color:var(--text); }
  .inv-t td:last-child{ font-family:'IBM Plex Mono',monospace; }
  .inv-t tr.total td{ border-bottom:none; border-top:2px solid var(--ink); font-weight:700; color:var(--ink); padding-top:12px; }

  /* ============ FORM BUILDER ============ */  .mock-label{ font-family:'IBM Plex Mono',monospace; font-size:10px; letter-spacing:.06em; color:var(--muted); margin-bottom:6px; }
  .mock-input{ border:1px solid var(--line); border-radius:8px; padding:10px 12px; font-size:13px; color:var(--faint); margin-bottom:14px; background:var(--bg); }
  .mock-select{ display:flex; gap:8px; margin-bottom:14px; flex-wrap:wrap; }
  .mock-pill{ font-size:12px; font-weight:500; border:1px solid var(--line); border-radius:999px; padding:6px 12px; color:var(--muted); }
  .mock-pill.on{ background:var(--amber-tint); border-color:var(--amber-line); color:var(--amber-deep); font-weight:600; }
  .mock-btn{ background:var(--inverse-bg); color:var(--inverse-fg); font-size:13px; font-weight:600; border-radius:8px; padding:10px 16px; display:inline-block; }

  /* ============ SETTINGS ============ */
  .set-card{ margin-bottom:18px; }
  .set-row{
    display:flex; align-items:center; justify-content:space-between; gap:20px;
    padding:14px 18px; border-bottom:1px solid var(--line-soft);
  }
  .set-row:last-child{ border-bottom:none; }
  .set-row .k b{ display:block; font-size:13.5px; color:var(--ink); font-weight:600; }
  .set-row .k small{ font-size:12px; color:var(--muted); }
  .set-input{
    border:1px solid var(--line); border-radius:8px; padding:8px 12px;
    font-size:13px; color:var(--ink); font-family:'Inter',sans-serif; background:var(--panel); min-width:230px;
  }
  .set-input.mono{ font-family:'IBM Plex Mono',monospace; font-size:12px; }
  textarea.set-input{ resize:vertical; line-height:1.5; font-family:'Inter',sans-serif; }

  /* client detail: project blocks */
  .proj-block{ margin-bottom:22px; }
  .proj-block-h{ display:flex; align-items:center; gap:12px; margin-bottom:10px; }
  .proj-block-h h3{ font-size:15px; display:flex; align-items:center; gap:9px; cursor:pointer; }
  .proj-block-h h3 .pd{ width:9px; height:9px; border-radius:50%; }
  .proj-block-h .pb-meta{ font-family:'IBM Plex Mono',monospace; font-size:11px; color:var(--muted); }
  .proj-block-h a{ margin-left:auto; font-size:12.5px; font-weight:600; color:var(--muted); }
  .proj-block-h a:hover{ color:var(--ink); }

  /* client tabs */
  /* new invoice: range + project checks */
  .range-pills{ display:flex; gap:8px; flex-wrap:wrap; margin-bottom:14px; }
  .rp{ font-size:12.5px; font-weight:500; color:var(--muted); border:1px solid var(--line); background:var(--panel); border-radius:999px; padding:6px 13px; cursor:pointer; }
  .rp:hover{ border-color:var(--line-strong); color:var(--ink); }
  .rp.on{ background:var(--inverse-bg); color:var(--inverse-fg); border-color:var(--ink); }  /* bill: notes + filter */
  .bill-note{ padding:10px 18px 0; font-size:12px; color:var(--muted); line-height:1.5; }
  .bill-note b{ color:var(--ink); }  /* bill: project groups with tasks */  .task-check{
    display:flex; align-items:center; gap:10px; padding:8px 18px 8px 30px; cursor:pointer;
    border-top:1px solid var(--bg);
  }
  .task-check:hover{ background:var(--bg); }  .task-check .tc-id{ font-family:'IBM Plex Mono',monospace; font-size:11px; color:var(--faint); flex:none; }
  .task-check .tc-t{ font-size:13px; color:var(--ink); min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }  .task-check .tc-h{ margin-left:auto; font-size:11.5px; color:var(--muted); flex:none; }


/* ===== TaskBite app additions (forms, inline toggles, flash) ===== */
.flash{ background:var(--green-tint); color:var(--green-deep); border:1px solid var(--green-line); border-radius:10px; padding:10px 14px; font-size:13px; margin-bottom:18px; }

/* Toast: it says what happened, offers the way there, and leaves. */
.toast{
  /* Bottom-left of the main area (clear of the sidebar) so it doesn't sit
     under the Priorities button now living bottom-right. */
  position:fixed; left:258px; right:auto; bottom:22px; z-index:90;
  display:flex; align-items:center; gap:12px;
  background:var(--inverse-bg); color:var(--inverse-fg); border-radius:11px;
  padding:11px 12px 11px 16px; font-size:13px;
  box-shadow:0 12px 32px -12px rgba(16,19,23,.5);
  animation:toastIn .18s ease;
}
.toast a{ color:#fff; font-weight:600; text-decoration:underline; text-underline-offset:2px; white-space:nowrap; }
.toast a:hover{ opacity:.8; }
.toast-x{
  display:flex; align-items:center; justify-content:center;
  width:22px; height:22px; padding:0; border:none; border-radius:6px;
  background:rgba(255,255,255,.12); color:#fff;
}
.toast-x:hover{ background:rgba(255,255,255,.22); }
.toast-x .ico{ width:13px; height:13px; }
.toast.gone{ opacity:0; transform:translateY(6px); transition:opacity .25s ease, transform .25s ease; }
@keyframes toastIn{ from{ opacity:0; transform:translateY(8px); } to{ opacity:1; transform:none; } }
@media (prefers-reduced-motion: reduce){
  .toast{ animation:none; }
  .toast.gone{ transition:none; }
}
@media (max-width: 640px){
  .toast{ left:14px; right:14px; bottom:14px; }
}
details.reply-d,details.edit-d,details.add-detail{ display:inline-block; }
details.reply-d > summary,details.edit-d > summary,details.add-detail > summary{ list-style:none; cursor:pointer; }
details > summary::-webkit-details-marker{ display:none; }
.reply-form{ display:flex; flex-direction:column; gap:8px; margin-top:8px; }
.reply-form textarea{ width:100%; min-height:64px; border:1px solid var(--line); border-radius:9px; padding:9px 11px; font-family:'Inter',sans-serif; font-size:13.5px; resize:vertical; }
.reply-form .btn{ align-self:flex-start; }
.inline-add{ display:flex; gap:8px; align-items:center; margin-top:8px; flex-wrap:wrap; }
.inline-add input{ flex:1; min-width:120px; border:1px solid var(--line); border-radius:8px; padding:8px 11px; font-family:'Inter',sans-serif; font-size:13.5px; }
.composer .box textarea{ width:100%; min-height:80px; border:none; outline:none; resize:vertical; font-family:'Inter',sans-serif; font-size:14px; padding:12px; }
.tline{ text-decoration:none; }

/* ===== Responsive hardening (TaskBite dev phase) ===== */
html,body{ max-width: 100%; overflow-x: hidden; }
img,svg,table{ max-width: 100%; }

/* Tabs never cause horizontal page scroll - they scroll themselves */
.tabs{ overflow-x: auto; -webkit-overflow-scrolling: touch; }
.tabs::-webkit-scrollbar{ height: 0; }
.tabs .tab{ flex: none; white-space: nowrap; }

@media (max-width: 1000px) {
  /* On-screen invoice document: stack the From / Bill-to parties */
  .inv-doc .parties{ flex-direction: column !important; gap: 16px !important; }
}

@media (max-width: 720px) {
  .topbar{ align-items: flex-start; }
  .top-actions{ flex-wrap: wrap; }
  .top-actions form{ flex: 1; }
  .top-actions form .btn{ width: 100%; justify-content: center; }
  /* Wide tables (invoice/report on screen) scroll inside their card */
  .inv-doc,.note-body{ overflow-x: auto; }
  .inv-t,table.items{ min-width: 460px; }
  /* Inline add/reply forms wrap cleanly */
  .inline-add{ flex-direction: column; align-items: stretch; }
  .inline-add input,.inline-add .btn{ width: 100%; }
}

/* ===== Attachments ===== */
.cmt-attachments{ display:flex; flex-wrap:wrap; gap:8px; margin-top:8px; }a.attach{ display:inline-flex; align-items:center; gap:6px; font-size:12px; color:var(--muted); background:var(--bg); border:1px solid var(--line); border-radius:8px; padding:5px 10px; text-decoration:none; }
a.attach:hover{ color:var(--ink); border-color:var(--line-strong); }
/* ===== Rich comment composer ===== */
.rc{ border:1px solid var(--line); border-radius:12px; background:var(--panel); overflow:hidden; }
.rc.rc-dragging{ border-color:var(--amber); box-shadow:0 0 0 3px var(--amber-tint); }
.rc-toolbar{ display:flex; align-items:center; gap:2px; padding:6px 8px; border-bottom:1px solid var(--line-soft); background:var(--bg); flex-wrap:wrap; }
.rc-toolbar button,.rc-attach{ display:inline-flex; align-items:center; gap:5px; border:none; background:none; color:var(--muted); font-size:13px; font-weight:600; padding:5px 8px; border-radius:7px; cursor:pointer; font-family:'Inter',sans-serif; }
.rc-toolbar button:hover,.rc-attach:hover{ background:var(--line-soft); color:var(--ink); }
.rc-sep{ width:1px; height:18px; background:var(--line); margin:0 4px; }
.rc-editor{ min-height:80px; max-height:320px; overflow-y:auto; padding:12px 14px; font-size:14px; line-height:1.55; color:var(--ink); outline:none; }
.rc-editor:empty:before{ content:attr(data-placeholder); color:var(--faint); }
.rc-empty .rc-editor:before{ content:attr(data-placeholder); color:var(--faint); }
.rc-empty .rc-editor:not(:empty):before{ content:''; }
.rc-editor p{ margin:0 0 8px; } .rc-editor ul,.rc-editor ol{ margin:0 0 8px; padding-left:22px; }
.rc-editor a{ color:var(--blue-deep); }

/* "mentioned" tag on an attention row - you were @-called-out here. */
.pill.mentioned{ background:var(--blue-tint); color:var(--blue-deep); border:1px solid var(--blue-line); }

/* @-mention chips - in a comment bubble and inside the editor while typing. */
.mention{
  display:inline; padding:1px 5px; border-radius:5px;
  background:var(--blue-tint); color:var(--blue-deep); font-weight:600; white-space:nowrap;
}
.rc-editor .mention{ cursor:default; }
/* the autocomplete dropdown (positioned in JS, fixed to the caret) */
.mention-menu{
  position:fixed; z-index:80; min-width:200px; max-width:280px;
  background:var(--panel); border:1px solid var(--line); border-radius:10px;
  box-shadow:0 12px 32px -12px rgba(16,19,23,.24); padding:5px;
}
.mention-opt{
  display:flex; align-items:center; gap:8px; padding:7px 9px; border-radius:7px;
  font-size:13px; color:var(--ink); cursor:pointer;
}
.mention-opt.active,.mention-opt:hover{ background:var(--bg); }
.mention-av{
  width:22px; height:22px; border-radius:50%; flex:none;
  background:var(--inverse-bg); color:var(--inverse-fg); font-size:9px; font-weight:700;
  display:flex; align-items:center; justify-content:center;
}

/* Sidebar pickers (assignee, add-follower): a <details> dropdown styled like
   the @-mention list, avatars and all. */
.picker{ position:relative; }
.picker > summary{ list-style:none; cursor:pointer; }
.picker > summary::-webkit-details-marker{ display:none; }
.picker-trigger{ display:inline-flex; align-items:center; gap:7px; font-size:12.5px; font-weight:600; color:var(--ink); }
.picker-trigger .caret{ color:var(--faint); font-size:10px; }
.picker-menu{
  position:absolute; right:0; top:calc(100% + 6px); z-index:40;
  min-width:190px; max-height:260px; overflow-y:auto;
  background:var(--panel); border:1px solid var(--line); border-radius:10px;
  box-shadow:0 12px 32px -12px rgba(16,19,23,.24); padding:5px;
}
.picker-opt{
  display:flex; align-items:center; gap:8px; width:100%; text-align:left;
  border:none; background:none; padding:7px 9px; border-radius:7px;
  font-size:13px; color:var(--ink); cursor:pointer;
}
.picker-opt:hover,.picker-opt.on{ background:var(--bg); }
/* The status picker sits by the title on the left, so its menu opens rightward. */
.status-picker{ position:relative; }
.status-picker .picker-menu{ left:0; right:auto; min-width:150px; }
.status-picker .picker-opt{ padding:5px 7px; }
.status-picker .picker-trigger .pill{ cursor:pointer; }

/* Priority flag (⚑) on task rows and in the sidebar picker, coloured by level. */
.prio{ font-size:12px; line-height:1; flex:none; }
.prio-urgent{ color:var(--red); }
.prio-high{ color:var(--amber-deep, #E8890C); }
.prio-normal{ color:var(--faint); }
.prio-low{ color:#8BA3C7; }

/* Followers as a row of avatars; click one to remove, + to add. */
.follower-row{ display:flex; align-items:center; gap:6px; flex-wrap:wrap; justify-content:flex-end; }
.follower{ border:none; background:none; padding:0; margin:0; cursor:pointer; position:relative; line-height:0; border-radius:50%; }
.follower::after{
  content:"\00d7"; position:absolute; top:-3px; right:-3px; width:14px; height:14px;
  border-radius:50%; background:var(--rose-deep,var(--red-deep)); color:#fff; font-size:10px;
  display:none; align-items:center; justify-content:center; line-height:1;
}
.follower:hover::after{ display:flex; }
.follower-plus{
  width:26px; height:26px; border-radius:50%; border:1px dashed var(--line);
  display:flex; align-items:center; justify-content:center; color:var(--muted);
  font-size:15px; cursor:pointer; list-style:none;
}
.follower-plus::-webkit-details-marker{ display:none; }
.follower-plus:hover{ border-color:var(--muted); color:var(--ink); }

/* Inline-editable description under the task title. */
.desc-form{ margin-bottom:20px; }
.desc-edit{
  width:100%; display:block; box-sizing:border-box; resize:vertical; min-height:52px;
  background:var(--panel); border:1px solid var(--line); border-radius:12px;
  padding:14px 16px; font-family:'Inter',sans-serif; font-size:13.5px; line-height:1.55; color:var(--text);
}
.desc-edit::placeholder{ color:var(--faint); }
.desc-edit:focus{ outline:none; border-color:var(--line-strong); box-shadow:0 4px 16px -8px rgba(16,19,23,.12); }

/* Small inline inputs in the meta sidebar (due date, estimate) - blend in until
   hovered/focused so the row still reads as a value. */
.meta-input{
  border:1px solid transparent; background:none; border-radius:6px; padding:2px 6px;
  font-size:12.5px; font-weight:600; color:var(--ink); font-family:inherit;
}
.meta-input:hover{ border-color:var(--line); }
.meta-input:focus{ outline:none; border-color:var(--line-strong); background:var(--panel); }
.meta-input.mono{ font-family:'IBM Plex Mono',monospace; }
.rc-thumbs{ display:flex; flex-wrap:wrap; gap:8px; padding:0 12px 12px; }
.rc-thumbs:empty{ padding:0; }
.rc-thumb{ position:relative; width:64px; height:64px; border-radius:9px; overflow:hidden; border:1px solid var(--line); background:var(--bg); }
.rc-thumb img{ width:100%; height:100%; object-fit:cover; }
.rc-thumb.is-file{ display:flex; align-items:center; justify-content:center; font-size:9px; text-align:center; padding:4px; color:var(--muted); word-break:break-word; }
.rc-x{ position:absolute; top:2px; right:2px; width:18px; height:18px; border:none; border-radius:50%; background:rgba(16,19,23,.7); color:#fff; font-size:13px; line-height:1; cursor:pointer; display:flex; align-items:center; justify-content:center; }

/* thread image thumbnails (click to enlarge) */
.cmt-thumb{ display:block; width:88px; height:88px; border-radius:10px; overflow:hidden; border:1px solid var(--line); cursor:zoom-in; }
.cmt-thumb img{ width:100%; height:100%; object-fit:cover; display:block; }

/* lightbox */
.lightbox{ position:fixed; inset:0; background:rgba(16,19,23,.85); display:none; align-items:center; justify-content:center; z-index:1000; padding:32px; cursor:zoom-out; }
.lightbox.open{ display:flex; }
.lightbox img{ max-width:100%; max-height:100%; border-radius:8px; box-shadow:0 20px 60px rgba(0,0,0,.5); }

/* client portal: project cards on the home overview */
.proj-card{ display:flex; align-items:center; gap:13px; padding:16px 18px; margin-bottom:11px; background:var(--panel); border:1px solid var(--line); border-radius:13px; text-decoration:none; transition:border-color .12s, box-shadow .12s, transform .12s; }
.proj-card:hover{ border-color:var(--line-strong); box-shadow:0 6px 20px -12px rgba(16,19,23,.18); transform:translateY(-1px); }
.proj-card .pd{ width:11px; height:11px; border-radius:50%; flex:none; }
.proj-card .pc-main{ display:flex; flex-direction:column; gap:3px; min-width:0; }
.proj-card .pc-main b{ font-size:15px; color:var(--ink); }
.proj-card .pc-main small{ font-size:12px; color:var(--muted); font-family:'IBM Plex Mono',monospace; }
.proj-card .pc-arrow{ margin-left:auto; color:var(--faint); font-size:18px; flex:none; }
.proj-card:hover .pc-arrow{ color:var(--amber-deep); }

/* internal-note checkbox on the composer */
.internal-toggle{ display:inline-flex; align-items:center; gap:7px; font-size:12.5px; font-weight:600; color:var(--muted); cursor:pointer; user-select:none; padding:6px 10px; border:1px solid var(--line); border-radius:8px; transition:background .12s, border-color .12s, color .12s; }
.internal-toggle:hover{ border-color:var(--line-strong); }
.internal-toggle input{ accent-color:var(--amber-deep); width:15px; height:15px; cursor:pointer; }
.internal-toggle small{ font-weight:400; color:var(--faint); }
.internal-toggle .lock{ filter:grayscale(1); opacity:.6; }
.rc-internal .internal-toggle{ background:var(--amber-tint); border-color:var(--amber-line); color:var(--amber-deep); }
.rc-internal .internal-toggle small{ color:var(--amber-deep); }
.rc-internal .internal-toggle .lock{ filter:none; opacity:1; }

/* internal comments: clearly marked, amber-tinted with a left border */
.cmt.internal .msg{ background:var(--amber-tint); border-color:var(--amber-line); }
.cmt.internal .body{ position:relative; }
.internal-tag{ display:inline-flex; align-items:center; gap:4px; font-size:10.5px; font-weight:700; letter-spacing:.02em; color:var(--amber-deep); background:var(--amber-tint); border:1px solid var(--amber-line); padding:1px 7px; border-radius:20px; text-transform:uppercase; }

/* delivery channel toggles on the composer */
.chan-toggles{ display:inline-flex; align-items:center; gap:12px; }
.chan-toggles.disabled{ opacity:.4; pointer-events:none; }
.chan-toggle{ display:inline-flex; align-items:center; gap:6px; font-size:12.5px; font-weight:600; color:var(--muted); cursor:pointer; user-select:none; }
.chan-toggle input{ accent-color:var(--amber-deep); width:15px; height:15px; cursor:pointer; }

/* Slack provenance + delivery marks in a comment header */
.via-slack{ font-size:10.5px; font-weight:700; letter-spacing:.02em; color:var(--violet); background:var(--violet-tint); padding:1px 7px; border-radius:20px; text-transform:uppercase; }
.slack-link{ font-size:12px; color:var(--muted); text-decoration:none; font-weight:700; }
.slack-link:hover{ color:var(--amber-deep); }
.deliv{ font-size:11px; color:var(--faint); }
.cmt-resend{ border:none; background:none; color:var(--muted); font-size:11.5px; font-weight:600; cursor:pointer; padding:0; }
.cmt-resend:hover{ color:var(--amber-deep); }

/* inline task rename */
.rename-btn{ border:none; background:none; color:var(--faint); cursor:pointer; font-size:15px; line-height:1; padding:5px 7px; border-radius:7px; align-self:flex-start; margin-top:4px; }
.rename-btn:hover{ color:var(--amber-deep); background:var(--line-soft); }
.rename-form{ display:flex; gap:8px; align-items:center; flex-wrap:wrap; margin:2px 0 8px; }
/* a set display: overrides the UA [hidden] rule, so restore it explicitly */
.rename-form[hidden]{ display:none; }
.task-title-row[hidden]{ display:none; }
.rename-form input{ font-family:'Space Grotesk',sans-serif; font-size:24px; font-weight:700; letter-spacing:-.01em; padding:5px 11px; border:1px solid var(--line); border-radius:10px; color:var(--ink); min-width:280px; max-width:100%; }
.rename-form input:focus{ outline:none; border-color:var(--amber); box-shadow:0 0 0 3px var(--amber-tint); }

/* compact inline selects + watcher chips in the task meta sidebar */
/* merge-contact control on the client page */
.merge-d summary{ list-style:none; cursor:pointer; }
.merge-d summary::-webkit-details-marker{ display:none; }
.merge-d[open] summary{ color:var(--amber-deep); }

/* ============================================================================
   ONE ROW SHAPE, EVERYWHERE
   ----------------------------------------------------------------------------
   Every list in the app is the same idea - a stack of things you can act on -
   so they read as one component rather than five. Each row is a discrete
   capsule with its own fill and ring, not a line separated by a divider.

   All of it comes off the --row-* tokens in the block at the top of this file,
   the same ones the dashboard widgets use: change --row-radius once and every
   list changes with it.

   Two radii, because a row that opens is not a row that does not. Single-line
   rows take the pill; anything that expands in place (a time entry with its
   editor, an activity line that can wrap) takes the softer corner, since a
   999px radius around a growing box reads as a mistake.
   ========================================================================== */
:root{ --row-radius-soft:13px; }

.row-task,
.tline:not(.tline-head),
.sub-line,
.feed-item,
.search-res,
.tentry,
.tentry-d{
  background:var(--row-bg);
  border:1px solid var(--row-line);
  border-radius:var(--row-radius);
  margin-bottom:var(--row-gap);
  transition:background .12s ease, border-color .12s ease;
}

.feed-item,
.tentry,
.tentry-d{ border-radius:var(--row-radius-soft); }

/* The dividers these rows used to rely on. */
.tline:not(.tline-head):last-child,
.sub-line:last-child,
.feed-item:last-child,
.search-res:last-child,
.tentry:last-child,
.tentry-d:last-child{ margin-bottom:0; }
.feed-item + .feed-item{ border-top:1px solid var(--row-line); }

/* A summary inside its own capsule is the capsule's header, not a second one. */
.tentry-d > .tentry{
  background:none; border:none; border-radius:0; margin:0;
}

.tline:not(.tline-head):hover,
.sub-line:hover,
.search-res:hover, .search-res.active,
.tentry-d > summary.tentry:hover{
  background:var(--row-bg-hover); border-color:var(--line-strong);
}
.tentry-d > summary.tentry:hover{ border:none; }
/* Unread keeps the flag ring here too, as it does on the dashboard. */
.tline.has-unread{ border-color:var(--row-flag-line); }

/* Capsules need air from the card edge; these lists used to run edge to edge. */
.tlist, .sub-list{ padding:0 12px 12px; }
.tlist .tline-head{ margin:0 -12px 6px; }
.feed{ padding:6px 12px 12px; }

/* The subtask elbow was drawn against a flush row; with a gap between capsules
   it has nothing to attach to, so the indent alone carries the nesting. */
.tline.sub{ padding-left:34px; }
.tline.sub::before{ display:none; }

/* The time-entries toggle is a list, not an inline "add" control. .add-detail
   is display:inline-block so those shrink-wrap their label, which left every
   entry sized to its own text instead of the card. Ten other places rely on
   that, so this is a modifier rather than a change to the shared rule. */
details.add-detail.entries-d{ display:block; width:100%; padding:0 12px 12px; }
.entries-d > summary.add-line{ margin:0 -12px 8px; }
.entries-d .tentry,
.entries-d .tentry-d{ width:100%; }
/* The figure column is fixed so every row's hours line up down the list; the
   description takes whatever is left. */
.tentry .d{ flex:1 1 auto; min-width:0; }

/* ============================================================================
   PERSONAL TODO LIST
   ----------------------------------------------------------------------------
   Deliberately lighter than a task row: no client, no status, no assignee. It
   is the thing you wrote down so you could stop holding it in your head, and it
   should look like one line of handwriting, not a record.
   ========================================================================== */
.todo-body{ padding:0 12px 12px; }

/* flex-start, not center: once the text runs to a second line the circle should
   stay level with the first one, the way it would on paper. */
.todo-add{ display:flex; align-items:flex-start; gap:10px; padding:2px 4px 10px; }
.todo-add textarea{
  flex:1; min-width:0; border:none; background:none; outline:none; resize:none;
  font-family:inherit; font-size:13.5px; line-height:20px; color:var(--task-ink);
  padding:0; margin:0; overflow:hidden;
  /* Grown to fit by app.js; this is the floor and the ceiling. */
  min-height:20px; max-height:8lh;
}
.todo-add textarea::placeholder{ color:var(--faint); }
/* Lines the field up with the rows below it, so typing looks like writing the
   next line rather than filling in a form.
   min-height:0 is load-bearing: `.todo-add > *` below forces 20px on every
   child, which is what stretched the old 17px circle into an ellipse. */
.todo-add .todo-add-ico{
  flex:none; width:16px; height:16px; min-height:0;
  align-self:flex-start; margin-top:2px; color:var(--faint);
}

.todo-row{
  display:flex; align-items:flex-start; gap:10px;
  padding:7px 4px; border-radius:var(--row-radius-soft);
}
/* The circle and the controls stay put; only the text grows. */
/* Every child gets the text's own 20px line box and centres inside it, so
   the grip, the circle and the first line of text share one baseline
   however many lines the text runs to. */
.todo-row > *, .todo-row form{ min-height:20px; display:flex; align-items:center; }
.todo-row .todo-text{ display:block; }
.todo-add{ align-items:flex-start; }
.todo-add > *{ min-height:20px; display:flex; align-items:center; }
.todo-add textarea{ display:block; }
.todo-row:hover{ background:var(--row-bg-hover); }

/* The circle. A real button, so it is reachable by keyboard and says what it
   does - the whole interaction of this widget is pressing it. */
.todo-box{
  flex:none; width:17px; height:17px; border-radius:50%; cursor:pointer;
  border:1.5px solid var(--control-line); background:none; padding:0;
  display:inline-flex; align-items:center; justify-content:center;
  font-size:9px; line-height:1; color:transparent;
  transition:border-color .12s ease, background .12s ease, color .12s ease;
}
.todo-box:hover{ border-color:var(--green); }
.todo-box.on{ background:var(--green); border-color:var(--green); color:#fff; }

/* Wraps rather than truncating: a note you cannot finish reading is no use, and
   unlike a task title there is nothing to click through to for the rest of it.
   anywhere covers a pasted URL with no spaces to break on. */
.todo-text{
  flex:1; min-width:0; font-size:13.5px; line-height:20px; color:var(--task-ink);
  white-space:pre-wrap; overflow-wrap:anywhere;
}
.todo-row.done .todo-text{ color:var(--muted); text-decoration:line-through; }
.todo-when{ flex:none; font-size:10px; color:var(--faint); }

.todo-x{
  flex:none; border:none; background:none; cursor:pointer; color:var(--faint);
  padding:3px; border-radius:6px; line-height:0; opacity:0;
  transition:opacity .12s ease, color .12s ease, background .12s ease;
}
.todo-row:hover .todo-x, .todo-x:focus-visible{ opacity:1; }
.todo-x:hover{ color:var(--red); background:var(--red-tint); }
.todo-x svg{ width:13px; height:13px; }

.todo-empty{ padding:14px 4px; font-size:12.5px; color:var(--faint); }
.todo-h-right{ display:flex; align-items:center; gap:10px; }
.todo-arch-link{ font-size:11.5px; font-weight:600; color:var(--muted); }
.todo-arch-link:hover{ color:var(--ink); text-decoration:underline; text-underline-offset:2px; }
.todo-arch{ margin-top:10px; padding-top:10px; border-top:1px solid var(--line-soft); }
.todo-arch-h{
  font-family:'IBM Plex Mono',monospace; font-size:9px; letter-spacing:.07em;
  text-transform:uppercase; color:var(--faint); padding:0 4px 6px;
}

/* Task titles sit at 500 on the light theme. On the dark one the same weight
   in near-white reads heavier than it measures, so it steps back to 400 -
   unread still lifts to 650 and stays the thing that stands out. */
[data-theme="dark"] .row-task .t{ font-weight:400; }
[data-theme="dark"] .row-task.unread .t{ font-weight:650; }

/* A link inside a note. Underlined rather than coloured: the line already sits
   in a list of plain text, and colour alone is not a reliable signal. */
.todo-link{
  color:var(--blue-deep); text-decoration:underline; text-underline-offset:2px;
  text-decoration-thickness:1px;
}
.todo-link:hover{ color:var(--blue); }
/* Marks the ones that leave TaskBite - an internal link keeps you here. */
.todo-link-ext{ font-size:9px; margin-left:3px; opacity:.7; }

/* ---------- FEATURED PROJECTS PICKER ----------
   Star projects from the sidebar without going anywhere. Rendered from the tree
   the composer already loaded, so opening it costs no request. */
.feat-pick{ position:relative; }
.feat-pick > summary{ list-style:none; cursor:pointer; }
.feat-pick > summary::-webkit-details-marker{ display:none; }
.feat-pick[open] > summary{ color:var(--muted); background:var(--bg); }
/* Fixed, not absolute: the sidebar scrolls, and anything overflow:auto clips
   its absolutely-positioned children - the menu was being cut off at the
   sidebar's edge. Placed by app.js against the summary's own rectangle, since
   fixed positioning has no anchor of its own. */
.feat-pop{
  position:fixed; z-index:70; width:270px;
  left:calc(var(--side-inset) + var(--side-width) + 10px);
  top:var(--side-inset);
  background:var(--panel); border:1px solid var(--line); border-radius:12px;
  box-shadow:var(--shadow-pop); overflow:hidden;
  opacity:0; pointer-events:none;
}
.feat-pop.placed{ opacity:1; pointer-events:auto; }
.feat-h{
  display:flex; align-items:center; justify-content:space-between; gap:10px;
  padding:10px 12px; border-bottom:1px solid var(--line-soft); font-size:12px;
}
.feat-h a{ font-size:11px; font-weight:600; color:var(--muted); }
.feat-h a:hover{ color:var(--ink); text-decoration:underline; text-underline-offset:2px; }
.feat-list{ max-height:min(56vh, 360px); overflow-y:auto; padding:5px; }
/* Clients collapse in the picker: with twenty of them, every project
   listed at once is a wall rather than a menu. */
.feat-client-d > summary{ list-style:none; cursor:pointer; }
.feat-client-d > summary::-webkit-details-marker{ display:none; }
.feat-client{
  display:flex; align-items:center; gap:7px; padding:7px 8px; border-radius:8px;
  font-size:10px; font-weight:700; letter-spacing:.05em; text-transform:uppercase;
  color:var(--faint);
}
.feat-client:hover{ background:var(--bg); color:var(--muted); }
.feat-client .pd{ width:7px; height:7px; border-radius:50%; flex:none; }
.feat-cname{ min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
/* How many of this client's projects you have pinned, so a closed row still
   says whether there is anything of yours inside it. */
.feat-count{
  flex:none; font-size:9px; font-weight:700; letter-spacing:0;
  color:var(--star-on); background:var(--amber-tint); border-radius:999px; padding:1px 6px;
}
.feat-caret{
  margin-left:auto; width:13px; height:13px; flex:none; color:var(--faint);
  stroke-width:2; transition:transform .18s;
}
.feat-client-d:not([open]) .feat-caret{ transform:rotate(-90deg); }
.feat-client-d .feat-row{ padding-left:22px; }
.feat-row{
  display:flex; align-items:center; gap:8px; width:100%; text-align:left;
  border:none; background:none; padding:6px 8px; border-radius:8px; cursor:pointer;
  font-family:inherit; font-size:12.5px; color:var(--text);
}
.feat-row:hover{ background:var(--bg); color:var(--ink); }
.feat-star{ flex:none; font-size:12px; color:var(--faint); line-height:1; }
.feat-star::before{ content:"\2606"; }
.feat-row.on .feat-star::before{ content:"\2605"; }
.feat-row.on .feat-star{ color:var(--star-on); }
.feat-row.on{ font-weight:600; color:var(--ink); }
.feat-name{ min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.feat-empty{ padding:14px; text-align:center; font-size:12px; color:var(--muted); }

/* The task page's track button. One element in both states, so JS can correct
   it when the stopwatch stops somewhere else - see timer.js markTracked(). */
.track-btn .tb-on{ display:none; }
.track-btn.on .tb-on{ display:inline; }
.track-btn.on .tb-idle{ display:none; }
.track-btn.on{
  color:var(--timer-ink); border-color:var(--timer-line); background:var(--timer-bg);
}

/* The project task list uses .tline, which has its own column widths. */
.tline .right .tcol-timer{ width:22px; justify-content:center; }
.tline:hover .timer-start, .tline .timer-start.on{ opacity:1; }
/* Priorities rows put the play button inline rather than in a column. */
.card-tint .timer-start{ color:var(--widget-muted); }
.card-tint .row-task:hover .timer-start{ opacity:1; }
.card-tint .timer-start:hover{ background:var(--widget-row-bg); color:var(--widget-ink); }

/* ===== Import mapping preview table ===== */
.imp-table{ border-collapse:collapse; font-size:12px; white-space:nowrap; }
.imp-table th,.imp-table td{ border:1px solid var(--line); padding:6px 9px; text-align:left; }
.imp-table th{ background:var(--bg); color:var(--muted); font-weight:600; }
.imp-table td{ color:var(--text); }

/* ===== Files ===== */
.file-filters{ display:flex; flex-wrap:wrap; gap:8px; align-items:center; }
.file-filters .set-input{ max-width:170px; font-size:12.5px; padding:7px 10px; }
.file-row{
  display:flex; align-items:center; gap:13px;
  padding:9px 4px; border-radius:var(--row-radius-soft);
}
.file-row:hover{ background:var(--row-bg-hover); }
.file-thumb{
  flex:none; width:42px; height:42px; border-radius:9px; overflow:hidden;
  border:1px solid var(--line); background:var(--bg);
  display:flex; align-items:center; justify-content:center; text-decoration:none;
}
.file-thumb img{ width:100%; height:100%; object-fit:cover; }
.file-thumb.is-doc span{
  font-family:'IBM Plex Mono',monospace; font-size:10px; font-weight:600; color:var(--muted);
}
.file-main{ flex:1; min-width:0; display:flex; flex-direction:column; gap:2px; }
.file-name{
  font-size:13.5px; font-weight:500; color:var(--task-ink); text-decoration:none;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.file-name:hover{ text-decoration:underline; }
.file-meta{ font-size:11.5px; color:var(--faint); }
.file-where{
  flex:none; max-width:38%; display:flex; flex-direction:column; gap:2px;
  text-align:right; font-size:12.5px;
}
.file-where a{ color:var(--muted); text-decoration:none; }
.file-where a:hover{ color:var(--ink); }
.file-proj{ font-size:11px; color:var(--faint); }
@media (max-width:760px){
  .file-where{ display:none; }
  .file-filters .set-input{ max-width:none; flex:1 1 140px; }
}

/* ===== Projects page: two columns ===== */
.proj-cols{ display:grid; grid-template-columns:1fr 1fr; gap:8px 14px; align-items:start; }
.proj-cols .row-task{ margin-bottom:0; }
@media (max-width:900px){
  .proj-cols{ grid-template-columns:1fr; }
}
/* A project row on the client page is the whole link, not a link inside a row. */
.proj-row{ text-decoration:none; cursor:pointer; }
.proj-row .pd{ width:9px; height:9px; border-radius:50%; flex:none; }
.proj-row .t{ color:var(--task-ink); font-weight:500; }
.proj-row:hover .t{ color:var(--ink); }

/* ===== Comment reactions ===== */
/* Reactions sit left and push everything after them right - Reply, Edit and
   Delete end up together on the far side without needing a wrapper. */
.cmt-react{ display:flex; align-items:center; gap:5px; margin-right:auto; }
.react-chip{
  display:inline-flex; align-items:center; gap:4px;
  border:1px solid var(--line); background:var(--panel); border-radius:999px;
  padding:2px 8px; font-size:12px; line-height:1.5; cursor:pointer; color:var(--text);
}
.react-chip span{ font-size:11px; font-weight:600; color:var(--muted); }
.react-chip:hover{ border-color:var(--line-strong); }
.react-chip.mine{ background:var(--amber-tint,#fdf3e2); border-color:var(--amber-deep); }
.react-chip.mine span{ color:var(--amber-deep); }
.react-pick{ position:relative; }
.react-pick > summary{
  list-style:none; cursor:pointer; font-size:13px; line-height:1;
  color:var(--faint); border:1px solid transparent; border-radius:999px; padding:3px 6px;
}
.react-pick > summary::-webkit-details-marker{ display:none; }
.react-pick > summary:hover{ color:var(--ink); border-color:var(--line); }
.react-pop{
  position:absolute; bottom:calc(100% + 6px); left:0; z-index:30;
  display:flex; gap:2px; padding:5px 6px;
  background:var(--panel); border:1px solid var(--line); border-radius:11px;
  box-shadow:var(--shadow-card);
}
.react-opt{
  border:none; background:none; cursor:pointer; font-size:16px; line-height:1;
  padding:3px 5px; border-radius:7px;
}
.react-opt:hover{ background:var(--bg); }
/* An open reply form takes a row of its own rather than being squeezed into
   the right-hand group it is anchored in. */
.cmt-actions .reply-d[open]{ flex:1 1 100%; }
