/* uBoard — every style in the app.
 *
 * Lifted out of index.html unchanged: the file was 1,500 lines of CSS above 9,000 lines of
 * JavaScript, and neither could be read without scrolling past the other. Nothing here was
 * rewritten, and tests/split-test.ts checks that it is still byte-for-byte what the <style> block
 * held.
 */
  :root {
    --purple: #7b68ee;
    --purple-dark: #5b4bd4;
    --purple-light: #efeafd;
    --bg: #f9f9fb;
    --panel: #ffffff;
    --border: #e7e5f0;
    --table-rule: #bdbaca;     /* the table view's lines: a quiet grey (Andrey, 25 Sep 2026: thinner and greyer than black) */
    --title-text: #1a1730;     /* a task's name: a shade stronger than body text */
    --text: #292640;
    --text-soft: #4d4a63;
    --hint: #8b87a0;
    --placeholder-icon: #b9b6c8;
    --sidebar-bg: #0a0a0a;
    --sidebar-text: #a3a3a3;
    --sidebar-hover: #222222;
    --sidebar-active: #2a2a2a;
    --todo: #87909e;
    --inprogress: #1090e0;
    --done: #008844;
    --urgent: #9c2b3a;
    --high: #f8ae00;
    --normal: #0ea5c9;
    --low: #87909e;
    /* Surfaces that used to be written as literal whites and blacks, so the dark theme can change
       them in one place. */
    --text-strong: #000000;
    --ink: #111111;              /* the black buttons */
    --ink-text: #ffffff;
    --glass: rgba(255, 255, 255, 0.62);
    --glass-strong: rgba(255, 255, 255, 0.86);
    --ch-scrim: rgba(20, 15, 40, 0.13);
    --scroll-thumb: rgba(20, 15, 40, 0.28);
    --code-tint: rgba(20, 15, 40, 0.07); --code-tint-mine: rgba(255, 255, 255, 0.16);
    --quote-rule: rgba(20, 15, 40, 0.22); --quote-rule-mine: rgba(255, 255, 255, 0.4);
    --glass-edge: rgba(255, 255, 255, 0.6);
    --main-surface: rgba(255, 255, 255, 0.92);
    /* The menu's own tone. Under a light theme it is the one dark thing on the screen; under a
       dark one the two trade places (see the dark blocks below), so both live here rather than
       being written into #sidebar. */
    --side-bg: linear-gradient(180deg, rgba(3, 3, 5, 0.82) 0%, rgba(0, 0, 0, 0.90) 100%);
    --side-edge: rgba(255, 255, 255, 0.12);
    --side-hover: rgba(255, 255, 255, 0.07); --side-active: rgba(255, 255, 255, 0.13);
    --row-hover: #faf9ff;
    --row-picked: #f3f1fd;
    --tab-active-bg: #f0eff4;
    --bubble-mine: #e2eaf3;
    --input-bg: #ffffff;
    --page-bg:
      radial-gradient(760px 520px at 5% 8%, rgba(123, 104, 238, 0.42), transparent 62%),
      radial-gradient(640px 540px at 12% 90%, rgba(16, 144, 224, 0.34), transparent 64%),
      radial-gradient(820px 560px at 88% 16%, rgba(214, 69, 93, 0.14), transparent 62%),
      radial-gradient(700px 520px at 78% 92%, rgba(47, 158, 68, 0.12), transparent 64%),
      linear-gradient(140deg, #eceaf4 0%, #f4f3f8 45%, #eef1f7 100%);
    --chip-bg: #eeecf4;
    --chip-fg: #625d7a;
    --chip-fg-soft: #7b7690;
    --col-bg: #f5f3fb;
    --count-bg: #f0eef8;
    --swatch-hover: #ececec;
    --avatar-bg: #e3e3e3;
    --track-bg: #e6e6e6;
    --row-hover-soft: #eeeef3;
    --row-hover-strong: #e4e4ec;
    --row-linked: #fcfcfe;
    --row-picked-hover: #ebe8fb;
    --warn-bg: #fff5e6;
    --warn-bg-2: #fff7ed;
    --warn-bg-3: #fff8e6;
    --warn-bg-4: #fff4e0;
    --mark-bg: #fff3bf;
    --warn-fg: #8a4f00;
    --warn-fg-2: #b45309;
    --warn-edge: #fed7aa;
    --warn-edge-2: #f3d38a;
    --ok-bg: #e9f7ee;
    --ok-bg-2: #e9f7ef;
    --ok-bg-3: #e6f6ee;
    --ok-fg: #1c6b38;
    --ok-fg-2: #1e6b41;
    --info-bg: #eef2fe;
    --info-bg-2: #eaf2fe;
    --info-fg: #2a3f8f;
    --info-fg-2: #1b4f9c;
    --danger-bg: #fdecec;
    --ref-hover: #e4dbff;
    --tpl-hover: #f6f3ff;
    --check-edge: #c9c5d8;
    --avatar-fg: #555;
    color-scheme: light;
  }
  /* The dark theme. Chosen in Settings, or — the default — whatever the device is set to: the
     media query applies it unless somebody picked light, and data-theme="dark" applies it whatever
     the device says. The two blocks hold the same values; CSS has no way to say "either". A dark
     palette of its own rather than the light one inverted: surfaces step up in lightness the higher
     they sit, text is off-white, and the accent is lifted so it still reads on a dark ground. */
  @media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
      --purple: #8f80f7; --purple-dark: #b7adff; --purple-light: #2b2644;
      --bg: #17161f; --panel: #1f1e29; --border: #302e3e; --table-rule: #524f68; --title-text: #f8f7fd;
      --text: #ecebf4; --text-soft: #c3c0d4; --hint: #8e8aa5; --placeholder-icon: #5f5c73;
      --text-strong: #ffffff; --ink: #ecebf4; --ink-text: #15141c;
      --glass: rgba(31, 30, 41, 0.62); --glass-strong: rgba(31, 30, 41, 0.86); --glass-edge: rgba(255, 255, 255, 0.08);
      --ch-scrim: rgba(0, 0, 0, 0.30);
    --scroll-thumb: rgba(255, 255, 255, 0.26);
      --code-tint: rgba(255, 255, 255, 0.09); --code-tint-mine: rgba(255, 255, 255, 0.12);
      --quote-rule: rgba(255, 255, 255, 0.24); --quote-rule-mine: rgba(255, 255, 255, 0.34);
      /* Dark theme, the other way round from the light one: the working area is the darker grey
         and the menu the lighter, so the eye rests on the page being worked in and the menu reads
         as a surface laid over it. */
      --main-surface: rgba(17, 16, 23, 0.94);
      --side-bg: linear-gradient(180deg, rgba(10, 10, 14, 0.88) 0%, rgba(4, 4, 8, 0.94) 100%);
      --side-edge: rgba(255, 255, 255, 0.09);
      --side-hover: rgba(255, 255, 255, 0.08); --side-active: rgba(255, 255, 255, 0.15);
      --row-hover: #25242f; --row-picked: #2a2641; --tab-active-bg: #2b2a37;
      --bubble-mine: #2c4461; --input-bg: #262532;
      --page-bg:
        radial-gradient(760px 520px at 5% 8%, rgba(123, 104, 238, 0.22), transparent 62%),
        radial-gradient(640px 540px at 12% 90%, rgba(16, 144, 224, 0.15), transparent 64%),
        radial-gradient(820px 560px at 88% 16%, rgba(214, 69, 93, 0.08), transparent 62%),
        linear-gradient(140deg, #0b0a11 0%, #0f0e16 45%, #0b0d12 100%);
      --chip-bg: #2c2b38; --chip-fg: #b8b4cb; --chip-fg-soft: #9a96ad; --col-bg: #1a1922; --count-bg: #2c2b38; --swatch-hover: #2c2b38; --avatar-bg: #3a3947; --track-bg: #2c2b38; --row-hover-soft: #26252f; --row-hover-strong: #2e2d3a; --row-linked: #22212c; --row-picked-hover: #322d4d; --warn-bg: #3a2a12; --warn-bg-2: #3a2a12; --warn-bg-3: #3a2a12; --warn-bg-4: #3a2a12; --mark-bg: #4a3c10; --warn-fg: #f3b765; --warn-fg-2: #f3b765; --warn-edge: #6b4a1c; --warn-edge-2: #6b4a1c; --ok-bg: #16301f; --ok-bg-2: #16301f; --ok-bg-3: #16301f; --ok-fg: #7fd6a0; --ok-fg-2: #7fd6a0; --info-bg: #1b2644; --info-bg-2: #1b2644; --info-fg: #a9bcff; --info-fg-2: #a9bcff; --danger-bg: #3d1d22; --ref-hover: #3a3160; --tpl-hover: #2b2644; --check-edge: #4a4860; --avatar-fg: #d6d4e0; 
      color-scheme: dark;
    }
  }
  :root[data-theme="dark"] {
    --purple: #8f80f7; --purple-dark: #b7adff; --purple-light: #2b2644;
    --bg: #17161f; --panel: #1f1e29; --border: #302e3e; --table-rule: #524f68; --title-text: #f8f7fd;
    --text: #ecebf4; --text-soft: #c3c0d4; --hint: #8e8aa5; --placeholder-icon: #5f5c73;
    --text-strong: #ffffff; --ink: #ecebf4; --ink-text: #15141c;
    --glass: rgba(31, 30, 41, 0.62); --glass-strong: rgba(31, 30, 41, 0.86); --glass-edge: rgba(255, 255, 255, 0.08);
    --ch-scrim: rgba(0, 0, 0, 0.30);
    --scroll-thumb: rgba(255, 255, 255, 0.26);
    --code-tint: rgba(255, 255, 255, 0.09); --code-tint-mine: rgba(255, 255, 255, 0.12);
    --quote-rule: rgba(255, 255, 255, 0.24); --quote-rule-mine: rgba(255, 255, 255, 0.34);
    --main-surface: rgba(17, 16, 23, 0.94);
    --side-bg: linear-gradient(180deg, rgba(10, 10, 14, 0.88) 0%, rgba(4, 4, 8, 0.94) 100%);
    --side-edge: rgba(255, 255, 255, 0.09);
    --side-hover: rgba(255, 255, 255, 0.08); --side-active: rgba(255, 255, 255, 0.15);
    --row-hover: #25242f; --row-picked: #2a2641; --tab-active-bg: #2b2a37;
    --bubble-mine: #2c4461; --input-bg: #262532;
    --page-bg:
      radial-gradient(760px 520px at 5% 8%, rgba(123, 104, 238, 0.22), transparent 62%),
      radial-gradient(640px 540px at 12% 90%, rgba(16, 144, 224, 0.15), transparent 64%),
      radial-gradient(820px 560px at 88% 16%, rgba(214, 69, 93, 0.08), transparent 62%),
      linear-gradient(140deg, #0b0a11 0%, #0f0e16 45%, #0b0d12 100%);
    --chip-bg: #2c2b38; --chip-fg: #b8b4cb; --chip-fg-soft: #9a96ad; --col-bg: #1a1922; --count-bg: #2c2b38; --swatch-hover: #2c2b38; --avatar-bg: #3a3947; --track-bg: #2c2b38; --row-hover-soft: #26252f; --row-hover-strong: #2e2d3a; --row-linked: #22212c; --row-picked-hover: #322d4d; --warn-bg: #3a2a12; --warn-bg-2: #3a2a12; --warn-bg-3: #3a2a12; --warn-bg-4: #3a2a12; --mark-bg: #4a3c10; --warn-fg: #f3b765; --warn-fg-2: #f3b765; --warn-edge: #6b4a1c; --warn-edge-2: #6b4a1c; --ok-bg: #16301f; --ok-bg-2: #16301f; --ok-bg-3: #16301f; --ok-fg: #7fd6a0; --ok-fg-2: #7fd6a0; --info-bg: #1b2644; --info-bg-2: #1b2644; --info-fg: #a9bcff; --info-fg-2: #a9bcff; --danger-bg: #3d1d22; --ref-hover: #3a3160; --tpl-hover: #2b2644; --check-edge: #4a4860; --avatar-fg: #d6d4e0; 
    color-scheme: dark;
  }
  * { box-sizing: border-box; margin: 0; padding: 0; }
  [hidden] { display: none !important; }
  /* scrollbars stay functional but out of sight */
  #drawer-body, #activity-list, #view-body, #sidebar, .props-panel, #field-panel .panel-body, .table-wrap, #link-suggestions {
    scrollbar-width: none; -ms-overflow-style: none;
  }
  #drawer-body::-webkit-scrollbar, #activity-list::-webkit-scrollbar, #view-body::-webkit-scrollbar,
  #sidebar::-webkit-scrollbar, .props-panel::-webkit-scrollbar, #field-panel .panel-body::-webkit-scrollbar,
  .table-wrap::-webkit-scrollbar, #link-suggestions::-webkit-scrollbar { width: 0; height: 0; display: none; }
  /* A chat is read by scrolling, so hiding the bar entirely takes away the one thing that says
     where you are in a long conversation. It is drawn thin instead, and only while the pointer is
     over the thing that scrolls. */
  .chat-rows, #ch-messages, .ch-list {
    scrollbar-width: thin; scrollbar-color: transparent transparent;
  }
  .chat-rows:hover, #ch-messages:hover, .ch-list:hover { scrollbar-color: var(--scroll-thumb) transparent; }
  .chat-rows::-webkit-scrollbar, #ch-messages::-webkit-scrollbar, .ch-list::-webkit-scrollbar { width: 7px; height: 7px; }
  .chat-rows::-webkit-scrollbar-track, #ch-messages::-webkit-scrollbar-track, .ch-list::-webkit-scrollbar-track { background: transparent; }
  .chat-rows::-webkit-scrollbar-thumb, #ch-messages::-webkit-scrollbar-thumb, .ch-list::-webkit-scrollbar-thumb {
    background: transparent; border-radius: 4px;
  }
  .chat-rows:hover::-webkit-scrollbar-thumb, #ch-messages:hover::-webkit-scrollbar-thumb,
  .ch-list:hover::-webkit-scrollbar-thumb { background: var(--scroll-thumb); }
  /* No blue box on a tap. A phone browser flashes a highlight over whatever was touched and leaves a
     focus ring on a tapped button — switching sections in the bottom bar drew a blue frame each
     time (Andrey, 23 Sep). The ring stays for the keyboard, where it is how you know where you are. */
  html { -webkit-tap-highlight-color: transparent; }
  button:focus:not(:focus-visible), a:focus:not(:focus-visible), [role="button"]:focus:not(:focus-visible),
  [tabindex]:focus:not(:focus-visible), .tab-item:focus:not(:focus-visible) { outline: none; }
  body {
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    background: var(--page-bg);
    background-attachment: fixed; color: var(--text);
    /* dvh, not vh: on a phone 100vh is the height with the browser's toolbar hidden, so with it
       showing the bottom of the page sat behind the menu bar — the chat's input with it. The vh
       line stays for browsers that do not know dvh. */
    height: 100vh; height: 100dvh; overflow: hidden; font-size: 13px; -webkit-font-smoothing: antialiased;
    padding: 8px; box-sizing: border-box;
  }
  button, input, select, textarea { font-family: inherit; font-size: inherit; }

  /* Login */
  .oidc-btn {
    border: 1px solid var(--border); background: var(--panel); color: var(--text); cursor: pointer;
    border-radius: 9px; padding: 10px 18px; font: inherit; font-size: 14px; font-weight: 600;
  }
  .oidc-btn:hover { border-color: var(--purple); color: var(--purple-dark); }

  #signup-screen {
    display: none; position: fixed; inset: 0; z-index: 300; overflow-y: auto;
    background: var(--bg); padding: 40px 18px calc(40px + env(safe-area-inset-bottom, 0px));
  }
  #signup-screen.visible { display: block; }
  .signup-card {
    max-width: 420px; margin: 0 auto; background: var(--panel); border: 1px solid var(--border);
    border-radius: 16px; padding: 28px 26px; display: flex; flex-direction: column; gap: 12px;
    box-shadow: 0 18px 50px rgba(16, 16, 30, 0.10);
  }
  .signup-card h2 { font-size: 21px; font-weight: 700; }
  .signup-card p { font-size: 13.5px; color: var(--text-soft); line-height: 1.5; }
  .signup-card label { font-size: 12px; font-weight: 600; color: var(--hint); margin-top: 4px; }
  .signup-card input {
    padding: 9px 11px; border: 1px solid var(--border); border-radius: 9px; font: inherit; font-size: 14px;
    background: var(--panel); color: var(--text); width: 100%; box-sizing: border-box;
  }
  .signup-card input:focus { outline: 2px solid var(--purple); outline-offset: -1px; }
  .signup-slug { display: flex; align-items: center; gap: 6px; }
  .signup-slug input { flex: 1; min-width: 0; }
  #signup-domain { font-size: 13px; color: var(--hint); white-space: nowrap; }
  .signup-note { font-size: 12px; min-height: 16px; }
  .signup-note.ok { color: var(--done); }
  .signup-note.bad { color: var(--urgent); }
  .signup-who { font-size: 13px; color: var(--text-soft); background: var(--bg); border-radius: 9px; padding: 8px 10px; }
  .signup-error { color: var(--urgent); font-size: 13px; }
  .signup-card .primary-btn {
    align-self: flex-start; margin-top: 8px; border: none; background: #111111; color: #fff;
    border-radius: 9px; padding: 10px 16px; font: inherit; font-size: 14px; font-weight: 600; cursor: pointer;
  }
  .signup-card .primary-btn:disabled { opacity: 0.6; cursor: default; }

  #login-screen {
    display: none; position: fixed; inset: 0; background: var(--bg);
    flex-direction: column; align-items: center; justify-content: center; gap: 20px; z-index: 999;
  }
  #login-screen.visible { display: flex; }
  #login-screen h2 { font-size: 22px; font-weight: 700; }
  .login-link {
    border: none; background: none; color: var(--hint); font: inherit; font-size: 13px;
    cursor: pointer; text-decoration: underline; text-underline-offset: 3px; padding: 2px;
  }
  .login-link:hover { color: var(--purple-dark); }
  .login-form { display: flex; flex-direction: column; gap: 8px; width: 264px; }
  .login-form input {
    padding: 9px 11px; border: 1px solid var(--border); border-radius: 9px; font: inherit; font-size: 14px;
    background: var(--panel); color: var(--text); width: 100%; box-sizing: border-box;
  }
  .login-form input:focus { outline: 2px solid var(--purple); outline-offset: -1px; }
  .login-form button { width: 100%; }
  #login-error { color: var(--urgent); }
  #login-screen p { font-size: 14px; color: var(--hint); text-align: center; max-width: 260px; }

  /* App shell: floating panels on a soft page, one dark menu */
  /* The menu, the edge you drag, and the work. The gap is small on purpose: the strip between them
     is already a visible seam, and 10px on either side of it put a corridor down the window. */
  #app { display: none; height: calc(100vh - 16px); height: calc(100dvh - 16px); gap: 5px; }
  #app.visible { display: flex; }

  /* The single menu: frosted glass, dark against a light page and light against a dark one */
  #sidebar {
    width: var(--side-w, 244px); flex-shrink: 0; box-sizing: border-box;
    background: var(--side-bg);
    backdrop-filter: blur(34px) saturate(220%); -webkit-backdrop-filter: blur(34px) saturate(220%);
    --side-text: #f7f7f9; --side-text-soft: #e4e3ea; --side-hint: #a09fad;   /* a touch whiter, as Andrey asked (24 Sep 2026) */
    color: var(--side-text);
    display: flex; flex-direction: column; padding: 12px 10px; overflow-y: auto;
    transition: margin-left 0.2s; font-size: 13px;
    border-radius: 18px; border: 1px solid var(--side-edge);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.10), inset 0 0 40px rgba(255, 255, 255, 0.03),
      0 14px 40px rgba(6, 6, 16, 0.30);
  }
  .side-head { display: flex; align-items: center; gap: 9px; padding: 2px 6px 10px; }
  /* The strip between the menu and the work. Invisible until the pointer is on it, like the one
     between a chat list and a conversation. */
  #side-split {
    width: 5px; margin: 0 -2px; flex-shrink: 0; cursor: col-resize; border-radius: 3px;
    background: transparent; transition: background 0.15s;
  }
  #side-split:hover, body.side-resizing #side-split { background: var(--glass-edge); }
  body.side-resizing { cursor: col-resize; user-select: none; }
  body.side-folded #side-split { pointer-events: none; }
  @media (max-width: 780px) { #side-split { display: none; } }
  .side-head .ws-icon img { width: 30px; height: 30px; border-radius: 9px; object-fit: cover; display: block; }
  .side-search {
    display: flex; align-items: center; gap: 7px; margin: 0 2px 10px; padding: 7px 9px;
    background: rgba(255, 255, 255, 0.07); border: 1px solid rgba(255, 255, 255, 0.07);
    border-radius: 10px; color: var(--side-hint);
  }
  .side-search:focus-within { border-color: rgba(255, 255, 255, 0.18); background: rgba(255, 255, 255, 0.1); }
  .side-search input {
    flex: 1; min-width: 0; border: none; background: none; outline: none; font: inherit; font-size: 12.5px; color: var(--side-text);
  }
  .side-search input::placeholder { color: var(--side-hint); }
  .side-search kbd {
    font: inherit; font-size: 10.5px; color: var(--side-hint); background: rgba(255, 255, 255, 0.08);
    border-radius: 5px; padding: 1px 5px;
  }
  .side-nav { display: flex; flex-direction: column; gap: 2px; }
  .side-nav-item {
    display: flex; align-items: center; gap: 9px; padding: 7px 9px; border-radius: 9px; cursor: pointer;
    color: var(--side-text-soft); font-size: 13px; font-weight: 500;
  }
  .side-nav-item svg { width: 17px; height: 17px; flex-shrink: 0; }
  .side-nav-item:hover { background: var(--side-hover); color: var(--side-text); }
  .side-nav-item.active { background: var(--side-active); color: var(--side-text); font-weight: 600; }
  /* a digest is waiting: one quiet dot, no counter to dismiss */
  .side-nav-item.has-news { color: var(--side-text); }
  .side-nav-item.has-news::after {
    content: ''; margin-left: auto; width: 6px; height: 6px; border-radius: 50%;
    background: #36d07a; box-shadow: 0 0 0 3px rgba(54, 208, 122, 0.18);
  }
  .side-foot { margin-top: auto; padding-top: 10px; border-top: 1px solid rgba(255, 255, 255, 0.07); display: flex; align-items: center; gap: 8px; }
  .side-foot .side-nav-item { flex: 1; }
  .side-me { width: 28px; height: 28px; border-radius: 50%; overflow: hidden; flex-shrink: 0; display: inline-flex; }
  .side-me .avatar { width: 28px; height: 28px; font-size: 12px; }
  .side-section-add {
    margin-left: auto; width: 20px; height: 20px; display: inline-flex; align-items: center; justify-content: center;
    border: none; background: none; color: var(--side-hint); border-radius: 6px; cursor: pointer;
  }
  .side-section-add:hover { background: var(--side-hover); color: var(--side-text); }
  .side-section-title {
    display: flex; align-items: center; font-size: 10.5px; font-weight: 700; text-transform: uppercase;
    letter-spacing: 0.5px; color: var(--side-hint); padding: 14px 9px 5px;
  }
  /* The row keeps its height whether or not the hover actions are in it: the buttons are taller
     than the text, so without this the row grew by 7px on hover and pushed everything below it
     down — the menu appeared to jump under the cursor. */
  .side-item {
    display: flex; align-items: center; justify-content: space-between; gap: 6px;
    padding: 4px 9px; min-height: 27px; box-sizing: border-box;
    border-radius: 6px; cursor: pointer; color: var(--side-text-soft);
    font-size: 13px; margin-bottom: 1px;
  }
  .side-item:hover { background: var(--side-hover); }
  /* Favourites and Recent (keptHtml): drawn like a row of the tree, but not one — the tree's rows
     carry actions, drag and drop, and are what "the list's row" means to the rest of the app. */
  .side-kept-item { display: flex; align-items: center; gap: 6px; padding: 4px 9px; min-height: 27px; box-sizing: border-box;
    border-radius: 6px; cursor: pointer; color: var(--side-text-soft); font-size: 13px; margin-bottom: 1px; }
  .side-kept-item:hover { background: var(--side-hover); }
  .side-kept-item .name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .side-item.active { background: var(--side-active); color: var(--side-text); font-weight: 600; }
  .side-item .name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .side-item .count { font-size: 11px; color: var(--side-hint); }
  .side-item.active .count { color: var(--side-text-soft); }
  .side-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--purple); flex-shrink: 0; }
  .side-icon { display: inline-flex; flex-shrink: 0; color: var(--side-hint); }
  .side-item.active .side-icon { color: var(--side-text); }
  #new-space-btn {
    margin-top: 6px; background: none; border: none; color: var(--side-hint); display: flex; align-items: center; gap: 8px;
    border-radius: 6px; padding: 6px 9px; cursor: pointer; text-align: left; font-size: 13px;
  }
  #new-space-btn:hover { background: var(--side-hover); color: var(--side-text-soft); }

  /* Spaces tree */
  .side-space {
    display: flex; align-items: center; gap: 8px; padding: 5px 9px; min-height: 30px; box-sizing: border-box;
    margin-top: 6px; border-radius: 6px;
    font-size: 13px; font-weight: 600; color: var(--side-text); cursor: pointer;
  }
  .side-space:hover { background: var(--side-hover); }
  .side-space.active { background: var(--side-active); }
  .side-space .space-icon {
    width: 20px; height: 20px; border-radius: 6px; color: #fff; font-size: 11px; font-weight: 700;
    display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; position: relative;
  }
  /* The glyph is an inline SVG, so by default it sits on the text baseline and leaves the
     descender gap below it — which lifts it inside the badge and makes the whole icon read as too
     high next to the space's name. Centring it in its own box puts it back on the middle. */
  .side-space .space-icon .space-letter { display: inline-flex; align-items: center; justify-content: center; line-height: 0; }
  .side-space .space-icon .space-caret { display: none; }
  .side-space:hover .space-icon .space-letter { display: none; }
  .side-space:hover .space-icon .space-caret { display: inline-flex; }
  .side-space.collapsed .space-caret svg { transform: none; }
  .space-caret svg { transform: rotate(90deg); transition: transform 0.12s; }
  .side-space .name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .side-space-lists { margin-left: 18px; padding-left: 6px; border-left: 1px solid rgba(255, 255, 255, 0.1); }
  .side-space-lists .empty-hint { color: var(--side-hint); font-size: 12px; padding: 5px 9px; }
  .side-item.folder-row { font-weight: 600; }
  .side-item.folder-row .folder-caret svg { transform: rotate(90deg); transition: transform 0.12s; }
  .side-item.folder-row.collapsed .folder-caret svg { transform: none; }
  .folder-children { margin-left: 16px; padding-left: 6px; border-left: 1px solid rgba(255, 255, 255, 0.1); }
  .side-actions { display: none; align-items: center; gap: 1px; flex-shrink: 0; }
  .side-item:hover .side-actions, .side-space:hover .side-actions, .side-actions.open { display: inline-flex; }
  .side-item:hover .count, .side-item.menu-open .count { display: none; }
  .side-item.menu-open .side-actions, .side-space.menu-open .side-actions { display: inline-flex; }
  /* 19px so that 4px of padding above and below adds up to the row's 27px exactly */
  .side-act-btn {
    width: 21px; height: 19px; border: none; background: none; border-radius: 5px; color: var(--side-text-soft);
    display: inline-flex; align-items: center; justify-content: center; cursor: pointer; padding: 0;
  }
  .side-act-btn:hover { background: rgba(255, 255, 255, 0.14); color: var(--side-text); }
  .side-rename-input {
    flex: 1; min-width: 0; font: inherit; border: 1px solid var(--purple); border-radius: 5px; padding: 1px 5px; outline: none;
    background: var(--input-bg); color: var(--text);
  }
  .side-item.drop-before, .side-space.drop-before { box-shadow: inset 0 2px 0 0 var(--purple); }
  .side-item.drop-after, .side-space.drop-after { box-shadow: inset 0 -2px 0 0 var(--purple); }
  /* "Into" needs to look like into, wherever it lands: a space, a folder's own row, and the open
     folder under it — which is where somebody aims when the folder is empty. Only the space had a
     style for it, so a perfectly good drop on a folder looked like a refusal. */
  .side-space.drop-into, .side-item.drop-into, .folder-children.drop-into, .side-space-lists.drop-into {
    background: rgba(255, 255, 255, 0.18); border-radius: 8px;
  }
  .empty-hint.drop-into { background: rgba(255, 255, 255, 0.18); border-radius: 8px; color: var(--side-text, #fff); }
  .side-item.dragging, .side-space.dragging { opacity: 0.45; }
  .menu-sep { height: 1px; background: var(--border); margin: 4px 2px; }
  .menu-label { font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.4px; color: var(--hint); padding: 6px 9px 2px; }
  .status-menu-item.danger { color: var(--urgent); }
  .status-menu-item.disabled { color: var(--placeholder-icon, #b9b5c6); pointer-events: none; }
  /* The space's code, beside its name in the new-space dialog. Small, because it is three
     characters and looks silly at the width of a name field. */
  .new-space-code { display: flex; align-items: center; gap: 10px; padding: 0 0 10px; }
  .new-space-code span { font-size: 12px; font-weight: 600; color: var(--hint); }
  .new-space-code input {
    width: 78px; border: 1px solid var(--border); border-radius: 9px; padding: 7px 9px;
    font: inherit; font-size: 13px; letter-spacing: 1px; text-transform: uppercase; outline: none;
  }
  .new-space-code input:focus { border-color: var(--purple); }
  .color-swatches { display: grid; grid-template-columns: repeat(5, 18px); gap: 7px; padding: 4px 9px 6px; }
  #new-space-colors { grid-template-columns: repeat(10, 18px); }
  .color-swatch { width: 18px; height: 18px; border-radius: 5px; cursor: pointer; border: 2px solid transparent; }
  .color-swatch.selected { border-color: var(--text); }
  .icon-swatches { display: grid; grid-template-columns: repeat(6, 24px); gap: 4px; padding: 4px 9px 6px; }
  #new-space-icons { grid-template-columns: repeat(9, 24px); padding: 0 0 12px; }
  .icon-swatch {
    width: 24px; height: 24px; border-radius: 6px; display: inline-flex; align-items: center; justify-content: center;
    cursor: pointer; color: #333; border: 1.5px solid transparent; font-size: 11px; font-weight: 700;
  }
  .icon-swatch:hover { background: var(--swatch-hover); }
  .icon-swatch.selected { border-color: var(--text); background: var(--swatch-hover); }
  .icon-swatch svg, .space-icon .space-letter svg { width: 13px; height: 13px; }
  .modal-box .modal-text { font-size: 13px; color: var(--text-soft); margin-bottom: 12px; line-height: 1.45; }
  .modal-box label.modal-choice { display: flex; align-items: center; gap: 8px; font-size: 13px; margin-bottom: 8px; cursor: pointer; }
  #delete-choices:not(:empty) { margin-bottom: 16px; }
  .modal-box label.modal-choice input { width: auto; margin: 0; }
  .modal-box select { width: 100%; border: 1px solid var(--border); border-radius: 8px; padding: 7px 8px; margin: 0 0 12px; font: inherit; }
  /* Share dialog */
  #share-modal .modal-box { width: 460px; }
  /* The filter is read across rather than down: field, what to compare, what to compare with.
     The id is in the selector because .modal-box sets a width of its own, and a dialog of three
     controls in a 320px column is the thing this rule exists to prevent. */
  #filter-modal .modal-box { width: min(760px, 94vw); max-height: 86vh; overflow-y: auto; }
  .filter-top { font-size: 13px; color: var(--hint); display: flex; align-items: center; gap: 6px; margin-bottom: 10px; }
  .filter-group { border: 1px solid var(--border); border-radius: 12px; padding: 10px; margin-bottom: 10px; }
  .filter-group-head { display: flex; align-items: center; gap: 6px; font-size: 13px; color: var(--hint); margin-bottom: 8px; }
  .filter-group-head .quiet-link { margin-left: auto; }
  .filter-rule { display: flex; align-items: center; gap: 6px; margin-bottom: 6px; flex-wrap: nowrap; }
  .filter-rule .icon-btn { margin-left: auto; flex-shrink: 0; }
  .filter-rule select, .filter-rule input {
    border: 1px solid var(--border); border-radius: 8px; padding: 5px 8px; font: inherit; font-size: 13px;
    background: var(--input-bg); color: var(--text);
  }
  .filter-field { min-width: 150px; }
  .filter-op { min-width: 120px; }
  .filter-value { flex: 1 1 auto; min-width: 150px; max-width: 320px; }
  select.filter-value { padding: 4px 6px; }
  /* Every control in this dialog sizes itself: `.modal-box select` and `.modal-box input` make
     them fill the box and carry a bottom margin, which is right for a form of one field per line
     and wrong for a row that reads as a sentence. The id keeps this above that rule. */
  #filter-modal .modal-box select, #filter-modal .modal-box input { width: auto; margin: 0; }
  #filter-modal .filter-join { font-size: 13px; min-width: 96px; flex: 0 0 auto; }
  .filter-count { font-size: 12.5px; color: var(--hint); margin-top: 8px; }
  #filter-btn.on { border-color: var(--purple); color: var(--purple); }
  #filter-count { margin-left: 5px; background: var(--purple); color: #fff; border-radius: 9px; padding: 0 5px; font-size: 11px; }
  @media (max-width: 780px) {
    .filter-rule { flex-wrap: wrap; }
    .filter-rule select, .filter-rule input { min-width: 0; flex: 1 1 45%; max-width: none; }
  }
  .share-section { font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.4px; color: var(--hint); margin: 12px 0 6px; }
  .share-row { display: flex; align-items: center; gap: 8px; padding: 5px 0; font-size: 13px; }
  .share-row .who { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .share-row .who small { color: var(--hint); margin-left: 4px; }
  .share-row .fixed-role { color: var(--hint); font-size: 12px; }
  .share-row select, .share-invite select { width: auto; margin: 0; padding: 4px 6px; border-radius: 6px; font-size: 12.5px; }
  .share-row .remove-btn { border: none; background: none; color: var(--hint); cursor: pointer; font-size: 15px; padding: 0 4px; }
  .share-row .remove-btn:hover { color: var(--urgent); }
  .share-invite { display: flex; gap: 6px; margin-top: 4px; }
  .share-invite input { flex: 1; margin: 0 !important; }
  .share-invite button { padding: 0 12px; border-radius: 8px; border: none; background: var(--purple); color: #fff; font-weight: 600; cursor: pointer; }
  .avatar { width: 22px; height: 22px; border-radius: 50%; background: var(--avatar-bg); color: var(--avatar-fg); font-size: 10.5px; font-weight: 700; display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; overflow: hidden; }
  .avatar img { width: 100%; height: 100%; object-fit: cover; }
  .share-hint { font-size: 12px; color: var(--hint); line-height: 1.4; margin-top: 4px; }

  /* Settings */
  .settings { max-width: 760px; }
  .settings h2 { font-size: 16px; margin: 4px 0 4px; }
  .settings .settings-card { border: 1px solid var(--border); border-radius: 10px; padding: 14px 16px; margin: 12px 0 20px; }
  /* The page's own sections, as chips. Everything on one scroll was eleven headings deep. */
  /* Your own name and face, edited in place. The name is a field that looks like text until it is
     clicked, because it is read far more often than it is changed. */
  .profile-row { align-items: center; gap: 12px; }
  .profile-face { position: relative; display: inline-flex; }
  .profile-face-btn {
    position: absolute; left: 0; right: 0; bottom: -2px; border: none; cursor: pointer;
    background: rgba(0, 0, 0, 0.55); color: #fff; font: inherit; font-size: 9.5px; font-weight: 600;
    padding: 2px 0; border-radius: 0 0 8px 8px; opacity: 0; transition: opacity 0.15s;
  }
  .profile-face:hover .profile-face-btn { opacity: 1; }
  .profile-name {
    font-weight: 600; font-size: 15px; width: 100%; max-width: 320px; border: 1px solid transparent;
    background: none; color: var(--text); border-radius: 8px; padding: 4px 8px; margin: -4px -8px 2px;
  }
  .profile-name:hover { border-color: var(--border); }
  .profile-name:focus { border-color: var(--purple); background: var(--input-bg); outline: none; }

  .set-chips {
    display: flex; flex-wrap: wrap; gap: 6px; margin: 2px 0 18px; position: sticky; top: 0;
    background: var(--main-surface); padding: 6px 0 8px; z-index: 2;
  }
  .set-chip {
    border: 1px solid var(--border); background: none; color: var(--text-soft); cursor: pointer;
    font: inherit; font-size: 12.5px; font-weight: 600; padding: 5px 12px; border-radius: 999px;
  }
  .set-chip:hover { background: var(--row-hover); color: var(--text); }
  .set-chip.active { background: var(--ink); border-color: var(--ink); color: var(--ink-text); }
  .set-section > h2:first-child { margin-top: 0; }
  /* An address with a button beside it: never wrapped, scrollable if it is long, copied in one
     press. It used to sit inside a sentence, where it broke across two lines. */
  .copy-line {
    display: flex; align-items: center; gap: 10px; margin: 10px 0; padding: 8px 10px;
    background: var(--bg); border: 1px solid var(--border); border-radius: 10px;
  }
  .copy-label { font-size: 12px; color: var(--hint); flex-shrink: 0; }
  .copy-line code {
    flex: 1; min-width: 0; overflow-x: auto; white-space: nowrap; font-size: 13px;
    background: none; padding: 0;
  }
  .copy-line .btn { flex-shrink: 0; }
  .plan-top { display: flex; align-items: flex-start; gap: 16px; }
  .plan-band { font-size: 17px; font-weight: 700; }
  .plan-price { margin-left: auto; font-size: 17px; font-weight: 700; white-space: nowrap; }
  .plan-meter { height: 7px; border-radius: 4px; background: var(--bg); overflow: hidden; margin: 12px 0 8px; }
  .plan-meter-fill { height: 100%; background: linear-gradient(90deg, var(--purple), #9b8cff); border-radius: 4px; transition: width 0.3s; }
  .plan-line { font-size: 13.5px; }
  .plan-facts { display: flex; flex-wrap: wrap; gap: 4px 18px; margin-top: 8px; font-size: 12.5px; color: var(--hint); }
  .storage-details { margin-top: 10px; }
  .storage-details summary { cursor: pointer; font-size: 13px; font-weight: 600; }
  .storage-details input {
    width: 100%; box-sizing: border-box; padding: 8px 10px; border: 1px solid var(--border);
    border-radius: 8px; font: inherit; font-size: 13px; background: var(--panel); color: var(--text);
  }
  .backups-block { margin-top: 16px; padding-top: 12px; border-top: 1px solid var(--border); }
  .backups-head { font-size: 13.5px; font-weight: 700; display: flex; gap: 8px; align-items: baseline; }
  .backups-head .muted { font-weight: 500; }
  .backup-list { margin-top: 8px; display: flex; flex-direction: column; gap: 3px; }
  .backup-row { display: flex; justify-content: space-between; gap: 12px; font-size: 12.5px; }
  .oidc-redirect { margin-top: 10px; font-size: 13px; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
  .oidc-redirect code { background: var(--bg); padding: 3px 7px; border-radius: 6px; font-size: 12.5px; }
  .oidc-label { display: block; font-size: 12px; font-weight: 600; color: var(--hint); margin: 10px 0 3px; }
  #import-card input[type=file] { font: inherit; font-size: 13px; }
  .import-facts { display: flex; flex-wrap: wrap; gap: 8px; margin: 12px 0 8px; }
  .import-fact { background: var(--bg); border-radius: 9px; padding: 7px 12px; display: flex; flex-direction: column; }
  .import-fact b { font-size: 16px; font-variant-numeric: tabular-nums; }
  .import-fact span { font-size: 11.5px; color: var(--hint); }
  .import-warn { margin-top: 6px; font-size: 12.5px; color: var(--warn-fg); background: var(--warn-bg); border-radius: 8px; padding: 7px 10px; }
  .import-error { margin-top: 8px; font-size: 13px; color: var(--urgent); }
  .import-sample { margin: 10px 0; display: flex; flex-direction: column; gap: 3px; }
  .import-row { display: flex; justify-content: space-between; gap: 12px; font-size: 12.5px; border-bottom: 1px solid var(--border); padding-bottom: 3px; }
  /* The wiki import's own preview: a page tree, indented the way it will end up. */
  .import-summary { margin: 12px 0 6px; font-size: 13px; }
  .import-summary b { font-size: 16px; font-variant-numeric: tabular-nums; }
  #wiki-preview .import-sample { max-height: 220px; overflow-y: auto; font-size: 12.5px; }
  #wiki-preview .import-sample li { list-style: none; }
  .import-notes { margin: 8px 0 4px 16px; font-size: 12.5px; color: var(--text-soft); line-height: 1.5; }
  .import-skipped { font-size: 12.5px; color: var(--warn-fg); background: var(--warn-bg); border-radius: 8px; padding: 6px 10px; margin: 6px 0; }
  #wiki-import-card select {
    padding: 6px 9px; border: 1px solid var(--border); border-radius: 8px; font: inherit; font-size: 13px;
    background: var(--panel); color: var(--text);
  }
  #import-card select {
    padding: 6px 9px; border: 1px solid var(--border); border-radius: 8px; font: inherit; font-size: 13px;
    background: var(--panel); color: var(--text);
  }
  #audit-card select {
    padding: 6px 9px; border: 1px solid var(--border); border-radius: 8px; font: inherit; font-size: 13px;
    background: var(--panel); color: var(--text);
  }
  .sys-facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 12px; margin: 12px 0 4px; }
  .sys-label { font-size: 11px; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; color: var(--hint); }
  .sys-value { font-size: 19px; font-weight: 700; font-variant-numeric: tabular-nums; margin: 2px 0 1px; }
  .sys-value code { font-size: 15px; font-weight: 600; }
  .sys-line { margin-top: 8px; font-size: 13px; color: var(--text-soft); }
  .sys-bad { color: var(--urgent); }
  #sys-routes td.num, #sys-routes th.num { text-align: right; font-variant-numeric: tabular-nums; }

  /* The one screen a person sees when the workspace requires a second factor they have not set
     up. Deliberately not a dialog: there is nothing behind it to go back to. */
  #enrol-gate:not([hidden]) {
    position: fixed; inset: 0; z-index: 400; overflow-y: auto; background: var(--bg);
    padding: 8vh 18px calc(40px + env(safe-area-inset-bottom, 0px));
  }
  .gate-card {
    max-width: 460px; margin: 0 auto; background: var(--panel); border: 1px solid var(--border);
    border-radius: 16px; padding: 26px; display: flex; flex-direction: column; gap: 12px;
    box-shadow: 0 18px 50px rgba(16, 16, 30, 0.10);
  }
  .gate-card h2 { font-size: 20px; font-weight: 700; }
  .gate-card p { font-size: 13.5px; color: var(--text-soft); line-height: 1.55; }
  .gate-card input {
    padding: 9px 11px; border: 1px solid var(--border); border-radius: 9px; font: inherit;
    font-size: 15px; background: var(--panel); color: var(--text); max-width: 180px;
  }
  .gate-secret { font-size: 15px; letter-spacing: 1px; user-select: all; word-break: break-all; }

  .member-2fa { color: var(--done); font-weight: 600; }

  #sessions-table { margin-top: 8px; }
  #sessions-table tr.session-current td { background: var(--bg); }
  #sessions-table td:last-child, #sessions-table th:last-child { text-align: right; }

  .security-form {
    display: flex; flex-direction: column; gap: 8px; margin-top: 10px; padding: 12px;
    background: var(--bg); border-radius: 10px; max-width: 420px;
  }
  .security-form input {
    padding: 8px 10px; border: 1px solid var(--border); border-radius: 8px; font: inherit;
    background: var(--panel); color: var(--text); max-width: 280px;
  }
  .totp-secret { font-size: 15px; letter-spacing: 1px; user-select: all; }
  .recovery-list { display: flex; flex-wrap: wrap; gap: 8px; margin: 10px 0; }
  .recovery-list code { font-size: 13.5px; }

  #oidc-card input, #oidc-card select {
    width: 100%; box-sizing: border-box; padding: 8px 10px; border: 1px solid var(--border);
    border-radius: 8px; font: inherit; font-size: 13.5px; background: var(--panel); color: var(--text);
  }
  .oidc-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 0 14px; }
  .plan-notice { margin-top: 12px; padding: 9px 11px; border-radius: 9px; font-size: 13px; }
  .plan-notice.ok { background: var(--ok-bg); color: var(--ok-fg); }
  .plan-notice.info { background: var(--info-bg); color: var(--info-fg); }
  .plan-notice.warn { background: var(--warn-bg); color: var(--warn-fg); }
  .plan-licence { margin-top: 10px; font-size: 13px; }
  .plan-next { margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--border); font-size: 13px; color: var(--text-soft); }
  .settings .muted { color: var(--hint); font-size: 12.5px; line-height: 1.45; }
  .settings table { width: 100%; border-collapse: collapse; font-size: 13px; }
  .settings td, .settings th { text-align: left; padding: 7px 6px; border-bottom: 1px solid var(--border); vertical-align: middle; }
  .settings th { font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.4px; color: var(--hint); font-weight: 700; }
  .settings select, .settings input[type=text], .settings input[type=email] { border: 1px solid var(--border); border-radius: 7px; padding: 6px 8px; font: inherit; }
  .settings .row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-top: 10px; }
  .settings .btn { border: none; border-radius: 7px; padding: 7px 12px; font-weight: 600; cursor: pointer; background: var(--purple); color: #fff; }
  .settings .btn.secondary { background: var(--bg); color: var(--text-soft); border: 1px solid var(--border); }
  .settings .btn.danger { background: none; color: var(--urgent); padding: 4px 6px; }
  .settings code, .token-reveal code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; background: var(--bg); border: 1px solid var(--border); border-radius: 6px; padding: 2px 6px; word-break: break-all; }
  .token-reveal { background: var(--warn-bg-3); border: 1px solid var(--warn-edge-2); border-radius: 8px; padding: 10px 12px; margin-top: 10px; font-size: 12.5px; line-height: 1.5; }
  .settings .table-wrap { overflow-x: auto; }
  .audit-item { font-size: 12.5px; padding: 6px 0; border-bottom: 1px solid var(--border); }
  .audit-item .when { color: var(--hint); margin-right: 6px; }
  #drawer.readonly #drawer-body input, #drawer.readonly #drawer-body select, #drawer.readonly #drawer-body textarea,
  #drawer.readonly #drawer-header select, #drawer.readonly #drawer-delete, #drawer.readonly #drawer-body button { pointer-events: none; opacity: 0.6; }
  #drawer.readonly #comment-input { display: none; }
  /* Filter and Columns sit side by side and are the same kind of control, so they look it. Filter
     shipped with no style of its own and showed as the browser's bare button beside a finished one. */
  #properties-btn, #filter-btn { background: none; border: 1px solid var(--border); border-radius: 8px; height: 30px; padding: 0 12px; cursor: pointer; color: var(--text-soft); font-size: 12.5px; display: inline-flex; align-items: center; gap: 5px; box-sizing: border-box; font-family: inherit; }
  #properties-btn:hover, #filter-btn:hover { background: var(--bg); }
  .props-panel { width: 260px; max-height: 70vh; overflow-y: auto; padding: 6px; }
  .props-panel .props-head { display: flex; align-items: center; justify-content: space-between; padding: 6px 8px 8px; font-weight: 700; font-size: 13px; }
  .props-panel .props-head span { color: var(--hint); font-weight: 600; font-size: 12px; }
  .prop-row { display: flex; align-items: center; gap: 9px; padding: 6px 8px; border-radius: 6px; font-size: 13px; cursor: pointer; }
  .prop-row:hover { background: var(--bg); }
  .prop-row .prop-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .prop-row .prop-icon { color: var(--hint); display: inline-flex; }
  .switch { width: 32px; height: 18px; border-radius: 9px; background: #d4d4d4; position: relative; flex-shrink: 0; transition: background 0.15s; }
  .switch.on { background: var(--purple); }
  .switch::after { content: ''; position: absolute; top: 2px; left: 2px; width: 14px; height: 14px; border-radius: 50%; background: #fff; transition: transform 0.15s; }
  .switch.on::after { transform: translateX(14px); }
  .cell-muted { color: var(--hint); font-size: 12px; }
  .cell-text { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; display: block; }
  /* Field type picker (right-hand panel) */
  #field-panel {
    position: fixed; top: 0; right: 0; height: 100vh; width: 340px; max-width: 94vw; background: var(--panel);
    border-left: 1px solid var(--border); box-shadow: -8px 0 28px rgba(20,15,40,0.12); z-index: 400;
    transform: translateX(105%); transition: transform 0.18s ease; display: flex; flex-direction: column;
  }
  #field-panel.open { transform: none; }
  #field-panel header { display: flex; align-items: center; gap: 8px; padding: 14px 16px 10px; font-weight: 700; font-size: 15px; }
  #field-panel header button { margin-left: auto; border: none; background: var(--bg); width: 26px; height: 26px; border-radius: 50%; cursor: pointer; color: var(--text-soft); }
  #field-panel .panel-body { padding: 0 16px 18px; overflow-y: auto; flex: 1; }
  #field-search { width: 100%; border: 1px solid var(--border); border-radius: 8px; padding: 8px 10px; outline: none; font: inherit; margin-bottom: 10px; }
  .field-type { display: flex; align-items: center; gap: 10px; padding: 8px 8px; border-radius: 8px; cursor: pointer; font-size: 13.5px; }
  .field-type:hover { background: var(--bg); }
  .field-type .ft-icon, .chosen-type .ft-icon { width: 20px; display: inline-flex; justify-content: center; align-items: center; color: var(--purple-dark); }
  .field-type small { color: var(--hint); }
  .field-type.unavailable { opacity: 0.45; cursor: not-allowed; }
  .field-type.unavailable .ft-icon { color: var(--hint); }
  .field-section { font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.4px; color: var(--hint); padding: 14px 8px 4px; }
  .field-section.spread { display: flex; justify-content: space-between; align-items: center; }
  .field-tabs { display: flex; gap: 16px; border-bottom: 1px solid var(--border); margin: 2px 0 8px; }
  .field-tabs button { border: none; background: none; padding: 8px 2px; font: inherit; font-size: 13.5px; font-weight: 600; color: var(--hint); cursor: pointer; border-bottom: 2px solid transparent; }
  .field-tabs button.active { color: var(--text); border-bottom-color: var(--text); }
  .field-type.col-row { gap: 9px; }
  .field-type.col-row .col-label { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .field-type.col-row .col-label small { color: var(--hint); }
  .field-type.col-row .ft-icon { color: var(--text-soft); }
  .field-type.col-row.locked { opacity: 0.55; pointer-events: none; }
  #field-form label { display: block; font-size: 12px; font-weight: 600; color: var(--text-soft); margin: 12px 0 4px; }
  #field-form input[type=text], #field-form input[type=number], #field-form textarea, #field-form select {
    width: 100%; border: 1px solid var(--border); border-radius: 8px; padding: 8px 10px; font: inherit; outline: none; background: var(--panel); color: var(--text);
  }
  #field-form textarea { min-height: 76px; resize: vertical; }
  #field-form .form-actions { display: flex; gap: 8px; margin-top: 16px; }
  #field-form .form-actions button { flex: 1; padding: 9px; border-radius: 8px; border: none; font-weight: 600; cursor: pointer; }
  .chosen-type { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--text-soft); background: var(--bg); padding: 8px 10px; border-radius: 8px; }
  .chosen-type button { margin-left: auto; border: none; background: none; color: var(--purple-dark); cursor: pointer; font-size: 12.5px; }
  .cf-bar { position: relative; height: 6px; border-radius: 3px; background: var(--track-bg); width: 100%; }
  .cf-bar span { position: absolute; left: 0; top: 0; bottom: 0; border-radius: 3px; background: var(--purple); }
  .cf-stars { letter-spacing: 1px; color: #f8ae00; }
  .cf-chips { display: flex; gap: 4px; overflow: hidden; }
  .cf-link { display: flex; align-items: center; gap: 4px; overflow: hidden; }
  .cf-link a { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .cf-edit { border: none; background: none; color: var(--hint); cursor: pointer; padding: 0 2px; display: none; flex-shrink: 0; }
  tr.task-row:hover .cf-edit, .jf-row:hover .cf-edit { display: inline-flex; }
  .cf-edit:hover { color: var(--purple-dark); }
  table.task-table th.col-dragging { opacity: 0.45; }
  table.task-table th.col-drop-left { box-shadow: inset 2px 0 0 0 var(--purple); }
  table.task-table th.col-drop-right { box-shadow: inset -2px 0 0 0 var(--purple); }
  .props-hint { font-size: 11.5px; color: var(--hint); padding: 10px 8px 4px; line-height: 1.4; }
  .cf-check { width: 15px; height: 15px; }
  /* An article. There is no pane of pages beside it any more: an article is reached from the tree
     on the left like anything else in a space, and the only list it carries is of the articles
     inside it — its contents, at the top, where a table of contents belongs. */
  .doc-layout { display: flex; gap: 22px; align-items: flex-start; height: 100%; }
  .doc-main { flex: 1; min-width: 0; max-width: 860px; }
  /* With no comments beside it the column used to sit hard left, leaving a hand's width of nothing
     down the right of a wide screen. On its own it is centred; with comments it stays where it was,
     because then the space on the right is doing something. */
  .doc-layout > .doc-main:only-child { margin-inline: auto; }
  .doc-loading { display: flex; justify-content: center; padding: 60px 0; }
  .doc-contents { margin: 4px 0 16px; padding: 12px 14px; border: 1px solid var(--border); border-radius: 12px; background: var(--bg); }
  .doc-contents.empty { border: none; background: none; padding: 0 0 10px; }
  .doc-contents h4 { margin: 0 0 8px; font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.4px; color: var(--hint); }
  .doc-contents-rows { display: flex; flex-direction: column; gap: 2px; }
  .doc-contents-rows button {
    display: flex; align-items: center; gap: 8px; width: 100%; text-align: left; border: none; background: none;
    font: inherit; font-size: 14px; color: var(--text); padding: 6px 8px; margin-left: -8px; border-radius: 8px; cursor: pointer;
  }
  .doc-contents-rows button:hover { background: var(--row-hover); color: var(--purple-dark); }
  .doc-contents-icon { display: inline-flex; width: 18px; justify-content: center; }
  .doc-contents > .quiet-link { margin-top: 8px; }
  /* An article in the tree on the left: the same row as a list, with its own emoji when it has one
     and a caret when it holds other articles. */
  .side-item.article-row.leaf { padding-left: 10px; }
  .side-item.article-row .side-icon:first-child { flex-shrink: 0; }
  .doc-title { width: 100%; border: none; outline: none; background: none; font: inherit; font-size: 26px; font-weight: 700; color: var(--text); padding: 4px 8px; margin-left: -8px; border-radius: 8px; }
  .doc-title:hover, .doc-title:focus { background: var(--bg); }
  .doc-meta { font-size: 11.5px; color: var(--hint); margin: 2px 0 12px 0; }
  .doc-body { width: 100%; min-height: 320px; border: none; outline: none; resize: none; overflow: hidden; background: none;
    font: inherit; font-size: 14px; line-height: 1.65; color: var(--text); padding: 8px; margin-left: -8px; border-radius: 8px; }
  .doc-body:hover, .doc-body:focus { background: var(--bg); }
  .doc-view { font-size: 14px; min-height: 200px; }
  .task-ref { color: var(--purple-dark); border-bottom: 1px dashed var(--purple); text-decoration: none; }
  .task-ref.missing { color: var(--hint); border: none; }
  /* whiteboard */
  #view-body.flush { padding: 0; overflow: hidden; position: relative; }
  .wb-wrap { position: absolute; inset: 0; overflow: hidden; }
  .board-canvas { position: absolute; inset: 0; overflow: hidden; background-color: var(--row-hover);
    background-image: radial-gradient(circle, #dedbe9 1.1px, transparent 1.1px); cursor: default; }
  .board-canvas[data-tool="hand"] { cursor: grab; }
  .board-canvas[data-tool="pen"] { cursor: crosshair; }
  .board-canvas[data-tool="note"], .board-canvas[data-tool="text"], .board-canvas[data-tool="rect"],
  .board-canvas[data-tool="ellipse"], .board-canvas[data-tool="task"] { cursor: crosshair; }
  .board-canvas[data-tool="arrow"] .board-item { cursor: crosshair; }
  .board-layer { position: absolute; top: 0; left: 0; transform-origin: 0 0; }
  .board-svg { position: absolute; top: 0; left: 0; width: 100%; height: 100%; overflow: visible; transform-origin: 0 0; pointer-events: none; }
  .board-svg > g, .board-svg > polyline { pointer-events: auto; }
  .board-stroke { cursor: move; }
  .board-stroke.selected, .board-arrow.selected line:last-child { filter: drop-shadow(0 0 0 var(--purple)); stroke-dasharray: 7 4; }
  .board-arrow { cursor: pointer; }

  .board-item { position: absolute; border-radius: 10px; box-sizing: border-box; cursor: move;
    display: flex; flex-direction: column; font-size: 14px; color: #2e2b3f; }
  .board-item.selected { outline: 2px solid var(--purple); outline-offset: 2px; }
  .board-note { box-shadow: 0 3px 10px rgba(46, 43, 63, 0.16); padding: 12px 13px; border-radius: 4px; }
  .board-rect { border: 1.5px solid rgba(46, 43, 63, 0.22); padding: 12px 13px; }
  .board-ellipse { border: 1.5px solid rgba(46, 43, 63, 0.22); border-radius: 50%; padding: 18px 22px; align-items: center; justify-content: center; text-align: center; }
  .board-body { flex: 1; outline: none; overflow: hidden; white-space: pre-wrap; word-break: break-word; line-height: 1.4; }
  .board-item.board-text { background: none; padding: 6px 8px; font-size: 20px; font-weight: 600; }
  .board-rect .board-body, .board-ellipse .board-body { display: flex; align-items: center; justify-content: center; text-align: center; }
  .board-item.editing { cursor: text; }
  .board-item.editing .board-body { cursor: text; }
  .board-item:not(.editing) .board-body { pointer-events: none; }
  .board-ph { position: absolute; inset: 12px 13px auto; color: rgba(46, 43, 63, 0.35); font-size: 13px; pointer-events: none; }
  .board-handle { position: absolute; right: -6px; bottom: -6px; width: 12px; height: 12px; border-radius: 3px;
    background: var(--panel); border: 2px solid var(--purple); cursor: nwse-resize; }

  .board-label { background: var(--panel); border: 1px solid var(--border); border-radius: 8px; padding: 4px 8px;
    font-size: 12px; text-align: center; justify-content: center; box-shadow: 0 1px 4px rgba(46, 43, 63, 0.08); }
  .board-label .board-body { flex: none; }
  .board-frame { background: rgba(255, 255, 255, 0.55); border: 1.5px solid #cfcadd; border-radius: 12px; cursor: move; }
  .board-frame.selected { outline-offset: 3px; }
  .board-frame-title { background: none; border: none; box-shadow: none; padding: 0 4px; font-size: 13px; font-weight: 700;
    color: var(--text-soft); align-items: center; }
  .board-frame-title .board-body { flex: none; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .frame-no { display: inline-flex; align-items: center; justify-content: center; width: 18px; height: 18px; margin-right: 8px;
    border-radius: 5px; background: var(--bg); font-size: 11px; font-weight: 700; color: var(--hint); }
  .wb-wrap.presenting .board-toolbar, .wb-wrap.presenting .board-zoom,
  .wb-wrap.presenting .board-hint, .wb-wrap.presenting .board-sel-tools, .wb-wrap.presenting .board-empty { display: none; }
  .wb-wrap.presenting .board-frame { border-color: transparent; background: #fff; }
  .wb-wrap.presenting .board-frame-title { display: none; }
  body.presenting #sidebar, body.presenting #topbar { display: none; }
  body.presenting .board-canvas { background-image: none; background-color: var(--chip-bg); }
  .board-present-bar { position: absolute; left: 50%; bottom: 20px; transform: translateX(-50%); display: flex; align-items: center; gap: 10px;
    background: var(--panel); border: 1px solid var(--border); border-radius: 12px; padding: 6px 10px; box-shadow: 0 8px 24px rgba(46, 43, 63, 0.16); }
  .board-present-bar button { border: none; background: none; font: inherit; font-size: 17px; line-height: 1; color: var(--text-soft);
    cursor: pointer; padding: 4px 8px; border-radius: 7px; }
  .board-present-bar button:hover:not(:disabled) { background: var(--bg); }
  .board-present-bar button:disabled { color: var(--placeholder-icon, #cfcadd); cursor: default; }
  .board-present-bar .pb-name { font-size: 13px; font-weight: 600; max-width: 260px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .board-present-bar .pb-count { font-size: 12px; color: var(--hint); }
  .board-present-bar .pb-exit { font-size: 12.5px; color: var(--purple-dark); font-weight: 600; }
  .board-cbadge { position: absolute; right: -8px; top: -8px; min-width: 20px; height: 20px; padding: 0 5px; border-radius: 10px;
    background: var(--purple); color: #fff; font-size: 11px; font-weight: 700; display: inline-flex; align-items: center;
    justify-content: center; cursor: pointer; box-shadow: 0 1px 4px rgba(46, 43, 63, 0.25); }
  .board-cbadge.done { background: var(--done, #2f9e44); }
  .board-thread { position: absolute; width: 288px; max-height: 60%; display: flex; flex-direction: column; z-index: 6;
    background: var(--panel); border: 1px solid var(--border); border-radius: 12px; box-shadow: 0 10px 30px rgba(46, 43, 63, 0.18); }
  .board-thread .bt-head { display: flex; align-items: center; padding: 10px 12px; border-bottom: 1px solid var(--border); font-size: 13px; }
  .board-thread .bt-close { margin-left: auto; border: none; background: none; color: var(--hint); cursor: pointer; font-size: 13px; }
  .board-thread .bt-list { overflow: auto; padding: 4px 12px; flex: 1; }
  .board-thread .bt-comment { padding: 8px 0; border-bottom: 1px solid var(--border); font-size: 13px; }
  .board-thread .bt-comment:last-child { border-bottom: none; }
  .board-thread .bt-comment.resolved { opacity: 0.55; }
  .board-thread .bt-meta { display: flex; gap: 8px; align-items: baseline; font-size: 11.5px; color: var(--hint); }
  .board-thread .bt-meta b { font-size: 12.5px; color: var(--text); }
  .board-thread .bt-text { margin: 3px 0 5px; line-height: 1.45; word-break: break-word; }
  .board-thread .bt-actions { display: flex; gap: 10px; }
  .board-thread .bt-actions button { border: none; background: none; padding: 0; font-size: 11.5px; color: var(--hint); cursor: pointer; }
  .board-thread .bt-actions button:hover { color: var(--purple-dark); }
  .board-thread .bt-actions button.danger:hover { color: var(--urgent); }
  .board-thread .bt-compose { padding: 10px 12px; border-top: 1px solid var(--border); display: flex; flex-direction: column; gap: 8px; }
  .board-thread textarea { width: 100%; resize: none; border: 1px solid var(--border); border-radius: 8px; padding: 7px 9px; font: inherit; font-size: 13px; outline: none; }
  .board-thread textarea:focus { border-color: var(--purple); }
  .board-minimap { position: absolute; left: 16px; bottom: 16px; width: 168px; height: 112px; background: var(--panel);
    border: 1px solid var(--border); border-radius: 10px; overflow: hidden; cursor: pointer; box-shadow: 0 4px 14px rgba(46, 43, 63, 0.1); }
  .wb-wrap.presenting .board-minimap, .wb-wrap.presenting .board-thread { display: none; }
  .board-lock { position: absolute; left: -8px; top: -8px; width: 20px; height: 20px; border-radius: 50%; background: var(--panel);
    border: 1px solid var(--border); color: var(--hint); display: inline-flex; align-items: center; justify-content: center; }
  .board-item.found { outline: 2px solid #f8ae00; outline-offset: 2px; }
  .board-search { position: absolute; left: 50%; top: 16px; transform: translateX(-50%); display: flex; align-items: center; gap: 4px;
    background: var(--panel); border: 1px solid var(--border); border-radius: 10px; padding: 5px 8px; box-shadow: 0 6px 18px rgba(46, 43, 63, 0.14); }
  .board-search input { border: none; outline: none; font: inherit; font-size: 13px; width: 190px; background: none; }
  .board-search span { font-size: 11.5px; color: var(--hint); min-width: 40px; text-align: center; }
  .board-search button { border: none; background: none; color: var(--text-soft); cursor: pointer; padding: 2px 6px; border-radius: 6px; font-size: 13px; }
  .board-search button:hover { background: var(--bg); }
  .board-image { padding: 0; overflow: hidden; background: #fff; box-shadow: 0 2px 8px rgba(46, 43, 63, 0.12); }
  .board-img { width: 100%; height: 100%; object-fit: contain; border-radius: 10px; pointer-events: none; }
  .board-img-loading { margin: auto; font-size: 12px; color: var(--hint); }
  .board-task { background: var(--panel); border: 1px solid var(--border); box-shadow: 0 2px 8px rgba(46, 43, 63, 0.1); padding: 10px 12px; gap: 6px; }
  .bt-head { display: flex; align-items: center; gap: 8px; }
  .bt-id { font-size: 11px; color: var(--hint); margin-left: auto; }
  .bt-name { font-size: 13.5px; font-weight: 600; line-height: 1.35; overflow: hidden; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; }
  .bt-name.missing { color: var(--hint); font-weight: 500; }
  .bt-foot { display: flex; align-items: center; gap: 6px; margin-top: auto; }
  .bt-due { font-size: 11.5px; color: var(--hint); }
  .bt-due.overdue { color: var(--urgent); }
  .bt-people { margin-left: auto; display: inline-flex; }
  .bt-people .avatar { width: 22px; height: 22px; font-size: 10px; margin-left: -6px; border: 2px solid var(--panel); }

  .board-toolbar { position: absolute; left: 14px; top: 14px; display: flex; align-items: center; gap: 3px; padding: 5px;
    background: var(--panel); border: 1px solid var(--border); border-radius: 12px; box-shadow: 0 6px 20px rgba(46, 43, 63, 0.12); }
  .board-tool { width: 32px; height: 32px; display: inline-flex; align-items: center; justify-content: center;
    border: none; background: none; border-radius: 8px; color: var(--text-soft); cursor: pointer; }
  .board-tool:hover { background: var(--bg); color: var(--text); }
  .board-tool.active { background: var(--purple-light); color: var(--purple-dark); }
  .board-sep { width: 1px; height: 20px; background: var(--border); margin: 0 4px; }
  .board-swatches { display: inline-flex; gap: 4px; }
  .board-swatch { width: 17px; height: 17px; border-radius: 50%; border: 1.5px solid rgba(46, 43, 63, 0.12); cursor: pointer; padding: 0; }
  .board-swatch.on { box-shadow: 0 0 0 2px var(--purple); }
  .board-readonly { font-size: 12px; color: var(--hint); padding: 6px 10px; }

  .board-sel-tools { position: absolute; display: flex; align-items: center; gap: 2px; padding: 4px 5px; z-index: 5;
    background: var(--panel); border: 1px solid var(--border); border-radius: 10px; box-shadow: 0 6px 18px rgba(46, 43, 63, 0.16); }
  .board-sel-tools button { width: 28px; height: 28px; display: inline-flex; align-items: center; justify-content: center;
    border: none; background: none; border-radius: 7px; color: var(--text-soft); cursor: pointer; }
  .board-sel-tools button:hover { background: var(--bg); color: var(--text); }
  .board-sel-tools button.danger:hover { background: var(--danger-bg); color: var(--urgent); }

  .board-zoom { position: absolute; right: 16px; bottom: 16px; display: flex; align-items: center; gap: 2px; padding: 4px;
    background: var(--panel); border: 1px solid var(--border); border-radius: 10px; box-shadow: 0 4px 14px rgba(46, 43, 63, 0.12); font-size: 12px; }
  .board-zoom button { border: none; background: none; color: var(--text-soft); cursor: pointer; padding: 4px 8px; border-radius: 6px; font: inherit; }
  .board-zoom button:hover { background: var(--bg); }
  .board-zoom span { min-width: 44px; text-align: center; color: var(--hint); cursor: pointer; }
  .board-hint { position: absolute; left: 50%; bottom: 16px; transform: translateX(-50%); font-size: 11.5px; color: var(--hint);
    background: rgba(255, 255, 255, 0.82); padding: 4px 12px; border-radius: 20px; pointer-events: none; white-space: nowrap; }
  .board-band { position: absolute; border: 1.5px solid var(--purple); background: rgba(123, 104, 238, 0.09); border-radius: 4px; pointer-events: none; }
  .board-band.ghost { border-style: dashed; background: rgba(123, 104, 238, 0.05); }

  .board-empty { position: absolute; left: 50%; top: 46%; transform: translate(-50%, -50%); text-align: center; max-width: 620px;
    background: var(--panel); border: 1px solid var(--border); border-radius: 14px; padding: 22px 26px; box-shadow: 0 8px 30px rgba(46, 43, 63, 0.1); }
  .board-empty h3 { font-size: 16px; font-weight: 700; }
  .board-empty p { font-size: 13px; color: var(--hint); margin: 6px 0 14px; }
  .board-empty-templates { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
  .board-empty-templates button { text-align: left; padding: 10px 12px; border: 1px solid var(--border); border-radius: 10px;
    background: var(--bg); cursor: pointer; font: inherit; color: var(--text); }
  .board-empty-templates button:hover { border-color: var(--purple); background: var(--tpl-hover); }
  .board-empty-templates b { display: block; font-size: 13px; }
  .board-empty-templates small { color: var(--hint); font-size: 11.5px; }
  .board-template-item { display: block; line-height: 1.35; }
  .board-template-item small { display: block; color: var(--hint); font-size: 11.5px; }
  .board-cursors { position: absolute; inset: 0; pointer-events: none; overflow: hidden; }
  .board-cursor { position: absolute; display: flex; align-items: flex-start; gap: 2px; transform: translate(-2px, -2px); transition: left 0.08s linear, top 0.08s linear; }
  .board-cursor span { font-size: 11px; font-weight: 600; color: #fff; padding: 2px 7px; border-radius: 10px; white-space: nowrap; margin-top: 10px; }
  .board-people { position: absolute; right: 16px; top: 16px; display: flex; gap: -4px; }
  .board-person { width: 26px; height: 26px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center;
    color: #fff; font-size: 12px; font-weight: 700; border: 2px solid var(--panel); margin-left: -6px; }
  .board-task-menu { width: 300px; }
  .board-task-option { align-items: center; gap: 8px; }
  .bto-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .bto-list { font-size: 11px; color: var(--hint); flex-shrink: 0; }
  .doc-head-row { display: flex; align-items: center; gap: 6px; }
  .doc-icon-btn { border: none; background: none; font-size: 26px; line-height: 1; cursor: pointer; padding: 2px 4px; border-radius: 8px; }
  .doc-icon-btn:hover:not(:disabled) { background: var(--bg); }
  .doc-menu { width: 262px; max-height: 260px; overflow: auto; }
  .doc-menu .status-menu-item { display: block; line-height: 1.35; }
  .doc-menu .status-menu-item small { display: block; color: var(--hint); font-size: 11.5px; }
  .doc-menu .status-menu-item.active { background: var(--purple-light); }
  .icon-grid { display: grid; grid-template-columns: repeat(8, 1fr); gap: 2px; padding: 6px; }
  .icon-grid button { border: none; background: none; font-size: 19px; cursor: pointer; padding: 5px; border-radius: 7px; }
  .icon-grid button:hover { background: var(--bg); }
  .md-table-wrap { overflow-x: auto; margin: 10px 0; }
  .md-table { border-collapse: collapse; font-size: 13.5px; }
  .md-table th, .md-table td { border: 1px solid var(--border); padding: 6px 10px; text-align: left; }
  .md-table th { background: var(--bg); font-weight: 600; }
  .md-view hr { border: none; border-top: 1px solid var(--border); margin: 14px 0; }
  ul.md-todo { list-style: none; padding-left: 2px; }
  .md-todo-item { display: flex; align-items: flex-start; gap: 8px; }
  .md-todo-item input { margin-top: 3px; }
  .md-todo-item.done { color: var(--hint); text-decoration: line-through; }
  .doc-templates { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 18px; font-size: 12.5px; color: var(--hint); }
  .doc-templates button { border: 1px solid var(--border); background: var(--panel); border-radius: 20px; padding: 5px 12px;
    font: inherit; font-size: 12.5px; color: var(--text); cursor: pointer; }
  .doc-templates button:hover { border-color: var(--purple); color: var(--purple-dark); }
  .doc-backlinks { margin-top: 28px; padding-top: 14px; border-top: 1px solid var(--border); }
  .doc-backlinks h4 { font-size: 11px; text-transform: uppercase; letter-spacing: 0.4px; color: var(--hint); margin-bottom: 8px; }
  .doc-backlinks button { display: inline-flex; align-items: center; gap: 6px; border: 1px solid var(--border); background: var(--panel);
    border-radius: 8px; padding: 5px 10px; margin: 0 6px 6px 0; font: inherit; font-size: 12.5px; cursor: pointer; }
  .doc-backlinks button:hover { border-color: var(--purple); }
  .page-ref { display: inline-flex; align-items: center; gap: 4px; color: var(--purple-dark); text-decoration: none;
    border-bottom: 1px solid var(--purple); }
  .doc-link-icon { display: inline-block; width: 16px; }
  .doc-conflict { background: var(--warn-bg-2); border: 1px solid var(--warn-edge); border-radius: 10px; padding: 12px 14px; margin-bottom: 14px; font-size: 13px; }
  .doc-conflict p { color: var(--text-soft); margin: 4px 0 10px; }
  .dc-actions { display: flex; gap: 8px; }
  .dc-actions button { border: 1px solid var(--border); background: var(--panel); border-radius: 8px; padding: 5px 12px; font: inherit; font-size: 12.5px; cursor: pointer; }
  .dc-actions .primary-btn { border-color: var(--purple); }
  /* The two buttons the app uses everywhere. They had no look of their own: every rule for them
     was written inside the one container that needed it (a dialog's actions, a comment's, the
     draft card's), so the same class used anywhere else came out as the browser's own grey box.
     This is the look; the container rules that follow still win where they say something else. */
  .ghost-btn, .primary-btn {
    font: inherit; font-size: 13px; font-weight: 600; line-height: 1.35; padding: 5px 13px;
    border-radius: 9px; cursor: pointer; border: 1px solid var(--border);
    background: var(--panel); color: var(--text);
  }
  .ghost-btn:hover { background: var(--row-hover); }
  .primary-btn { border-color: var(--purple); background: var(--purple); color: #fff; }
  .primary-btn:hover { background: var(--purple-dark); }
  .ghost-btn:disabled, .primary-btn:disabled { opacity: 0.6; cursor: default; }
  .ghost-btn.danger { color: var(--urgent); }

  /* Above everything it can be raised from — a panel, a modal, the board — because a dialog is
     always the question being asked right now. Below this it was drawn behind the chat's own panel
     and the answer could not be clicked. */
  .app-dialog-overlay { position: fixed; inset: 0; background: rgba(28, 25, 45, 0.35); display: flex; align-items: center;
    justify-content: center; z-index: 320; padding: 20px; }
  .app-dialog { background: var(--panel); border-radius: 14px; box-shadow: 0 20px 50px rgba(28, 25, 45, 0.25); padding: 20px 22px;
    width: 100%; max-width: 380px; }
  .app-dialog h3 { font-size: 15.5px; font-weight: 700; }
  .app-dialog p { font-size: 13px; color: var(--text-soft); margin-top: 6px; line-height: 1.45; }
  .app-dialog input { width: 100%; margin-top: 14px; padding: 8px 10px; border: 1px solid var(--border); border-radius: 8px;
    font: inherit; font-size: 13.5px; outline: none; }
  .app-dialog input:focus { border-color: var(--purple); }
  /* The statuses editor: a row per status, dragged into the order a team works in. */
  .app-dialog.wide { width: min(560px, 92vw); }
  /* The edit button sits with the person it edits, not in a trailing column: on a phone the table
     scrolls sideways and the last column is the one nobody ever reaches. */
  .member-who { display: inline-flex; align-items: center; gap: 6px; }
  .member-edit {
    border: none; background: none; color: var(--hint); cursor: pointer; padding: 2px 3px;
    border-radius: 6px; line-height: 0; opacity: 0.55;
  }
  .member-edit:hover { background: var(--bg); color: var(--purple-dark); opacity: 1; }
  .mm-head {
    display: flex; align-items: center; gap: 12px; padding: 0 0 14px; margin-bottom: 4px;
    border-bottom: 1px solid var(--border);
  }
  .mm-face .avatar { width: 46px; height: 46px; font-size: 18px; }
  .mm-who { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
  .mm-who b { font-size: 15px; }
  .mm-check { display: inline-flex; align-items: center; gap: 6px; color: var(--hint); font-size: 13px; white-space: nowrap; }
  .mm-block { margin: 6px 0 14px; }
  .mm-block > label { display: block; font-size: 11px; font-weight: 700; color: var(--hint); text-transform: uppercase; letter-spacing: 0.4px; margin-bottom: 5px; }
  .mm-block input[type="text"], .mm-block input:not([type]) {
    border: 1px solid var(--border); border-radius: 8px; padding: 7px 9px; font: inherit; font-size: 13px; outline: none;
  }
  .mm-block .muted { font-size: 12px; margin-top: 5px; line-height: 1.45; }
  .st-list { display: flex; flex-direction: column; gap: 6px; margin: 4px 0 12px; }
  .st-row { display: flex; align-items: center; gap: 8px; }
  .st-grip { color: var(--placeholder-icon); cursor: grab; user-select: none; }
  .st-name { flex: 1; min-width: 0; border: 1px solid var(--border); border-radius: 8px; padding: 6px 9px; font: inherit; font-size: 13px; outline: none; }
  .st-name:focus, .st-cat:focus { border-color: var(--purple); }
  .st-cat { border: 1px solid var(--border); border-radius: 8px; padding: 6px 8px; font: inherit; font-size: 12.5px; outline: none; background: var(--panel); }
  .st-colour { width: 30px; height: 30px; padding: 0; border: 1px solid var(--border); border-radius: 8px; background: none; cursor: pointer; }
  .st-remove { border: none; background: none; color: var(--hint); cursor: pointer; padding: 4px 6px; border-radius: 7px; }
  .st-remove:hover:not(:disabled) { background: var(--bg); color: var(--urgent); }
  .st-remove:disabled { opacity: 0.3; cursor: default; }
  .st-add { display: flex; gap: 8px; align-items: center; }
  .st-add input { flex: 1; min-width: 0; border: 1px solid var(--border); border-radius: 8px; padding: 7px 9px; font: inherit; font-size: 13px; outline: none; }
  .st-add select { border: 1px solid var(--border); border-radius: 8px; padding: 7px 8px; font: inherit; font-size: 12.5px; background: var(--panel); }
  .st-note { font-size: 12px; margin-top: 10px; line-height: 1.5; }
  /* Picking who is in a group: a scrollable column of names with checkboxes, sized so a workspace
     of thirty people does not push the buttons off the screen. */
  .pick-people {
    max-height: 260px; overflow-y: auto; margin: 10px 0 4px; display: flex; flex-direction: column; gap: 2px;
    border: 1px solid var(--border); border-radius: 10px; padding: 6px;
  }
  .pick-person { display: flex; align-items: center; gap: 9px; padding: 7px 8px; border-radius: 8px; cursor: pointer; font-size: 13.5px; }
  .pick-person:hover { background: var(--row-hover); }
  .pick-person input { width: 15px; height: 15px; accent-color: var(--purple); }

  .app-dialog-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 18px; }
  .app-dialog-actions button { border-radius: 8px; padding: 7px 14px; font: inherit; font-size: 13px; cursor: pointer; }
  .app-dialog-actions .ghost-btn { border: 1px solid var(--border); background: var(--panel); color: var(--text-soft); }
  .app-dialog-actions .ghost-btn:hover { background: var(--bg); }
  .app-dialog-actions .primary-btn { border: none; background: var(--purple); color: #fff; }
  .app-dialog-actions .primary-btn.danger { background: var(--urgent); }
  /* rich text editor */
  .rich { border: 1px solid var(--border); border-radius: 10px; background: var(--panel); }
  .rich-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 1px; padding: 5px 6px; border-bottom: 1px solid var(--border); }
  .rich-bar button { min-width: 28px; height: 28px; display: inline-flex; align-items: center; justify-content: center; border: none;
    background: none; border-radius: 7px; color: var(--text-soft); cursor: pointer; font: inherit; font-size: 12.5px; font-weight: 700; padding: 0 6px; }
  .rich-bar button:hover { background: var(--bg); color: var(--text); }
  .rich-sep { width: 1px; height: 18px; background: var(--border); margin: 0 5px; }
  .rich-body { padding: 12px 14px; min-height: 120px; outline: none; font-size: 14px; line-height: 1.65; }
  .rich-body.empty::before { content: attr(data-placeholder); color: var(--placeholder-icon, #b9b5c6); pointer-events: none; }
  .rich-body:focus { outline: none; }
  .rich-body > *:first-child { margin-top: 0; }
  .rich-body p { margin: 0 0 8px; }
  .rich-body ul, .rich-body ol { margin: 0 0 8px 20px; }
  .rich-body blockquote { border-left: 3px solid var(--border); padding-left: 12px; color: var(--text-soft); margin: 0 0 8px; }
  .rich-body pre { background: var(--bg); border-radius: 8px; padding: 10px 12px; overflow-x: auto; margin: 0 0 8px; }
  .rich-modes { display: flex; gap: 6px; align-items: center; margin-bottom: 8px; }
  .rich-modes button { border: none; background: none; font: inherit; font-size: 12.5px; color: var(--hint); cursor: pointer; padding: 3px 8px; border-radius: 7px; }
  .rich-modes button.active { background: var(--purple-light); color: var(--purple-dark); font-weight: 600; }
  .doc-presence { display: inline-flex; margin-left: 6px; }
  .doc-person { width: 24px; height: 24px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center;
    color: #fff; font-size: 11.5px; font-weight: 700; border: 2px solid var(--panel); margin-left: -6px; }
  .doc-person.editing { box-shadow: 0 0 0 2px #2f9e44; }
  .ref-chip { display: inline-flex; align-items: center; gap: 4px; padding: 0 6px; border-radius: 6px; background: var(--purple-light);
    color: var(--purple-dark); font-size: 0.95em; cursor: pointer; }
  .ref-chip:hover { background: var(--ref-hover); }
  /* comments on a passage */
  .doc-comment-btn { position: fixed; z-index: 60; display: inline-flex; align-items: center; gap: 6px; padding: 5px 10px;
    background: var(--panel); border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 4px 14px rgba(46, 43, 63, 0.16);
    font: inherit; font-size: 12.5px; color: var(--text); cursor: pointer; }
  .doc-comment-btn:hover { border-color: var(--purple); color: var(--purple-dark); }
  mark.commented { background: var(--mark-bg); border-bottom: 2px solid #f8ae00; padding: 0 1px; cursor: pointer; }
  .page-comments { width: 260px; flex-shrink: 0; border-left: 1px solid var(--border); padding-left: 16px; }
  .pc-head { display: flex; align-items: center; gap: 8px; font-size: 11px; font-weight: 700; text-transform: uppercase;
    letter-spacing: 0.4px; color: var(--hint); margin-bottom: 10px; }
  .pc-head .count { background: var(--purple); color: #fff; border-radius: 9px; padding: 0 6px; font-size: 10.5px; }
  .pc-thread { border: 1px solid var(--border); border-radius: 10px; padding: 9px 11px; margin-bottom: 8px; cursor: pointer; background: var(--panel); }
  .pc-thread.open { border-color: var(--purple); }
  .pc-thread.resolved { opacity: 0.55; }
  .pc-thread.draft { border-color: var(--purple); cursor: default; }
  .pc-quote { font-size: 11.5px; color: var(--text-soft); border-left: 2px solid #f8ae00; padding-left: 7px; margin-bottom: 6px;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .pc-meta { display: flex; gap: 8px; align-items: baseline; font-size: 11px; color: var(--hint); }
  .pc-meta b { font-size: 12.5px; color: var(--text); }
  .pc-text { font-size: 13px; line-height: 1.45; margin: 3px 0 6px; word-break: break-word; }
  .pc-thread textarea { width: 100%; resize: none; border: 1px solid var(--border); border-radius: 8px; padding: 6px 8px;
    font: inherit; font-size: 13px; outline: none; }
  .pc-thread textarea:focus { border-color: var(--purple); }
  .pc-actions { display: flex; gap: 8px; margin-top: 6px; }
  .pc-actions button { border-radius: 7px; padding: 5px 10px; font: inherit; font-size: 12px; cursor: pointer; border: 1px solid var(--border); background: var(--panel); }
  .pc-actions .primary-btn { border: none; background: var(--purple); color: #fff; }
  .pc-actions.small button { border: none; background: none; padding: 0; color: var(--hint); font-size: 11.5px; }
  .pc-actions.small button:hover { color: var(--purple-dark); }
  .pc-actions.small button.danger:hover { color: var(--urgent); }
  /* Frosted glass for the things that float: menus, dialogs, panels, toolbars */
  .status-menu, .app-dialog, #field-panel, .board-toolbar, .board-sel-tools, .board-zoom, .board-present-bar,
  .board-thread, .board-minimap, .board-search, .doc-comment-btn {
    background: var(--glass-strong) !important;
    backdrop-filter: blur(20px) saturate(150%); -webkit-backdrop-filter: blur(20px) saturate(150%);
  }
  /* The task card and the modals keep the plain white they had: no glass on the surfaces
     that hold a whole screen of content. */
  .status-menu, .app-dialog { border: 1px solid var(--glass-edge); }
  .app-dialog-overlay { backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px); }
  .board-canvas { background-color: rgba(251, 250, 255, 0.55); }
  /* The assistant inside the chat view is a chat like the others: no panel of its own, the pane's
     wallpaper behind it, and its messages drawn as bubbles. These win over the panel rules below,
     which were for the side panel it used to be. */
  /* The assistant in a pane: it draws its own header and composer, so the pane is only a frame for
     it — the same ground and corners as any other pane. */
  .ch-beside-one.asst-pane { display: flex; }
  .asst-host { flex: 1; min-width: 0; min-height: 0; display: flex; }
  .ch-main #assistant, .asst-host #assistant {
    position: static; inset: auto; z-index: auto; width: auto; height: auto; flex: 1; min-height: 0;
    display: flex; flex-direction: column; background: none; border: none; border-radius: 0;
    box-shadow: none; backdrop-filter: none; -webkit-backdrop-filter: none; overflow: visible;
  }
  .ch-msg .ch-bubble.chat-msg { align-self: auto; font-size: 16px; line-height: 1.45; color: var(--text-strong); white-space: normal; }
  .ch-msg .ch-bubble.chat-msg.you { background: var(--bubble-mine); border-color: transparent; padding: 7px 11px 7px 12px; border-radius: 17px; border-bottom-right-radius: 5px; }
  .ch-msg .ch-bubble.chat-msg.bot {
    max-width: min(92%, 680px); background: var(--panel); border: 1px solid rgba(20, 15, 40, 0.06);
    padding: 9px 12px; border-radius: 17px; border-bottom-left-radius: 5px;
  }
  .asst-avatar { background: linear-gradient(135deg, #7c6cf0, #3fa2e8) !important; color: #fff !important; }
  .chat-row .asst-avatar svg { width: 27px; height: 27px; }
  .chat-pin { color: var(--hint); display: inline-flex; margin-left: 2px; }
  .asst-note {
    font-size: 13px; color: var(--text-soft); background: var(--glass-strong); border-radius: 12px;
    padding: 8px 12px; margin-top: 8px;
  }
  /* A digest waiting: a dot on Chats, where the assistant lives. */
  #rail-chat.has-news::after, #tab-chats.has-news::after {
    content: ''; width: 7px; height: 7px; border-radius: 50%; background: var(--purple);
    position: absolute; top: 6px; right: 14px;
  }
  #rail-chat { position: relative; }

  /* The Spaces page: every space with what is in it, in rows made for a thumb. */
  .sp-page { max-width: 720px; margin: 0 auto; padding: 0 12px; }
  .sp-head { display: flex; align-items: center; gap: 10px; padding: 8px 2px 10px; }
  .sp-head h1 { margin: 0; flex: 1; font-size: 28px; font-weight: 700; letter-spacing: -0.02em; color: var(--text); }
  .sp-add {
    width: 38px; height: 38px; border: none; border-radius: 50%; cursor: pointer;
    background: var(--purple-light); color: var(--purple-dark); display: inline-flex; align-items: center; justify-content: center;
  }
  .sp-add svg { width: 18px; height: 18px; }
  .sp-search { width: 100%; box-sizing: border-box; margin-bottom: 10px; }
  .sp-rows { padding-bottom: 8px; }
  .sp-row {
    display: flex; align-items: center; gap: 14px; min-height: 50px; padding: 4px 8px; border-radius: 12px;
    cursor: pointer; color: var(--text);
  }
  .sp-row:active, .sp-row:hover { background: var(--bg); }
  .sp-icon {
    width: 30px; height: 30px; flex-shrink: 0; border-radius: 8px; display: inline-flex; align-items: center;
    justify-content: center; color: var(--text-soft); border: 1px solid var(--border);
  }
  .sp-icon svg { width: 17px; height: 17px; }
  .sp-space .sp-icon { border: none; }
  .sp-dot {
    width: 30px; height: 30px; border-radius: 8px; color: #fff; font-size: 15px; font-weight: 700;
    display: inline-flex; align-items: center; justify-content: center;
  }
  .sp-name { flex: 1; min-width: 0; font-size: 17px; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .sp-space .sp-name { font-weight: 650; }
  .sp-count { font-size: 14px; color: var(--hint); }
  .sp-where { font-size: 13px; color: var(--hint); flex-shrink: 0; }
  .sp-btn {
    width: 36px; height: 36px; flex-shrink: 0; border: none; background: none; border-radius: 50%; cursor: pointer;
    color: var(--hint); display: inline-flex; align-items: center; justify-content: center;
  }
  .sp-btn svg { width: 18px; height: 18px; }
  .sp-caret svg { transform: rotate(90deg); transition: transform 0.15s; }
  .sp-caret.closed svg { transform: none; }
  /* What is inside a space hangs from it on a thin line, as in the reference. */
  .sp-children { margin-left: 22px; padding-left: 12px; border-left: 1.5px solid var(--border); }
  .sp-empty { padding: 10px 8px; font-size: 14px; color: var(--hint); }
  .sp-row.obj-article .sp-icon { color: #2f7fe0; }
  .sp-row.obj-whiteboard .sp-icon { color: #e0a800; }
  .sp-row.obj-dashboard .sp-icon { color: #9b4fd6; }

  /* The theme choice: three settings side by side, the chosen one lifted. */
  .theme-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
  .theme-pick { display: inline-flex; gap: 2px; padding: 3px; border-radius: 10px; background: var(--bg); border: 1px solid var(--border); }
  .theme-pick button {
    border: none; background: none; color: var(--text-soft); font: inherit; font-size: 13px; font-weight: 600;
    padding: 6px 14px; border-radius: 8px; cursor: pointer;
  }
  .theme-pick button.on { background: var(--panel); color: var(--text); box-shadow: 0 1px 3px rgba(20, 15, 40, 0.15); }

  /* assistant */
  #assistant {
    width: 380px; flex-shrink: 0; box-sizing: border-box; display: flex; flex-direction: column; overflow: hidden;
    background: var(--glass-strong);
    backdrop-filter: blur(24px) saturate(150%); -webkit-backdrop-filter: blur(24px) saturate(150%);
    border: 1px solid var(--glass-edge); border-radius: 18px;
    box-shadow: inset 0 1px 0 var(--glass-edge), 0 14px 40px rgba(16, 16, 30, 0.10);
  }
  .chat-head { display: flex; align-items: center; gap: 9px; padding: 12px 14px; border-bottom: 1px solid var(--border); font-size: 13.5px; }
  .chat-badge { font-size: 10.5px; color: var(--hint); background: var(--bg); border-radius: 20px; padding: 2px 8px; }
  .chat-close { margin-left: auto; border: none; background: none; color: var(--hint); cursor: pointer; font-size: 13px; }
  .chat-log { flex: 1; overflow-y: auto; padding: 12px 14px; display: flex; flex-direction: column; gap: 10px; }
  .chat-msg { font-size: 13px; line-height: 1.5; }
  .chat-msg.you { align-self: flex-end; max-width: 85%; background: var(--ink); color: var(--ink-text); padding: 7px 11px; border-radius: 12px 12px 3px 12px; white-space: pre-wrap; }
  .chat-msg.bot { align-self: flex-start; max-width: 100%; background: var(--panel); border: 1px solid var(--border);
    padding: 9px 11px; border-radius: 12px 12px 12px 3px; }
  .chat-msg.bot p { margin: 0 0 6px; }
  .chat-msg.bot p:last-child { margin-bottom: 0; }
  .chat-list { margin: 4px 0 6px 16px; display: flex; flex-direction: column; gap: 3px; }
  .chat-list li { line-height: 1.4; }
  .chat-task { color: var(--purple-dark); text-decoration: none; border-bottom: 1px solid rgba(91, 75, 212, 0.35); }
  .chat-sub { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.4px; color: var(--hint); margin: 8px 0 2px; }
  .chat-dim { font-size: 11.5px; color: var(--hint); }
  .chat-start { font-size: 12.5px; }
  .chat-digest-head { font-size: 11px; font-weight: 700; letter-spacing: 0.4px; text-transform: uppercase; color: var(--purple-dark); }
  .chat-when { font-size: 11.5px; color: var(--hint); margin-left: 4px; }
  .chat-when.late, .chat-when.overdue { color: var(--urgent); }
  .chat-who { font-size: 11.5px; color: var(--hint); margin-left: 4px; }
  .chat-score { font-size: 11px; color: var(--placeholder-icon); margin-left: 4px; }
  .chat-group { margin: 6px 0; }
  .chat-group-name { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.4px; color: var(--hint); }
  .chat-more { color: var(--hint); }
  .chat-actions { display: flex; gap: 8px; margin-top: 6px; }
  .chat-actions button, .chat-draft-foot button { border: 1px solid var(--border); background: var(--panel); border-radius: 8px;
    padding: 5px 10px; font: inherit; font-size: 12px; cursor: pointer; }
  .chat-actions button:hover { border-color: var(--purple); color: var(--purple-dark); }
  .chat-draft { margin-top: 8px; border-top: 1px solid var(--border); padding-top: 8px; display: flex; flex-direction: column; gap: 5px; }
  .chat-item { display: flex; align-items: flex-start; gap: 7px; font-size: 12.5px; line-height: 1.4; }
  /* a subtask sits under its task, with a hairline to show what it belongs to */
  .chat-item.sub { margin-left: 16px; padding-left: 9px; border-left: 2px solid var(--border); }
  .chat-sub-item { margin-left: 14px; list-style: circle; }
  .chat-item-text { flex: 1; }
  .chat-item-meta { display: flex; flex-wrap: wrap; gap: 4px; }
  .chat-item-meta .chip { font-size: 10.5px; background: var(--bg); border-radius: 20px; padding: 1px 7px; color: var(--text-soft); }
  .chat-item-meta .chip.urgent { background: var(--danger-bg); color: var(--urgent); }
  .chat-item-meta .chip.high { background: var(--warn-bg-4); color: var(--warn-fg-2); }
  .chat-item-meta .chip.warn { background: var(--warn-bg-2); color: var(--warn-fg-2); }
  /* Said when the tasks have nowhere to go yet — a space with no lists, or a place we could not
     find. It carries an input, so it needs to read as part of the form rather than as a caption. */
  .chat-draft-note { font-size: 12px; color: var(--text-soft); line-height: 1.5; margin: 2px 0 4px; }
  .chat-inline-input { border: 1px solid var(--border); border-radius: 6px; padding: 2px 6px;
    font: inherit; font-size: 12px; background: var(--panel); color: inherit; min-width: 110px; max-width: 180px; }
  .chat-draft-foot { display: flex; align-items: center; gap: 8px; margin-top: 4px; }
  .chat-draft-foot select { flex: 1; min-width: 0; border: 1px solid var(--border); border-radius: 8px; padding: 5px 7px; font: inherit; font-size: 12px; }
  .chat-draft-foot .primary-btn { border: none; background: var(--ink); color: var(--ink-text); }
  .chat-compose { border-top: 1px solid var(--border); padding: 10px 12px; display: flex; flex-direction: column; gap: 8px; }
  .chat-compose textarea { width: 100%; resize: none; border: 1px solid var(--border); border-radius: 10px; padding: 8px 10px;
    font: inherit; font-size: 13px; outline: none; max-height: 160px; }
  .chat-compose textarea:focus { border-color: var(--purple); }
  .chat-compose .primary-btn { align-self: flex-end; border: none; background: var(--ink); color: var(--ink-text); border-radius: 8px;
    padding: 6px 14px; font: inherit; font-size: 12.5px; font-weight: 600; cursor: pointer; }
  .meaning-block { margin: 14px 24px 22px; border-top: 1px solid var(--border); padding-top: 10px; }
  .meaning-title { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.4px; color: var(--hint); margin-bottom: 4px; }
  .meaning-row { display: flex; align-items: center; gap: 10px; padding: 6px 4px; border-radius: 7px; cursor: pointer; font-size: 13px; }
  .meaning-row:hover { background: var(--bg); }
  .meaning-where { margin-left: auto; font-size: 11.5px; color: var(--hint); }
  .overdue-banner { display: flex; align-items: center; gap: 10px; background: var(--warn-bg-2); border: 1px solid var(--warn-edge);
    border-radius: 10px; padding: 8px 12px; margin-bottom: 12px; font-size: 12.5px; color: #92400e; }
  /* dashboard */
  .dashboard { display: flex; flex-direction: column; gap: 16px; }
  .dash-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; }
  .dash-tile { background: var(--panel); border: 1px solid var(--border); border-radius: 12px; padding: 14px 16px; }
  .dash-tile.bad .dash-value { color: var(--urgent); }
  .dash-label { font-size: 12px; color: var(--hint); }
  .dash-value { font-size: 28px; font-weight: 700; margin-top: 4px; }
  .chart-legend.row { flex-direction: row; flex-wrap: wrap; gap: 14px; margin-top: 6px; }
  .dash-toolbar { display: flex; gap: 14px; justify-content: flex-end; }
  .dash-plain { grid-column: 1 / -1; position: relative; padding-top: 4px; }
  .dash-plain .dash-menu { position: absolute; right: 2px; top: -18px; }
  .dash-menu { border: none; background: none; color: var(--hint); cursor: pointer; margin-left: auto; padding: 0 2px; display: inline-flex; }
  .dash-menu:hover { color: var(--purple-dark); }
  .dash-card h3 { display: flex; align-items: center; }
  .dash-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(330px, 1fr)); gap: 14px; }
  .dash-card { background: var(--panel); border: 1px solid var(--border); border-radius: 12px; padding: 14px 16px; overflow: hidden; }
  .dash-card.wide { grid-column: 1 / -1; }
  .dash-card h3 { font-size: 13px; font-weight: 700; margin-bottom: 10px; }
  .chart-row { display: flex; gap: 18px; align-items: center; flex-wrap: wrap; }
  .chart-legend { font-size: 12.5px; display: flex; flex-direction: column; gap: 6px; }
  .chart-legend .dot, .stacked-legend .dot { width: 9px; height: 9px; border-radius: 50%; display: inline-block; margin-right: 7px; }
  .chart-legend b { margin-left: 8px; }
  .chart-legend .pct { color: var(--hint); margin-left: 6px; }
  .stacked { display: flex; height: 16px; border-radius: 8px; overflow: hidden; background: var(--bg); }
  .stacked span { display: block; height: 100%; }
  .stacked-legend { display: flex; flex-wrap: wrap; gap: 14px; margin-top: 10px; font-size: 12.5px; color: var(--text-soft); }
  .dash-table { width: 100%; border-collapse: collapse; font-size: 13px; }
  .dash-table th { text-align: left; font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.4px; color: var(--hint); padding: 4px 8px; }
  .dash-table td { padding: 7px 8px; border-top: 1px solid var(--border); cursor: pointer; }
  .dash-table tr:hover td { background: var(--bg); }
  .dash-table .muted { color: var(--hint); }
  .dash-table .overdue { color: var(--urgent); font-weight: 600; }
  .dash-activity { display: flex; flex-direction: column; gap: 8px; max-height: 320px; overflow-y: auto; }
  .dash-activity .act-event { cursor: pointer; }
  #toast { position: fixed; bottom: 22px; left: 50%; transform: translateX(-50%); background: #111; color: #fff; padding: 9px 14px; border-radius: 8px; font-size: 13px; z-index: 1000; max-width: 90vw; }
  .btn-danger { background: var(--urgent); color: #fff; border: none; border-radius: 8px; padding: 7px 14px; cursor: pointer; font-weight: 600; }

  /* ---------- the bell and what is waiting ---------- */
  /* The count sits on the bell, not in a corner: the bell is where a person looks to find out. */
  /* ---------- channels ----------
     Prefixed `ch-`, not `chat-`: the assistant panel already owns .chat-head, .chat-msg and
     friends, and these rules sat further down the file, so they were quietly restyling it. */
  /* The unread total on the menu item, so a channel with something in it is visible from anywhere
     rather than only once you go looking for it. */
  #ch-unread {
    margin-left: auto; min-width: 18px; height: 18px; padding: 0 5px; border-radius: 9px;
    background: var(--urgent); color: #fff; font-size: 10px; font-weight: 700; line-height: 18px;
    text-align: center; box-sizing: border-box;
  }
  /* Chats are laid out the way a messenger is, because that is what everybody already knows how to
     use: one list of every chat, newest first, each row saying who had the last word and what it
     was; open one and it has the screen. Side by side when there is room, one after the other on
     a phone (see the max-width rules below). */
  /* `position: relative` so the sheet that rises from the bottom is measured against the
     conversation rather than the window: on a desktop it should not cover the list of chats. */
  .ch-wrap { display: flex; height: 100%; min-height: 0; position: relative; }
  /* The dragged width arrives as a custom property, not as an inline width: an inline width beats
     every stylesheet rule, including the phone's, and a list of chats that keeps a desktop's 320px
     on a 360px screen leaves a strip of nothing down the side. */
  .ch-list {
    width: var(--chat-list-w, 320px); flex-shrink: 0; display: flex; flex-direction: column; min-height: 0;
  }
  /* The divider is draggable on a wide screen: the right width for a list of chats depends on how
     long the names are and how much of a conversation somebody wants to see, which is not a thing
     to decide for everybody. On a phone the list and the conversation are separate screens. */
  .ch-split {
    width: 5px; flex-shrink: 0; cursor: col-resize; background: var(--border);
    background-clip: content-box; border-left: 2px solid transparent; border-right: 2px solid transparent;
  }
  .ch-split:hover, body.ch-resizing .ch-split { background: var(--purple); }
  body.ch-resizing { cursor: col-resize; user-select: none; }
  @media (max-width: 780px) { .ch-split { display: none; } }
  .chat-list-head { display: flex; align-items: center; gap: 8px; padding: 0 12px 10px 0; }
  .chat-search {
    flex: 1; min-width: 0; border: 1px solid var(--border); border-radius: 20px; background: var(--bg);
    padding: 8px 14px; font: inherit; font-size: 15px; color: var(--text); outline: none;
  }
  .chat-search:focus { border-color: var(--purple); background: var(--panel); }
  /* The two round buttons beside the search: a pencil for a new chat, a gear for how chats look.
     They share a shape but not a class — a test that clicks "the new-chat button" should never
     have two things to choose between. */
  .chat-new, .chat-skin-btn {
    width: 34px; height: 34px; flex-shrink: 0; border: none; border-radius: 50%; cursor: pointer;
    background: var(--purple-light); color: var(--purple-dark);
    display: inline-flex; align-items: center; justify-content: center;
  }
  .chat-new:hover, .chat-skin-btn:hover { background: var(--purple); color: #fff; }
  .chat-rows { flex: 1; min-height: 0; overflow-y: auto; padding-right: 8px; }
  .chat-row {
    display: flex; align-items: center; gap: 12px; padding: 11px 10px; border-radius: 12px;
    cursor: pointer; margin-bottom: 2px;
  }
  .chat-row:hover { background: var(--bg); }
  .chat-row.active { background: var(--purple-light); }
  .chat-row .ch-avatar { width: 54px; height: 54px; border-radius: 50%; font-size: 20px; }
  .chat-hash { background: var(--bg); color: var(--hint); font-weight: 600; }
  /* A group chat has no one face to show, so it carries the same mark everywhere: in the list, in
     the header, and wherever else a chat is named. */
  .chat-people { background: var(--purple-light); color: var(--purple-dark); }
  .chat-row-main { flex: 1; min-width: 0; }
  .chat-row-top, .chat-row-bottom { display: flex; align-items: center; gap: 6px; }
  .chat-row-bottom { margin-top: 6px; }
  .chat-row-name {
    font-size: 17px; font-weight: 600; color: var(--text);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .chat-row-time { margin-left: auto; flex-shrink: 0; font-size: 13px; color: var(--hint); }
  .chat-row.unread .chat-row-time { color: var(--purple); font-weight: 600; }
  .chat-row-line {
    flex: 1; min-width: 0; font-size: 15.5px; color: #858a94;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .chat-row.unread .chat-row-line { color: #6b707a; }
  .chat-row-who { color: var(--purple-dark); }
  .chat-quiet { color: var(--hint); }
  .ch-count {
    margin-left: auto; flex-shrink: 0; background: var(--purple); color: #fff; font-size: 11px;
    font-weight: 700; border-radius: 10px; padding: 0 7px; line-height: 20px; min-width: 20px;
    text-align: center; box-sizing: border-box;
  }
  /* Quiet on purpose: which of your colleagues is an agent is worth knowing and not worth
     shouting, and the list is read by name. */
  .ch-bot {
    flex-shrink: 0; font-size: 9.5px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
    color: var(--hint); border: 1px solid var(--border); border-radius: 5px; padding: 0 4px;
    line-height: 14px; vertical-align: middle;
  }

  /* The way back to the list. Only a phone needs it: on a wide screen the list never went away. */
  .chat-back {
    display: none; width: 34px; height: 34px; margin-left: -8px; flex-shrink: 0; border: none;
    border-radius: 50%; background: none; color: var(--text); cursor: pointer;
    align-items: center; justify-content: center;
  }
  .chat-back:hover { background: var(--bg); }
  .chat-head-text { min-width: 0; }
  .chat-head-name { font-weight: 700; font-size: 18.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .ch-head .ch-avatar { width: 38px; height: 38px; border-radius: 50%; font-size: 15px; }

  @media (max-width: 780px) {
    .ch-list { width: 100%; border-right: none; }
    .chat-list-head { padding: 0 10px 10px; }
    .chat-rows { padding: 0 4px; }
    .ch-wrap.has-open .ch-list { display: none; }
    .ch-wrap:not(.has-open) .ch-main { display: none; }
    /* A thread on a phone is its own screen, the way an open chat is: side by side there is room
       for one of them, and the one being read is the thread. */
    .ch-wrap.has-thread .ch-main { display: none; }
    /* Two conversations do not fit on a phone; a second pane, beside or below, is a desktop
       arrangement. */
    .ch-beside, .ch-below, .pane-split { display: none; }
    .ch-thread { width: 100%; margin-left: 0; border: none; border-radius: 0; }
    /* On a phone an open chat is the whole screen, picture included: it runs from the top edge to
       the bottom one, behind the floating menu bar, and the box you type in floats on it above the
       bar. The view's own padding is what kept it in a box. */
    body.view-chat.chat-open #view-body { padding: 0; }
    body.view-chat.chat-open .ch-wrap { height: 100%; }
    .ch-wrap .ch-main { margin-left: 0; border-radius: 0; }
    /* --kb-top and --kb-bottom are what the keyboard covers (applyChatViewport in app/channels.js):
       both bars move with it, so the line saying who you are writing to stays on screen and the box
       you type in sits on the keyboard rather than behind it. */
    .ch-wrap .ch-head {
      top: calc(var(--kb-top, 0px) + 6px + env(safe-area-inset-top, 0px)); left: 10px; right: 10px;
      padding: 5px 10px;
    }
    .ch-wrap .ch-head .ch-avatar { width: 32px; height: 32px; font-size: 13px; }
    .ch-wrap .chat-head-name { font-size: 15.5px; }
    .ch-wrap .ch-topic { font-size: 12px; }
    .ch-wrap .chat-back { margin-left: -4px; }
    .ch-wrap .ch-foot {
      bottom: calc(var(--kb-bottom, 0px) + 10px + env(safe-area-inset-bottom, 0px)); left: 10px; right: 10px;
    }
    .ch-wrap .ch-messages {
      padding-left: 10px; padding-right: 10px;
      padding-top: calc(var(--kb-top, 0px) + var(--ch-head-h, 56px) + 20px);
      padding-bottom: calc(var(--kb-bottom, 0px) + var(--ch-foot-h, 56px) + 20px);
    }
    /* Inside a conversation the menu bar steps away, as it does in Telegram: the chat is the whole
       screen and the way out is the arrow at the top. The list of chats keeps it. */
    body.view-chat.chat-open #tabbar { display: none; }
    .ch-wrap .ch-head { border-radius: 16px; }
    .chat-back { display: inline-flex; }
  }

  /* A chat carries its own header — who you are writing to — so the app's title bar above it says
     the same thing twice and steals a strip of the conversation. It goes in the chat view, on a
     phone and on a desktop alike, and the pane fills what it leaves. */
  /* A menu folded to its icons, when the person asks for it and until they ask otherwise. The
     head becomes a column: the arrow that opens it again on top, the logo under it, so the way
     back is the first thing under the cursor. Search goes: as an icon it was a button that left
     the view you were in, and nobody asked for that. On a phone the menu is a drawer anyway. */
  @media (min-width: 781px) {
    body.side-folded #sidebar {
      width: 64px; padding-left: 6px; padding-right: 6px; align-items: center;
    }
    body.side-folded #sidebar .side-search { display: none; }
    body.side-folded #sidebar .side-section-title,
    body.side-folded #sidebar #side-lists,
    body.side-folded #sidebar #new-space-btn { display: none; }
    body.side-folded #sidebar .side-nav-item { justify-content: center; gap: 0; padding: 10px 0; width: 44px; position: relative; }
    /* The label is the text node beside the icon; hiding it without touching the icon or the
       unread dot is what font-size: 0 does here, and the icon keeps its own size. */
    body.side-folded #sidebar .side-nav-item { font-size: 0; }
    body.side-folded #sidebar .side-nav-item svg { width: 20px; height: 20px; }
    body.side-folded #sidebar .side-head { flex-direction: column; justify-content: center; gap: 10px; padding-top: 2px; }
    body.side-folded #sidebar .side-foot { flex-direction: column; gap: 8px; align-items: center; }
    /* Unread, folded: a dot on the corner of the icon rather than a number nobody can read at
       10px. The count is still in the title for anyone who hovers. */
    body.side-folded #sidebar #ch-unread {
      position: absolute; top: 6px; right: 6px; min-width: 9px; width: 9px; height: 9px;
      padding: 0; font-size: 0; border-radius: 50%; background: var(--urgent);
      box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.35);
    }
  }

  body.view-chat #topbar { display: none; }
  body.view-chat #view-body { padding: 0; }
  body.view-chat .ch-wrap { height: 100%; }
  /* On a wide screen the pane keeps a margin from the window; a phone gives the chat the screen. */
  /* The conversation is the right half of the window, from the divider to the edges: no frame
     around it and no rounded corners, so the wallpaper meets the list rather than floating on a
     panel. The list keeps its own padding; the divider is its right border. */
  @media (min-width: 781px) {
    body.view-chat #view-body { padding: 0; }
    body.view-chat .ch-wrap { padding: 0; }
    body.view-chat .ch-list { padding-left: 14px; padding-top: 14px; }
    body.view-chat .ch-main { margin-left: 0; border-radius: 0; }
  }

  .ch-main { flex: 1; min-width: 0; display: flex; flex-direction: column; min-height: 0; margin-left: 18px; }

  /* The agents' conversations (app/channels.js, renderAgentLog): their pairs down the side, and the
     one being read as a log — who to whom, when — rather than as bubbles, because nobody reading it
     is one of the two sides. */
  .ch-avatar.agents-avatar, .chat-row .ch-avatar.agents-avatar, .ch-head .ch-avatar.agents-avatar {
    display: inline-flex; align-items: center; justify-content: center; color: #fff;
    background: linear-gradient(135deg, #9a8bff, #5f6df2);
  }
  /* Each conversation's two agents, one over the other, beside its name. */
  .al-pair-name { display: flex; align-items: center; gap: 9px; }
  .al-faces { display: inline-flex; flex-shrink: 0; }
  .al-faces .avatar { width: 26px; height: 26px; font-size: 11px; border: 2px solid var(--panel); box-sizing: content-box; }
  .al-faces .avatar + .avatar { margin-left: -9px; }
  .al-pair.active .al-faces .avatar { border-color: color-mix(in srgb, var(--purple) 14%, var(--panel)); }
  /* A log is read line by line, so it sits on the plain panel, not on the chat's wallpaper. */
  .agent-log {
    position: absolute; inset: 0; display: flex; min-height: 0; background: var(--panel);
    padding-top: calc(var(--ch-head-h, 56px) + 22px);
  }
  .al-pair-name { line-height: 1.3; }
  .agents-topic { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .al-pairs { width: 270px; flex-shrink: 0; overflow-y: auto; border-right: 1px solid var(--border); padding: 6px; }
  .al-pair {
    display: flex; flex-direction: column; gap: 2px; width: 100%; text-align: left; padding: 9px 10px; border: 0;
    border-radius: 9px; background: none; color: var(--text); cursor: pointer; font: inherit;
  }
  .al-pair:hover { background: var(--row-hover); }
  .al-pair.active { background: color-mix(in srgb, var(--purple) 14%, transparent); }
  .al-pair-name { font-weight: 600; font-size: 13.5px; }
  .al-pair-line { font-size: 12.5px; color: var(--text-soft); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .al-pair-when { font-size: 11px; color: var(--hint); }
  .al-feed { flex: 1; min-width: 0; overflow-y: auto; padding: 10px 18px 24px; }
  .al-line { display: flex; gap: 10px; padding: 7px 0; }
  .al-line .ch-avatar { flex-shrink: 0; margin-top: 2px; }
  .al-body { min-width: 0; flex: 1; }
  .al-meta { display: flex; align-items: baseline; flex-wrap: wrap; gap: 6px; font-size: 13px; color: var(--text); }
  .al-arrow { color: var(--hint); }
  .al-to-group { color: var(--text-soft); font-weight: 600; }
  .al-meta time { font-size: 11.5px; color: var(--hint); }
  .al-edited { font-size: 11px; color: var(--hint); font-style: italic; }
  .al-answers { font-size: 12px; color: var(--hint); margin-top: 2px; }
  .al-text { font-size: 14px; line-height: 1.45; margin-top: 3px; overflow-wrap: anywhere; }
  @media (max-width: 780px) {
    .al-pairs { width: 100%; border-right: 0; }
    .agent-log.has-open .al-pairs { display: none; }
    .agent-log:not(.has-open) .al-feed { display: none; }
    .al-feed { padding: 8px 12px 90px; }
    .agent-log { padding-top: calc(var(--kb-top, 0px) + var(--ch-head-h, 56px) + 20px); }
  }
  /* The area right of the list is a row: the column being worked in, then the panes beside it. The
     column holds the conversation and whatever has been stacked under it — which is what "they only
     go in a row" was asking for. */
  .ch-stage { flex: 1; min-width: 0; display: flex; min-height: 0; }
  /* The conversation being worked in keeps a readable width whatever is opened beside it; the panes
     give way first, down to a width a sentence still fits in. Below that the window is simply too
     small for two conversations, and one of them should be closed. */
  .ch-col { flex: 1 1 auto; min-width: 300px; display: flex; flex-direction: column; min-height: 0; }
  .ch-below { display: flex; flex-direction: column; min-height: 0; }
  .ch-below[hidden] { display: none; }
  /* The grip between two panes: nothing until the pointer is on it, like the one between the chat
     list and the conversation. Five pixels of hit area, negative margins so it costs no layout. */
  .pane-split {
    width: 5px; margin: 0 -1px; flex-shrink: 0; cursor: col-resize; border-radius: 3px;
    background: transparent; transition: background 0.15s;
  }
  .pane-split.flat { width: auto; height: 5px; margin: -1px 0; cursor: row-resize; }
  .pane-split:hover, body.ch-resizing .pane-split { background: var(--purple); opacity: 0.5; }
  .ch-head {
    display: flex; align-items: center; gap: 10px; padding: 8px 12px; border-radius: 14px;
    background: var(--glass-strong); backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
    box-shadow: 0 6px 18px rgba(20, 15, 40, 0.16);
  }
  .ch-topic { font-weight: 400; font-size: 13.5px; color: var(--hint); }
  /* The conversation sits on its own tinted ground so the bubbles read as bubbles. */
  /* The picture sits behind the whole conversation — its header, the messages and the box you type
     in — the way a messenger's wallpaper does, rather than in a frame of its own. */
  /* The conversation fills the whole pane and the header and the box you type in float over it, so
     what is said scrolls under their glass instead of stopping above and below it. How much room
     the messages leave for them is measured (fitChatChrome in app/channels.js). */
  /* The wallpaper and the colour of your own words are two custom properties, written by
     app/chat-skin.js and defaulting to what we ship. Everything else follows the theme. */
  /* The light theme hangs the green drawing: its shading is drawn into the picture, so it is laid
     over the pane once, covering, rather than tiled at a size of its own the way the old doodles
     were. Underneath it, the green the picture averages to, for the moment before it arrives. */
  .ch-main, .ch-beside-one {
    --chat-paper: url('/chat-bg-green.png');
    --chat-paper-colour: #e3f0e0;
    --chat-paper-repeat: no-repeat;
    --chat-paper-size: cover;
    background: var(--chat-paper-colour) var(--chat-paper) center / cover;
    background-repeat: var(--chat-paper-repeat, no-repeat);
    border-radius: 14px; position: relative;
  }
  /* The dark theme has a ground of its own: the light one under a dark reading is a grey fog, and
     the bubbles stop standing off it. This is the mean of the dark drawing, as the above is of the light. */
  @media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .ch-main,
    :root:not([data-theme="light"]) .ch-beside-one { --chat-paper: none; --chat-paper-colour: #0c0c0c; }
  }
  :root[data-theme="dark"] .ch-main,
  :root[data-theme="dark"] .ch-beside-one { --chat-paper: none; --chat-paper-colour: #0c0c0c; }
  /* On a phone the wallpaper covers the screen, which is about its own shape. On a desktop that
     same picture blown up to a window's width is a few enormous doodles; tiled at its drawn size
     it reads as a pattern, which is what it is. */
  @media (min-width: 781px) {
    .ch-main, .ch-beside-one { background-size: var(--chat-paper-size, 420px auto); background-repeat: var(--chat-paper-repeat, repeat); }
  }

  /* The panel behind the gear: papers to pick from, and the colour of your own bubbles. */
  .skin-papers { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; padding: 6px 8px 8px; }
  .skin-paper {
    height: 54px; border-radius: 10px; border: 2px solid transparent; cursor: pointer; position: relative;
    background-color: var(--bg); background-position: center; overflow: hidden;
  }
  .skin-paper.picked { border-color: var(--purple); }
  .skin-paper .skin-bubble { position: absolute; right: 6px; bottom: 6px; width: 20px; height: 12px; border-radius: 6px; }
  .skin-own { display: inline-flex; align-items: center; justify-content: center; color: var(--hint); border: 2px dashed var(--border); }
  .skin-bubbles { display: flex; flex-wrap: wrap; gap: 6px; padding: 4px 8px 10px; }
  .skin-swatch { width: 24px; height: 24px; border-radius: 50%; border: 2px solid transparent; cursor: pointer; }
  .skin-swatch.picked { border-color: var(--purple); }
  .skin-reset { background: var(--bg); color: var(--hint); font-size: 13px; line-height: 1; }
  .chat-skin-btn { margin-left: 4px; }
  .ch-head, .ch-foot { position: absolute; left: 14px; right: 14px; z-index: 3; }
  .ch-head { top: 12px; }
  .ch-foot { bottom: 12px; }
  .ch-messages {
    position: absolute; inset: 0; overflow-y: auto;
    padding: calc(var(--ch-head-h, 56px) + 22px) 14px calc(var(--ch-foot-h, 56px) + 22px);
  }
  /* A message does not simply vanish at the edge: it dims into the band the header and the box sit
     in, so the top and the bottom of the conversation read as edges rather than as cuts. */
  .ch-main::before, .ch-main::after, .ch-beside-one::before, .ch-beside-one::after {
    content: ''; position: absolute; left: 0; right: 0; z-index: 2; pointer-events: none;
    border-radius: inherit;
  }
  .ch-main::before, .ch-beside-one::before {
    top: 0; height: calc(var(--kb-top, 0px) + var(--ch-head-h, 56px) + 58px);
    background: linear-gradient(to bottom, var(--ch-scrim),
      var(--ch-scrim) calc(var(--kb-top, 0px) + var(--ch-head-h, 56px) + 12px), transparent);
  }
  .ch-main::after, .ch-beside-one::after {
    bottom: 0; height: calc(var(--kb-bottom, 0px) + var(--ch-foot-h, 56px) + 58px);
    background: linear-gradient(to top, var(--ch-scrim),
      var(--ch-scrim) calc(var(--kb-bottom, 0px) + var(--ch-foot-h, 56px) + 12px), transparent);
  }

  /* Messages are bubbles, the way every messenger draws them: yours on the right in the accent
     colour, everybody else's on the left, each message its own bubble with the time tucked into its
     corner. A run from one person sits closer together; its last bubble has the pointed corner. */
  /* Every message stands on its own. A tight run used to read as the last bubble growing —
     especially from a bot, which writes several in a row — so the gap inside a run is only
     slightly smaller than the gap between people, not three pixels. */
  .ch-msg { display: flex; align-items: flex-end; gap: 8px; margin-top: 8px; }
  .ch-msg:not(.run-on) { margin-top: 14px; }
  .ch-msg.mine { flex-direction: row-reverse; }
  .ch-bubble {
    /* Wide, as a messenger's are (Andrey, 24 Sep, with a phone screenshot): a long message reads in
       long lines, not in a narrow column down the middle of the screen. */
    min-width: 0; max-width: 90%; padding: 7px 11px 7px 12px; border-radius: 17px;
    background: var(--panel); border: 1px solid rgba(20, 15, 40, 0.06);
    box-shadow: 0 1px 2px rgba(20, 15, 40, 0.14);
  }
  /* Yours in light blue, black text on both sides: read at a glance, and as dark as text gets. */
  .ch-msg.mine .ch-bubble { background: var(--bubble-mine); border-color: transparent; }
  /* The pointed corner marks the end of a run; every other bubble keeps all four corners round,
     so none of them looks like a continuation of the one above. */
  .ch-msg.theirs.run-end .ch-bubble { border-bottom-left-radius: 7px; }
  .ch-msg.mine.run-end .ch-bubble { border-bottom-right-radius: 7px; }
  .ch-author { font-size: 14.5px; font-weight: 600; color: var(--purple-dark); margin-bottom: 2px; }
  /* 17px is a phone size: a thumb's reach and an arm's length away. On a desktop the same bubble
     next to the rest of the app looked shouted, so the whole conversation steps down there. */
  #side-fold {
    margin-left: auto; border: none; background: none; color: var(--side-hint); cursor: pointer;
    padding: 4px; border-radius: 7px; display: inline-flex;
  }
  #side-fold:hover { color: var(--side-text); background: var(--side-hover); }
  /* Folded, the arrow sits above the logo: the first thing in the strip is the way out of it. */
  @media (max-width: 780px) { #side-fold { display: none; } }
  @media (min-width: 781px) {
    body.side-folded #sidebar #side-fold { margin: 0; order: -1; }
    body.side-folded #sidebar .ws-icon img { width: 34px; height: 34px; border-radius: 10px; }
  }

  /* The panel behind a chat's name: who you are writing to, what has been shared, and the switch
     that stops it ringing. A sheet over the conversation rather than a column beside it, because
     it is opened to look something up and then closed again. */
  .about-overlay {
    position: fixed; inset: 0; z-index: 260; background: rgba(12, 10, 24, 0.44);
    display: flex; align-items: flex-start; justify-content: center; padding: 6vh 16px 16px;
    overflow-y: auto;
  }
  .about-panel {
    position: relative; width: min(460px, 100%); max-height: 86vh; overflow-y: auto;
    background: var(--panel); color: var(--text); border: 1px solid var(--border);
    border-radius: 18px; padding: 22px 20px 18px; box-shadow: 0 24px 60px rgba(10, 8, 24, 0.34);
  }
  .about-close {
    position: absolute; top: 12px; right: 12px; border: none; background: none; color: var(--hint);
    cursor: pointer; border-radius: 8px; padding: 4px; display: inline-flex;
  }
  .about-close:hover { background: var(--row-hover); color: var(--text); }
  .about-head { display: flex; flex-direction: column; align-items: center; gap: 4px; text-align: center; margin-bottom: 14px; }
  .about-face { width: 84px; height: 84px; border-radius: 50%; object-fit: cover; }
  .about-face-letter {
    display: inline-flex; align-items: center; justify-content: center; font-size: 40px; font-weight: 600;
    background: var(--purple-light); color: var(--purple-dark);
  }
  .about-name { font-size: 18px; font-weight: 650; }
  .about-switch {
    display: flex; align-items: center; justify-content: space-between; gap: 10px;
    padding: 9px 10px; border-radius: 10px; background: var(--row-hover); margin-bottom: 14px;
  }
  .about-mute { display: flex; align-items: center; gap: 9px; cursor: pointer; font-size: 13.5px; }
  .about-mute input { width: 15px; height: 15px; accent-color: var(--purple); }
  .about-section { margin-bottom: 14px; }
  .about-section h4 { margin: 0 0 8px; font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.5px; color: var(--hint); }
  .about-photos { display: grid; grid-template-columns: repeat(4, 1fr); gap: 4px; }
  .about-photos img { width: 100%; aspect-ratio: 1; object-fit: cover; border-radius: 8px; display: block; }
  .about-list { display: flex; flex-direction: column; gap: 2px; }
  .about-row {
    display: flex; align-items: center; justify-content: space-between; gap: 10px;
    padding: 8px 10px; border-radius: 9px; color: var(--text); text-decoration: none; font-size: 13px;
  }
  .about-row:hover { background: var(--row-hover); }
  /* The name takes the row. Without this a row with nothing on its right — a person with no role
     — pushed the name across to the far edge, and a list of people read as a ragged right margin. */
  .about-row-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .about-row-side { color: var(--hint); font-size: 12px; flex-shrink: 0; }
  .about-nothing { text-align: center; padding: 10px 0 4px; }
  /* Who is in a room and what each of them may do. The heading carries the count and, for whoever
     runs the room, the one button that changes it; the rest is a list of faces and names. */
  .about-people { display: flex; flex-direction: column; gap: 6px; }
  .about-people h4 { margin: 0; }
  /* The count and the one button that changes it, on the same line. A float here put the button
     over the row below it, where it swallowed the click meant for the room's own controls. */
  .about-people-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
  .about-add { padding: 2px 10px; font-size: 12px; flex-shrink: 0; }
  .about-person { gap: 10px; padding: 6px 8px; }
  .about-person-face {
    width: 30px; height: 30px; border-radius: 50%; object-fit: cover; flex-shrink: 0; font-size: 12px;
    display: inline-flex; align-items: center; justify-content: center;
  }
  /* A quiet chip, not a shout across the row: it says what somebody is, and nothing in a list of
     people should be the loudest thing on the screen. */
  .about-role {
    flex-shrink: 0; font-size: 11px; font-weight: 600; letter-spacing: 0.2px; color: var(--chip-fg);
    background: var(--chip-bg); border-radius: 8px; padding: 2px 8px;
  }
  /* Faint until the row is under the pointer, but never invisible: a control nobody can see is a
     control nobody finds. */
  .about-person-menu {
    flex-shrink: 0; opacity: 0.35; line-height: 1; padding: 2px 6px;
    border: none; background: none; box-shadow: none;
  }
  .about-person-menu:hover { background: var(--row-hover-strong); }
  .about-person:hover .about-person-menu, .about-person-menu:focus { opacity: 1; }
  /* What can be done to the room: the changes on the left, the way out on the right, one line. */
  .about-room {
    display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
    padding-top: 12px; border-top: 1px solid var(--border);
  }
  .about-room .ghost-btn { padding: 4px 12px; font-size: 12.5px; }
  .about-room .ghost-btn.danger { margin-left: auto; color: var(--urgent); border-color: transparent; }
  .about-room .ghost-btn.danger:hover { border-color: var(--urgent); }

  /* Earlier versions of an article: the list on the left, what changed on the right. */
  .hv-panel {
    position: relative; width: min(880px, 100%); max-height: 86vh; display: flex; flex-direction: column;
    background: var(--panel); color: var(--text); border: 1px solid var(--border);
    border-radius: 18px; padding: 20px; box-shadow: 0 24px 60px rgba(10, 8, 24, 0.34);
  }
  .hv-panel h3 { margin: 0 0 14px; font-size: 16px; }
  .hv-cols { display: flex; gap: 16px; min-height: 0; flex: 1; }
  .hv-list { width: 210px; flex-shrink: 0; overflow-y: auto; display: flex; flex-direction: column; gap: 2px; }
  .hv-row {
    display: flex; flex-direction: column; gap: 1px; text-align: left; border: none; background: none;
    cursor: pointer; padding: 8px 10px; border-radius: 9px; font: inherit; color: var(--text);
  }
  .hv-row:hover { background: var(--row-hover); }
  .hv-row.picked { background: var(--row-picked); }
  .hv-when { font-size: 13px; font-weight: 600; }
  .hv-who { font-size: 11.5px; color: var(--hint); }
  .hv-body { flex: 1; min-width: 0; overflow-y: auto; }
  .hv-diff { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12.5px; line-height: 1.55; }
  .hv-line { white-space: pre-wrap; padding: 0 6px; border-radius: 4px; }
  .hv-line.gone { background: var(--danger-bg); }
  .hv-line.came { background: var(--ok-bg); }
  .hv-line.same { color: var(--hint); }
  .hv-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 14px; }
  @media (max-width: 780px) {
    .hv-cols { flex-direction: column; }
    .hv-list { width: auto; max-height: 180px; }
  }

  /* Emoji: a grid of characters, no library and no images. */
  .ch-sheet .emoji-grid { grid-template-columns: repeat(auto-fill, minmax(38px, 1fr)); }
  .ch-sheet .emoji { font-size: 22px; height: 38px; }
  .emoji-grid { display: grid; grid-template-columns: repeat(10, 1fr); gap: 2px; padding: 4px 6px 8px; max-width: 330px; }
  .emoji {
    border: none; background: none; cursor: pointer; font-size: 19px; line-height: 1;
    padding: 4px 2px; border-radius: 7px;
  }
  .emoji:hover { background: var(--row-hover); }
  .ch-emoji-btn {
    border: none; background: none; color: var(--hint); cursor: pointer; padding: 4px;
    border-radius: 9px; display: inline-flex; align-items: center; flex-shrink: 0;
  }
  .ch-emoji-btn:hover { color: var(--purple); background: var(--row-hover); }
  /* The header is a button now: pressing the name opens the panel above. */
  .ch-head { cursor: pointer; }
  .ch-head .chat-back { cursor: pointer; }

  .ch-text { font-size: 17px; line-height: 1.4; overflow-wrap: anywhere; white-space: pre-wrap; color: var(--text-strong); }
  @media (min-width: 781px) {
    .ch-text { font-size: 14.5px; line-height: 1.45; }
    .ch-bubble { padding: 6px 10px 6px 11px; border-radius: 14px; max-width: min(84%, 780px); }
    .ch-meta { font-size: 11px; margin: 7px 0 -5px 10px; }
    .ch-author { font-size: 12.5px; }
    .ch-photo { max-width: min(100%, 240px); max-height: 240px; }
    .chat-row-name { font-size: 14px; }
    .chat-row-line { font-size: 12.5px; }
    .ch-send textarea { font-size: 14.5px; }
    .chat-head-name { font-size: 15px; }
  }
  /* The time floats into the last line's corner when there is room, and drops below when not. */
  .ch-meta {
    float: right; margin: 9px 0 -6px 12px; font-size: 12px; line-height: 1; color: var(--hint);
    white-space: nowrap;
  }
  .ch-msg .ch-avatar { width: 32px; height: 32px; border-radius: 50%; font-size: 13px; }
  .ch-avatar {
    width: 30px; height: 30px; border-radius: 9px; flex-shrink: 0; object-fit: cover;
    background: var(--purple-light); color: var(--purple-dark);
    display: inline-flex; align-items: center; justify-content: center;
    font-size: 12px; font-weight: 700; text-transform: uppercase;
  }
  .ch-avatar-gap { visibility: hidden; }
  /* Between days, a chip saying which day — the only place a date needs saying at all. */
  .ch-day { display: flex; justify-content: center; margin: 14px 0 4px; }
  .ch-day span {
    font-size: 14px; font-weight: 600; color: #fff; background: rgba(20, 40, 50, 0.32);
    border-radius: 12px; padding: 3px 11px;
  }

  /* The composer is the app's own rounded box, and it grows with what is typed: a message is
     allowed more than one line. */
  .ch-send {
    display: flex; align-items: flex-end; gap: 8px; padding: 6px 6px 6px 14px;
    border: 1px solid var(--border); border-radius: 20px; background: var(--panel);
    box-shadow: 0 -4px 18px rgba(20,15,40,0.16);
  }
  .ch-send:focus-within { border-color: var(--purple); box-shadow: 0 0 0 3px var(--purple-light), 0 -4px 18px rgba(20,15,40,0.16); }
  .ch-send textarea {
    flex: 1; min-width: 0; border: none; outline: none; background: none; font: inherit;
    font-size: 17px; line-height: 1.4; padding: 7px 0; color: var(--text); resize: none;
    max-height: 40vh; overflow-y: auto;
  }
  .ch-send button {
    flex-shrink: 0; border: none; border-radius: 50%; background: var(--purple); color: #fff;
    width: 36px; height: 36px; display: inline-flex; align-items: center; justify-content: center;
    cursor: pointer;
  }
  .ch-send button:hover { background: var(--purple-dark); }
  .ch-send button:disabled { background: var(--border); cursor: default; }

  /* Files in a chat: pictures drawn in the bubble, anything else a card you can take away. */
  .ch-photos { display: flex; flex-wrap: wrap; gap: 4px; margin: -2px -6px 4px; }
  .ch-photo {
    max-width: min(100%, 320px); max-height: 320px; border-radius: 12px; cursor: zoom-in;
    object-fit: cover; background: rgba(0, 0, 0, 0.06); min-width: 80px; min-height: 60px;
  }
  /* Sound and film play in the bubble, in the browser's own player. */
  .ch-video {
    display: block; width: min(100%, 360px); max-height: 420px; border-radius: 12px; margin: 2px -2px 6px;
    background: #000;
  }
  .ch-audio { display: flex; flex-direction: column; gap: 3px; margin: 2px 0 6px; }
  .ch-audio audio { width: min(300px, 70vw); height: 40px; }
  .ch-media-name { font-size: 12px; color: var(--hint); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 300px; }
  .ch-video.is-sending, .ch-audio.is-sending { opacity: 0.6; }
  .ch-file {
    display: flex; align-items: center; gap: 10px; padding: 6px 8px 6px 4px; margin: 2px 0 4px;
    text-decoration: none; color: var(--text); border-radius: 10px;
  }
  .ch-file:hover { background: rgba(0, 0, 0, 0.04); }
  .ch-file-icon {
    width: 38px; height: 38px; flex-shrink: 0; border-radius: 50%; background: var(--purple);
    display: inline-flex; align-items: center; justify-content: center; font-size: 18px;
  }
  .ch-file-text { display: flex; flex-direction: column; min-width: 0; }
  .ch-file-name { font-size: 16px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 240px; }
  .ch-file-size { font-size: 13.5px; color: var(--hint); }
  .ch-text-empty { min-height: 12px; }
  /* The phone's shell before a workspace is chosen: the same ground as the sign-in screen, and a
     row per workspace this address is in (app/mobile.js). */
  #workspace-screen { display: none; place-items: center; min-height: 100%; padding: 40px 18px; text-align: center; }
  #workspace-screen.visible { display: grid; }
  /* The chooser is not the app yet: nothing of the app's own furniture belongs on it — no tab bar,
     no new-task button, no title bar for a workspace that has not been chosen. */
  body:has(#workspace-screen.visible) #tabbar,
  body:has(#workspace-screen.visible) #tab-add,
  body:has(#workspace-screen.visible) #topbar,
  body:has(#workspace-screen.visible) #sidebar { display: none; }
  #workspace-screen h2 { margin: 0 0 6px; font-size: 26px; }
  .ws-lead { color: var(--text-soft); margin: 0 0 16px; }
  .ws-google { display: flex; justify-content: center; margin-bottom: 12px; }
  .ws-list { display: flex; flex-direction: column; gap: 8px; width: min(420px, 90vw); margin: 0 auto 14px; }
  .ws-row {
    display: flex; flex-direction: column; align-items: flex-start; gap: 2px; width: 100%;
    padding: 12px 14px; border: 1px solid var(--border); border-radius: 12px; background: var(--panel);
    font: inherit; color: var(--text); cursor: pointer; text-align: left;
  }
  .ws-row:hover { border-color: var(--purple); }
  .ws-row.current { border-color: var(--purple); background: var(--purple-light); }
  .ws-name { font-weight: 600; font-size: 15.5px; }
  .ws-where { font-size: 12.5px; color: var(--hint); }
  .ws-error { color: #c0392b; font-size: 13.5px; margin: 10px 0; }
  .ws-looking { display: flex; align-items: center; justify-content: center; gap: 10px; color: var(--text-soft); font-size: 14px; margin: 14px 0; }
  .ws-looking .ch-spinner { width: 18px; height: 18px; border-width: 2px; }
  /* A chat that is still loading says so with a turning ring, not with "nothing here yet" — that
     sentence is about a conversation, and it should only be read about one that really is empty. */
  .ch-loading { display: flex; align-items: center; justify-content: center; padding: 48px 0; }
  /* Big enough to be an answer. At 26px on a phone this read as a speck of dust on the glass
     rather than as "it is coming" — "лоудер очень маленький" — and the one moment it exists is the
     moment somebody is wondering whether anything is happening at all. */
  .ch-spinner {
    width: 40px; height: 40px; border-radius: 50%;
    border: 3px solid var(--quote-rule); border-top-color: var(--purple);
    animation: ch-spin 0.8s linear infinite;
  }
  @keyframes ch-spin { to { transform: rotate(360deg); } }
  @media (prefers-reduced-motion: reduce) { .ch-spinner { animation-duration: 2.4s; } }
  /* A message that was written in markdown is drawn as markdown — the same shapes as a document
     page, sized for a bubble: nothing here gets a page's margins, and a code block scrolls on its
     own rather than stretching the bubble. Plain messages keep `white-space: pre-wrap` above. */
  .ch-text.has-md, .ch-bubble.chat-msg .ch-text { white-space: normal; }
  .ch-md-body > :first-child, .ch-text.has-md > :first-child, .ch-bubble.chat-msg.bot > :first-child { margin-top: 0; }
  .ch-text.has-md p, .ch-bubble.chat-msg.bot > p { margin: 0; }
  .ch-text.has-md .md-blank, .ch-bubble.chat-msg.bot > .md-blank { height: 0.6em; }
  .ch-text.has-md h3, .ch-text.has-md h4, .ch-bubble.chat-msg.bot h3, .ch-bubble.chat-msg.bot h4 {
    font-size: 1.02em; font-weight: 650; margin: 8px 0 2px;
  }
  .ch-text.has-md h5, .ch-text.has-md h6 { font-size: 1em; font-weight: 650; margin: 8px 0 2px; }
  .ch-text.has-md ul, .ch-text.has-md ol, .ch-bubble.chat-msg.bot > ul, .ch-bubble.chat-msg.bot > ol {
    margin: 3px 0; padding-left: 22px;
  }
  .ch-text.has-md li, .ch-bubble.chat-msg.bot > ul li { margin: 1px 0; }
  .ch-text.has-md code, .ch-bubble.chat-msg.bot code {
    background: var(--code-tint); border-radius: 5px; padding: 1px 5px;
    font-family: ui-monospace, Menlo, monospace; font-size: 0.88em;
  }
  .ch-text.has-md pre, .ch-bubble.chat-msg.bot pre {
    background: var(--code-tint); border-radius: 10px; padding: 8px 11px; overflow-x: auto; margin: 5px 0;
  }
  .ch-text.has-md pre code, .ch-bubble.chat-msg.bot pre code { background: none; padding: 0; }
  .ch-text.has-md blockquote, .ch-bubble.chat-msg.bot blockquote {
    border-left: 3px solid var(--quote-rule); margin: 4px 0; padding: 1px 0 1px 10px; color: var(--text-soft);
  }
  .ch-text.has-md hr { border: none; border-top: 1px solid var(--quote-rule); margin: 8px 0; }
  .ch-text.has-md .md-table-wrap { margin: 6px 0; }
  .ch-text.has-md .md-table { font-size: 0.92em; }
  .ch-text.has-md .md-img, .ch-text.has-md img { max-width: 100%; border-radius: 10px; margin: 4px 0; }
  .ch-text.has-md a { color: inherit; text-decoration: underline; }
  .ch-msg.mine .ch-text.has-md code, .ch-msg.mine .ch-text.has-md pre { background: var(--code-tint-mine); }
  .ch-msg.mine .ch-text.has-md blockquote { border-left-color: var(--quote-rule-mine); }

  /* The paperclip, and what is waiting to go with the next message. */
  /* `.ch-send button` is the round purple Send; the paperclip beside it is a quiet icon, and has to
     say so at the same weight or it turns purple too. */
  .ch-send .ch-attach {
    flex-shrink: 0; width: 36px; height: 36px; margin-left: -8px; border: none; background: none;
    color: var(--hint); cursor: pointer; border-radius: 50%;
    display: inline-flex; align-items: center; justify-content: center;
  }
  .ch-send .ch-attach:hover { color: var(--purple-dark); background: var(--bg); }
  .ch-pending { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
  .ch-pending-file {
    display: inline-flex; align-items: center; gap: 6px; max-width: 100%; padding: 4px 6px 4px 10px;
    border-radius: 14px; background: var(--panel); box-shadow: 0 1px 2px rgba(20, 15, 40, 0.12); font-size: 13px;
  }
  .ch-pending-photo {
    position: relative; width: 84px; height: 84px; border-radius: 12px; overflow: hidden;
    background: var(--panel); box-shadow: 0 1px 3px rgba(20, 15, 40, 0.18);
  }
  .ch-pending-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
  .ch-pending-photo button {
    position: absolute; top: 4px; right: 4px; width: 22px; height: 22px; border-radius: 50%;
    border: none; background: rgba(0, 0, 0, 0.55); color: #fff; font-size: 15px; line-height: 1;
    cursor: pointer; display: inline-flex; align-items: center; justify-content: center; padding: 0;
  }
  /* What was shown to the assistant, inside the bubble that asked about it. */
  .asst-shot { display: block; max-width: 220px; max-height: 260px; border-radius: 10px; margin-bottom: 6px; }
  .ch-pending-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 180px; }
  .ch-pending-size { color: var(--hint); font-size: 12px; }
  .ch-pending-file button {
    border: none; background: none; cursor: pointer; color: var(--hint); font-size: 16px; line-height: 1;
    padding: 0 4px;
  }

  /* The action on a message appears under the cursor, like the row actions in a list. */
  .ch-act {
    opacity: 0; flex-shrink: 0; align-self: center; border: none; background: none;
    color: var(--hint); cursor: pointer; padding: 3px; border-radius: 7px;
  }
  .ch-msg:hover .ch-act { opacity: 1; }
  .ch-act:hover { background: var(--panel); color: var(--purple-dark); }
  /* The second conversation, beside the first: the same pane, narrower, and with its own head.
     There is room for it only on a wide screen. */
  /* The chats being watched, side by side to the right of the one being worked in. The wrapper is
     the flex child; the panes inside share it equally, so a third one narrows them all rather than
     pushing the conversation off the screen. */
  .ch-beside { display: flex; min-width: 0; }
  .ch-beside[hidden] { display: none; }
  /* A pane is the size it was dragged to — width beside, height below — rather than a share of
     what is left, so opening a third one does not re-divide the two already arranged. */
  .ch-beside-one {
    flex: 0 1 auto; min-width: 200px; display: flex; flex-direction: column; min-height: 0; position: relative;
    border-radius: 14px; overflow: hidden;
    background: var(--chat-paper-colour) var(--chat-paper) center / cover;
    background-repeat: var(--chat-paper-repeat, no-repeat);
  }
  .ch-beside-one .ch-head { cursor: default; }
  /* With chats beside it, the one being worked in keeps a readable width rather than shrinking to
     a column: what is being written in matters more than what is being watched. */
  .ch-wrap.has-beside .ch-main { flex: 1.4; }
  /* The conversation says it will take a chat dragged onto it. */
  .ch-main.drop-beside { outline: 2px dashed var(--purple); outline-offset: -6px; }
  /* Dropped low, the chat goes under this one rather than beside it — so the hint is at the bottom,
     where the pane would appear, rather than round the whole conversation. */
  .ch-main.drop-under::after {
    content: ''; position: absolute; left: 6px; right: 6px; bottom: 6px; height: 27%;
    border: 2px dashed var(--purple); border-radius: 12px; pointer-events: none;
  }
  /* A file dragged in from the desktop. The same gesture with a chat means something else, so the
     conversation says which one it took. The label cannot take the pointer: an overlay that did
     would swallow the drop it is advertising. */
  .ch-main.drop-files { outline: 2px dashed var(--purple); outline-offset: -6px; }
  .ch-main.drop-files::after {
    content: 'Drop to send'; position: absolute; inset: 0; z-index: 4; pointer-events: none;
    display: flex; align-items: center; justify-content: center;
    font-size: 15px; font-weight: 600; color: var(--purple);
    background: var(--glass); backdrop-filter: blur(2px); -webkit-backdrop-filter: blur(2px);
  }

  /* A message rises into place when it arrives, once. Small and quick on purpose: this happens
     several times a minute in a busy room, and anything longer than a blink becomes the thing you
     are watching instead of the thing that was said. */
  /* Rise and fade, and no scale: a scaled bubble is a *narrower* bubble for a moment, so its left
     edge moves — and a run of messages from one person reads as one column only while every left
     edge in it agrees. The check that measures those edges caught this, which is the second time
     today a test has been right about something I would have called cosmetic. */
  @keyframes ch-msg-in { from { opacity: 0; transform: translateY(7px); } to { opacity: 1; transform: none; } }
  .ch-msg.just-arrived .ch-bubble { animation: ch-msg-in 0.18s ease-out; }
  @media (prefers-reduced-motion: reduce) { .ch-msg.just-arrived .ch-bubble { animation: none; } }

  /* The ticks in the corner of your own message: one for sent or delivered, two for read. Read is
     the one that is coloured — it is the only one anybody looks for. */
  .ch-mark { display: inline-flex; margin-left: 4px; vertical-align: -2px; }
  .ch-mark svg { width: 15px; height: 13px; }
  .ch-mark.sent { opacity: 0.45; }
  .ch-mark.delivered { opacity: 0.75; }
  .ch-mark.read { color: #2fb457; opacity: 1; }
  /* On its way: the clock sits where the ticks will be, so the eye looks in one place for the whole
     journey of a message. */
  .ch-mark.sending { opacity: 0.55; }
  .ch-mark.sending svg { width: 13px; height: 13px; }
  .ch-mark.undelivered { color: var(--urgent); opacity: 1; font-weight: 700; }
  /* A message that did not go says so in its own bubble, and the way to try again is the same line
     — not a toast that has already gone by the time somebody looks up. */
  .ch-retry {
    display: block; margin-top: 5px; padding: 3px 9px; border: 1px solid var(--urgent); border-radius: 11px;
    background: none; font: inherit; font-size: 12px; color: var(--urgent); cursor: pointer; text-align: left;
  }
  .ch-retry:hover { background: var(--danger-bg); }
  /* A picture still going is shown from the copy in this browser, so it appears at once rather than
     after a round trip; it is dimmed until it has gone. */
  .ch-photo.is-sending { opacity: 0.6; }
  /* "edited", which opens what it said before. */
  .ch-edited {
    border: none; background: none; padding: 0; font: inherit; color: inherit; cursor: pointer;
    text-decoration: underline dotted; text-underline-offset: 2px;
  }
  /* A message being corrected in place. */
  .ch-editing textarea {
    width: 100%; min-width: 240px; resize: none; max-height: 220px; border: 1px solid var(--border);
    border-radius: 10px; padding: 7px 9px; font: inherit; font-size: 14px; background: var(--panel); color: var(--text);
  }
  .ch-editing-row { display: flex; justify-content: flex-end; gap: 6px; margin-top: 6px; }
  .ch-editing-row .ghost-btn, .ch-editing-row .primary-btn { padding: 3px 12px; font-size: 12.5px; }
  /* What a message said before each correction, oldest first. */
  .msg-history { display: flex; flex-direction: column; gap: 10px; max-height: 60vh; overflow-y: auto; }
  .msg-version { border-left: 2px solid var(--border); padding-left: 10px; }
  .msg-version.current { border-left-color: var(--purple); }
  .msg-version-when { font-size: 11.5px; color: var(--hint); margin-bottom: 2px; }
  .msg-version-text { white-space: pre-wrap; font-size: 13.5px; }

  /* Somebody with the app open. The dot sits on the corner of their face, in the list and at the
     top of a conversation; a room has none, and neither has an agent — a bot is "online" whenever
     its process is, which says nothing worth showing. */
  .ch-face { position: relative; display: inline-flex; flex-shrink: 0; }
  .ch-dot {
    position: absolute; right: 0; bottom: 0; width: 11px; height: 11px; border-radius: 50%;
    background: var(--hint); border: 2px solid var(--panel); opacity: 0; transition: opacity 0.15s;
  }
  .ch-face.is-online .ch-dot { background: #2fb457; opacity: 1; }
  /* "online" under the name, and what somebody is typing under that. The typing line replaces
     nothing — it appears below, so the header does not jump as people start and stop. */
  .ch-seen.is-online { color: #2fb457; }
  /* Typing takes the place of "online" and wears its colour: it is the same fact — somebody is at
     the other end — said more precisely. */
  .ch-topic.is-typing, .chat-row-bottom.is-typing { color: #2fb457; font-style: italic; }

  /* The sheet that comes up from the bottom of the conversation: emoji, and what to attach. It
     covers the conversation rather than the whole window, so the chat stays in view — and on a
     phone it is the whole width, which is where a thumb is. */
  .ch-sheet { position: absolute; inset: 0; z-index: 40; display: flex; align-items: flex-end; justify-content: center; }
  .ch-sheet-panel {
    width: min(460px, 100%); max-height: 60%; display: flex; flex-direction: column;
    background: var(--panel); border: 1px solid var(--border); border-bottom: none;
    border-radius: 16px 16px 0 0; box-shadow: 0 -10px 30px rgba(12, 10, 24, 0.22);
    padding: 10px 10px 8px; animation: sheet-rise 0.16s ease-out;
  }
  @keyframes sheet-rise { from { transform: translateY(14px); opacity: 0.6; } to { transform: none; opacity: 1; } }
  @media (prefers-reduced-motion: reduce) { .ch-sheet-panel { animation: none; } }
  .sheet-head { display: flex; align-items: center; gap: 8px; }
  .sheet-search {
    flex: 1; min-width: 0; border: 1px solid var(--border); border-radius: 10px; padding: 6px 10px;
    font: inherit; font-size: 13.5px; background: var(--bg); color: var(--text);
  }
  .sheet-tabs { display: flex; gap: 4px; overflow-x: auto; padding: 8px 0 6px; scrollbar-width: none; }
  .sheet-tabs::-webkit-scrollbar { display: none; }
  .sheet-tab {
    flex-shrink: 0; border: none; background: none; padding: 4px 10px; border-radius: 9px;
    font: inherit; font-size: 12.5px; color: var(--hint); cursor: pointer;
  }
  .sheet-tab:hover { background: var(--row-hover); }
  .sheet-tab.on { background: var(--chip-bg); color: var(--text); font-weight: 600; }
  .sheet-body { overflow-y: auto; min-height: 0; }
  .sheet-label { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.5px;
    color: var(--hint); margin: 6px 2px 4px; }
  .sheet-nothing { text-align: center; padding: 14px 0; }
  .sheet-title { flex: 1; font-weight: 650; font-size: 14px; }
  .sheet-hint { text-align: center; font-size: 12.5px; margin: 8px 0 2px; }
  /* The three ways to send something: big enough for a thumb, side by side on any width. */
  .attach-ways { display: flex; gap: 8px; padding: 6px 0 2px; }
  .attach-way {
    flex: 1; display: flex; flex-direction: column; align-items: center; gap: 6px;
    padding: 14px 8px; border: 1px solid var(--border); border-radius: 12px;
    background: var(--bg); font: inherit; font-size: 12.5px; color: var(--text); cursor: pointer;
  }
  .attach-way:hover { border-color: var(--purple); color: var(--purple-dark); }
  .attach-waiting { display: flex; flex-direction: column; gap: 4px; }
  .attach-one {
    display: flex; align-items: center; gap: 8px; padding: 6px 8px; border-radius: 9px; background: var(--row-hover);
    font-size: 13px;
  }
  .attach-one-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .attach-one-size { color: var(--hint); font-size: 12px; }

  /* A chat being dragged into place, and the line showing where it would land. */
  .chat-row.dragging { opacity: 0.45; }
  .chat-row.drop-before { box-shadow: inset 0 2px 0 var(--purple); }
  .chat-row.drop-after { box-shadow: inset 0 -2px 0 var(--purple); }

  /* What hangs under a message: the thread it started. Faces, a count, and when the last reply
     came — enough to decide whether to open it without opening it. */
  .ch-replies {
    display: inline-flex; align-items: center; gap: 6px; margin-top: 5px; padding: 3px 10px 3px 4px;
    border: 1px solid var(--border); border-radius: 12px; background: var(--panel);
    font: inherit; font-size: 12px; font-weight: 600; color: var(--purple-dark); cursor: pointer; max-width: 100%;
  }
  .ch-replies:hover { border-color: var(--purple); }
  .ch-replies-face {
    width: 18px; height: 18px; border-radius: 50%; object-fit: cover; flex-shrink: 0;
    background: var(--avatar-bg); color: var(--avatar-fg);
    display: inline-flex; align-items: center; justify-content: center; font-size: 10px; font-weight: 700;
  }
  .ch-replies-when { color: var(--hint); font-weight: 500; }

  /* The thread itself: a pane beside the conversation on a wide screen, over it on a phone. */
  .ch-thread {
    width: 380px; flex-shrink: 0; display: flex; flex-direction: column; min-height: 0;
    margin-left: 5px; border: 1px solid var(--side-edge); border-radius: 14px;
    background: var(--panel); overflow: hidden;
  }
  .ch-thread[hidden] { display: none; }
  .th-head {
    display: flex; align-items: center; gap: 10px; padding: 12px 10px 12px 16px;
    border-bottom: 1px solid var(--border); flex-shrink: 0;
  }
  .th-title { font-weight: 700; font-size: 14px; }
  .th-count { font-size: 12.5px; }
  .th-close { margin-left: auto; }
  .th-messages { flex: 1; min-height: 0; overflow-y: auto; padding: 12px 14px; display: flex; flex-direction: column; gap: 12px; }
  .th-msg { display: flex; gap: 9px; align-items: flex-start; }
  .th-body { min-width: 0; flex: 1; }
  .th-top { display: flex; align-items: baseline; gap: 8px; }
  .th-author { font-weight: 650; font-size: 13px; }
  .th-when { color: var(--hint); font-size: 11.5px; }
  /* The line between what started the thread and what answers it. */
  .th-sep { display: flex; align-items: center; gap: 10px; color: var(--hint); font-size: 11.5px; }
  .th-sep::before, .th-sep::after { content: ""; height: 1px; background: var(--border); flex: 1; }
  .th-send { display: flex; align-items: flex-end; gap: 8px; padding: 10px 12px; border-top: 1px solid var(--border); flex-shrink: 0; }
  .th-send textarea {
    flex: 1; resize: none; max-height: 160px; border: 1px solid var(--border); border-radius: 12px;
    padding: 8px 11px; font: inherit; font-size: 13.5px; background: var(--input-bg, var(--bg)); color: var(--text);
  }
  .th-send button {
    border: none; background: var(--purple); color: #fff; width: 34px; height: 34px; border-radius: 50%;
    display: flex; align-items: center; justify-content: center; cursor: pointer; flex-shrink: 0;
  }

  /* The task that came out of a message, sitting under it: the link people otherwise lose. */
  .ch-task {
    display: inline-flex; align-items: center; gap: 5px; margin-top: 5px; padding: 3px 9px 3px 7px;
    border: 1px solid var(--border); border-radius: 11px; background: var(--panel);
    font: inherit; font-size: 12px; color: var(--purple-dark); cursor: pointer; max-width: 100%;
  }
  .ch-task:hover { border-color: var(--purple); background: var(--purple-light); }
  .ch-task-form { display: flex; flex-direction: column; gap: 5px; padding: 10px; min-width: 260px; }
  .ch-task-form label { font-size: 11px; font-weight: 700; color: var(--hint); text-transform: uppercase; letter-spacing: 0.4px; }
  .ch-task-form input, .ch-task-form select {
    border: 1px solid var(--border); border-radius: 9px; padding: 7px 9px; outline: none;
    font: inherit; font-size: 13px; background: var(--panel);
  }
  .ch-task-form input:focus, .ch-task-form select:focus { border-color: var(--purple); }
  .ch-task-form .primary-btn { margin-top: 4px; }

  .ch-empty { padding: 40px 10px; text-align: center; color: var(--hint); font-size: 13px; }
  .ch-empty b { display: block; color: var(--text); font-size: 14px; margin-bottom: 4px; }

  #bell-btn {
    position: relative; border: 1px solid var(--border); background: var(--panel); color: var(--text-soft);
    width: 32px; height: 32px; border-radius: 9px; cursor: pointer; display: inline-flex;
    align-items: center; justify-content: center; flex-shrink: 0;
  }
  #bell-btn:hover { color: var(--purple-dark); border-color: #cfc9ee; }
  #bell-btn.has-unread { color: var(--purple-dark); }
  #bell-count {
    position: absolute; top: -5px; right: -5px; min-width: 16px; height: 16px; padding: 0 4px;
    border-radius: 8px; background: var(--urgent); color: #fff; font-size: 10px; font-weight: 700;
    line-height: 16px; text-align: center; box-sizing: border-box;
  }
  #notif-panel {
    position: absolute; top: 52px; right: 12px; width: min(380px, calc(100vw - 32px)); z-index: 120;
    background: var(--panel); border: 1px solid var(--border); border-radius: 14px;
    box-shadow: 0 18px 50px rgba(20,15,40,0.20); overflow: hidden;
  }
  .notif-head {
    display: flex; align-items: center; gap: 10px; padding: 11px 14px; font-weight: 700; font-size: 13px;
    border-bottom: 1px solid var(--border);
  }
  .notif-head .quiet-link { margin-left: auto; }
  .notif-body { max-height: min(60vh, 460px); overflow-y: auto; }
  .notif-row { padding: 10px 14px; border-bottom: 1px solid var(--border); cursor: pointer; }
  .notif-row:last-child { border-bottom: none; }
  .notif-row:hover { background: var(--bg); }
  /* Unread is carried by the bar down the left as well as the tint: a tint alone is invisible to
     anyone who cannot see that particular difference in colour. */
  .notif-row.unread { background: var(--row-hover); box-shadow: inset 3px 0 0 var(--purple); }
  .notif-line { font-size: 13px; color: var(--text); }
  .notif-task { font-size: 13px; font-weight: 600; margin-top: 2px; overflow-wrap: anywhere; }
  .notif-quote { font-size: 12.5px; color: var(--text-soft); margin-top: 3px; overflow-wrap: anywhere; }
  .notif-when { font-size: 11px; color: var(--hint); margin-top: 4px; }
  .notif-none { padding: 22px 14px; text-align: center; color: var(--hint); font-size: 13px; }


  #main {
    flex: 1; display: flex; flex-direction: column; min-width: 0; overflow: hidden; position: relative;
    background: var(--main-surface);
    backdrop-filter: blur(26px) saturate(150%); -webkit-backdrop-filter: blur(26px) saturate(150%);
    border: 1px solid var(--glass-edge); border-radius: 18px;
    box-shadow: inset 0 1px 0 var(--glass-edge), 0 14px 40px rgba(16, 16, 30, 0.10);
  }
  #topbar {
    display: flex; align-items: center; gap: 14px; padding: 0 18px; border-bottom: 1px solid var(--border);
    background: var(--panel); border-radius: 18px 18px 0 0; flex-shrink: 0; flex-wrap: wrap; height: 52px;
  }
  #hamburger { display: none; background: none; border: none; font-size: 18px; cursor: pointer; color: var(--text); }
  #view-title { font-size: 14px; font-weight: 700; margin-right: 6px; color: var(--text); white-space: nowrap; }
  .view-tabs { display: flex; align-items: center; gap: 4px; }
  .view-tab {
    padding: 0 10px; height: 30px; border: none; cursor: pointer; font-weight: 600; font-size: 12.5px;
    background: transparent; color: var(--hint); border-radius: 8px;
    display: inline-flex; align-items: center; gap: 6px;
  }
  .view-tab svg { color: currentColor; }
  .view-tab:hover { background: var(--bg); color: var(--text-soft); }
  .view-tab.active { background: var(--tab-active-bg); color: var(--text-strong); }
  #topbar-spacer { flex: 1; }
  #add-task-btn {
    background: #111111; color: #fff; border: 1px solid #111111; border-radius: 8px;
    height: 30px; padding: 0 14px; font-weight: 600; cursor: pointer; font-size: 12.5px;
    display: inline-flex; align-items: center; box-sizing: border-box;
  }
  #add-task-btn:hover { background: #2a2a2a; border-color: #2a2a2a; }
  /* the search box lives inside the menu now, so it takes the menu's look */

  #view-body { flex: 1; overflow: auto; padding: 18px 22px 40px; background: var(--panel); }

  /* List sections (shown when "All tasks" groups by list) */
  .list-section { margin-bottom: 10px; }
  .list-section-head {
    padding: 16px 4px 8px; border-bottom: 1px solid var(--border); margin-bottom: 10px;
  }
  .list-section-eyebrow { font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.4px; color: var(--hint); margin-bottom: 2px; }
  .list-section-name { font-weight: 700; font-size: 15px; color: var(--text); }
  .list-section:first-child .list-section-head { padding-top: 0; }

  /* Group headers (List view) */
  .group { margin-bottom: 18px; }
  .group-head {
    display: flex; align-items: center; gap: 8px; font-weight: 700; font-size: 12px;
    text-transform: uppercase; letter-spacing: 0.4px; padding: 6px 4px; color: var(--hint); cursor: pointer;
  }
  .dot { width: 9px; height: 9px; border-radius: 50%; display: inline-block; }
  .dot-todo { background: var(--todo); } .dot-inprogress { background: var(--inprogress); } .dot-done { background: var(--done); }
  .group-count { font-size: 11px; background: var(--count-bg); color: var(--hint); border-radius: 10px; padding: 1px 7px; }

  table.task-table { width: 100%; table-layout: fixed; border-collapse: collapse; background: var(--panel); border-radius: 10px; overflow: hidden; }
  table.task-table th {
    position: relative; text-align: left; font-size: 11px; text-transform: uppercase; color: var(--hint); font-weight: 700;
    padding: 8px 10px; border-bottom: 1px solid var(--border); overflow: hidden; white-space: nowrap;
  }
  table.task-table td { height: 38px; box-sizing: border-box; padding: 0 10px; border-bottom: 1px solid var(--border); vertical-align: middle; overflow: hidden; text-overflow: ellipsis; }
  .sort-arrow { display: inline-flex; align-items: center; color: var(--hint); }
  .sort-arrow-neutral { opacity: 0; transition: opacity 0.12s; }
  .th-inner { display: inline-flex; align-items: center; gap: 4px; max-width: 100%; }
  .th-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .sort-btn {
    width: 20px; height: 20px; border-radius: 6px; border: 1px solid transparent; background: transparent;
    display: inline-flex; align-items: center; justify-content: center; cursor: pointer; padding: 0; flex-shrink: 0; margin-left: 1px;
  }
  .sort-btn:hover { background: var(--purple-light); border-color: var(--purple); }
  .sort-btn:hover .sort-arrow { color: var(--purple-dark); }
  .sort-btn.active .sort-arrow { color: var(--purple-dark); }
  .status-menu-item.checked { color: var(--purple-dark); font-weight: 600; }
  table.task-table th.spacer-cell, table.task-table td.spacer-cell { padding: 0; }
  table.task-table th.spacer-cell:hover { background: none; }
  table.task-table th:hover { background: var(--bg); }
  table.task-table th:hover .sort-arrow-neutral { opacity: 0.75; }
  table.task-table th:hover .sort-btn:hover .sort-arrow-neutral { opacity: 1; }
  td.name-cell { position: relative; }
  .col-resize {
    position: absolute; top: 0; right: -4px; width: 8px; height: 100%; cursor: col-resize; z-index: 2;
  }
  .col-resize:hover { background: var(--purple); opacity: 0.3; }
  table.task-table tr.task-row:hover { background: var(--row-hover); cursor: pointer; }
  tr.task-row.done .task-title { text-decoration: line-through; color: var(--hint); }
  /* Inside a group that is entirely one status, the line through every row says nothing the heading
     has not said already, and a screen of finished work becomes hard to read. The muted colour
     stays — that still distinguishes a finished task in a mixed table. */
  .group.one-status tr.task-row.done .task-title { text-decoration: none; }
  .task-title { font-weight: 400; margin-left: 3px; font-size: 14px; color: var(--title-text); }
  /* Long titles used to run underneath the hover actions, which sit absolutely at the right edge of
     this same cell — so the last words were struck through by three buttons. Two things fix it, and
     both are needed: room reserved for the buttons, and permission for the title to wrap instead of
     pushing on forever. `min-width: 0` is the part that is easy to leave out — without it a flex
     item refuses to shrink below its content and wraps nowhere. */
  .task-title-cell { width: 100%; min-width: 0; padding-right: 82px; box-sizing: border-box; }
  .task-title { min-width: 0; overflow-wrap: anywhere; }
  /* In the list and the table a name is one line, cut with an ellipsis; the whole of it is in the
     card, and in the tooltip. (The board's cards still wrap, and the Gantt has its own setting.) */
  td.name-cell .task-title { font-weight: 400; flex: 0 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; overflow-wrap: normal; }
  /* Back to the original 13px circle with its 1.6px ring and 8px dot, but drawn as a vector
     so the ring stays even: the same shapes at the same size, without the fractional pixels. */
  .status-icon {
    width: 13px; height: 13px; border: none; border-radius: 50%; background: none no-repeat center / 13px 13px;
    cursor: pointer; padding: 0; margin: 0; flex-shrink: 0; display: inline-flex; align-items: center;
    justify-content: center; line-height: 1; vertical-align: middle; box-sizing: border-box;
    position: relative;
  }
  /* The circle is 13px across, which is a very small thing to hit — and missing it opens the task
     instead, which is the wrong action rather than no action. The target is widened with a
     pseudo-element so the circle itself does not move or grow: about 25 by 33, which is the row's
     full height and the empty space either side of the icon, and nothing a neighbour was using. */
  .status-icon::after { content: ''; position: absolute; inset: -10px -6px; border-radius: 4px; }
  .status-icon.todo {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='6.77' fill='none' stroke='%238b87a0' stroke-width='2.46' stroke-dasharray='3.8 3'/%3E%3C/svg%3E");
  }
  .status-icon.inprogress {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='7.02' fill='none' stroke='%231090e0' stroke-width='1.97'/%3E%3Ccircle cx='8' cy='8' r='4.92' fill='%231090e0'/%3E%3C/svg%3E");
  }
  .status-icon.done {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='7.02' fill='none' stroke='%232f9e44' stroke-width='1.97'/%3E%3Ccircle cx='8' cy='8' r='4.92' fill='%232f9e44'/%3E%3C/svg%3E");
  }
  /* Paused: the same ring, amber, with two bars for the pause */
  .status-icon.hold {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='7.02' fill='none' stroke='%23e8890c' stroke-width='1.97'/%3E%3Crect x='5.6' y='4.9' width='1.7' height='6.2' rx='0.6' fill='%23e8890c'/%3E%3Crect x='8.7' y='4.9' width='1.7' height='6.2' rx='0.6' fill='%23e8890c'/%3E%3C/svg%3E");
  }
  /* Abandoned: a grey ring struck through, so it reads as "not happening" at a glance */
  .status-icon.obsolete {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='7.02' fill='none' stroke='%238b87a0' stroke-width='1.97'/%3E%3Cline x1='4.4' y1='11.6' x2='11.6' y2='4.4' stroke='%238b87a0' stroke-width='1.97' stroke-linecap='round'/%3E%3C/svg%3E");
  }

  .editable-cell { cursor: pointer; }
  .editable-cell:hover { background: var(--bg); }
  .cell-placeholder-btn {
    border: none; background: none; cursor: pointer; color: var(--placeholder-icon); padding: 2px;
    display: inline-flex; align-items: center; justify-content: center;
  }
  .editable-cell:hover .cell-placeholder-btn { color: var(--text-soft); }
  .date-picker { width: 240px; padding: 6px; }
  .dp-cal-header { display: flex; align-items: center; justify-content: space-between; padding: 8px 4px 6px; font-weight: 700; font-size: 13px; }
  .dp-nav { border: none; background: none; cursor: pointer; color: var(--hint); font-size: 15px; padding: 2px 6px; border-radius: 5px; }
  .dp-nav:hover { background: var(--bg); color: var(--text); }
  .dp-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
  .dp-dow { font-size: 10.5px; font-weight: 700; color: var(--hint); text-align: center; padding-bottom: 4px; }
  .dp-cell {
    border: none; background: none; cursor: pointer; font-size: 12.5px; color: var(--text);
    width: 30px; height: 26px; border-radius: 6px;
  }
  .dp-cell:hover { background: var(--purple-light); }
  .dp-cell.dp-today { font-weight: 700; color: var(--purple-dark); }
  .dp-cell.dp-selected { background: var(--purple); color: #fff; }
  .dp-cell.dp-empty { cursor: default; }
  .dp-cell.dp-empty:hover { background: none; }
  .status-menu {
    position: fixed; z-index: 400; background: var(--panel); border: 1px solid var(--border); border-radius: 10px;
    box-shadow: 0 6px 24px rgba(0,0,0,0.15); padding: 6px; min-width: 150px;
  }
  .desc-popup {
    max-width: 340px; padding: 14px 16px; font-size: 13px; line-height: 1.6; color: var(--text);
    white-space: normal; word-break: break-word; max-height: 300px; overflow-y: auto;
  }
  .desc-icon-btn {
    border: 1px solid transparent; background: none; cursor: pointer; color: var(--hint); padding: 2px; flex-shrink: 0;
    display: inline-flex; align-items: center; border-radius: 5px;
  }
  .desc-icon-btn:hover { color: var(--purple-dark); border-color: var(--purple); background: var(--purple-light); }
  .status-menu-item {
    display: flex; align-items: center; gap: 8px; padding: 7px 9px; border-radius: 6px; cursor: pointer; font-size: 13px;
  }
  .status-menu-item:hover { background: var(--bg); }
  .status-menu-head { font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.4px;
    color: var(--hint); padding: 7px 9px 2px; }

  /* Picking several rows: the box is out of the way until you hover, or until something is picked */
  .row-check, .group-check { display: inline-flex; align-items: center; flex-shrink: 0; }
  .row-check { width: 15px; opacity: 0; transition: opacity 0.1s; }
  tr.task-row:hover .row-check, body.picking .row-check, tr.task-row.picked .row-check { opacity: 1; }
  /* Drawn rather than native, so it can be a hairline instead of a slab; the group box is the
     same thing one pixel larger, with a dash for "some of these" */
  .row-check input, .group-check input {
    appearance: none; -webkit-appearance: none; margin: 0; cursor: pointer;
    width: 13px; height: 13px; border: 1px solid var(--check-edge); border-radius: 3.5px; background: #fff;
    transition: border-color 0.1s, background 0.1s;
  }
  .group-check input { width: 14px; height: 14px; }
  .row-check input:hover, .group-check input:hover { border-color: #9a94b4; }
  .row-check input:checked, .group-check input:checked, .group-check input:indeterminate {
    border-color: var(--purple); background: var(--purple) no-repeat center / 9px 9px;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2.4 6.3l2.3 2.3 4.9-5' fill='none' stroke='%23fff' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  }
  .group-check input:indeterminate {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M3 6h6' fill='none' stroke='%23fff' stroke-width='1.9' stroke-linecap='round'/%3E%3C/svg%3E");
  }
  .row-check input:focus-visible, .group-check input:focus-visible { outline: 2px solid var(--purple); outline-offset: 1px; }
  tr.task-row.picked { background: var(--row-picked); }
  tr.task-row.picked:hover { background: var(--row-picked-hover); }
  .group-head .group-check { margin-right: 2px; }

  #bulk-bar {
    position: absolute; left: 50%; transform: translateX(-50%); bottom: 18px; z-index: 40;
    display: flex; align-items: center; gap: 6px; padding: 7px 8px 7px 14px; border-radius: 12px;
    background: rgba(10, 10, 14, 0.92); backdrop-filter: blur(18px) saturate(180%);
    box-shadow: 0 18px 44px rgba(16, 16, 30, 0.28); color: #fff; font-size: 12.5px;
  }
  #bulk-bar .bulk-count { font-weight: 600; margin-right: 6px; white-space: nowrap; }
  #bulk-bar button {
    border: 1px solid rgba(255, 255, 255, 0.14); background: rgba(255, 255, 255, 0.08); color: #fff;
    border-radius: 8px; padding: 5px 10px; font: inherit; font-size: 12.5px; cursor: pointer;
  }
  #bulk-bar button:hover { background: rgba(255, 255, 255, 0.18); }
  #bulk-bar button.danger { border-color: rgba(229, 72, 77, 0.5); color: #ff9ea1; }
  #bulk-bar button.danger:hover { background: rgba(229, 72, 77, 0.24); color: #fff; }
  #bulk-bar button.bulk-close { border: none; background: none; color: rgba(255, 255, 255, 0.6); padding: 5px 6px; }
  .badge { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; font-weight: 600; white-space: nowrap; color: #6c6881; }
  /* A status a space defined: its own colour on the dot, and the category behind the chip so
     finished work still reads as finished at a glance. */
  .status-chip.own { background: var(--bg); color: var(--text-soft); }
  .status-chip.own .dot { background: var(--placeholder-icon); }
  .status-chip.own.cat-doing { background: var(--info-bg-2); color: var(--info-fg-2); }
  .status-chip.own.cat-doing .dot { background: #2f80ed; }
  .status-chip.own.cat-done { background: var(--ok-bg-2); color: var(--ok-fg-2); }
  .status-chip.own.cat-done .dot { background: #27ae60; }
  .status-chip {
    display: inline-flex; align-items: center; gap: 6px; font-size: 11px; font-weight: 700; letter-spacing: 0.3px;
    padding: 3px 11px; border-radius: 12px; text-transform: uppercase; white-space: nowrap;
  }
  .status-chip.todo { background: var(--chip-bg); color: var(--chip-fg); }
  .status-chip.inprogress { background: var(--inprogress); color: #fff; }
  .status-chip.done { background: var(--done); color: #fff; }
  .status-chip.hold { background: #e8890c; color: #fff; }
  .status-chip.obsolete { background: var(--chip-bg); color: var(--chip-fg-soft); text-decoration: line-through; }
  .status-chip.obsolete .dot { background: #9793ab; }
  .status-chip .dot { background: currentColor; opacity: 0.8; }
  .status-chip.todo .dot { background: #9793ab; }
  /* A tag wears the colour its element was given, and which of the two pairs is used is decided
     here rather than in the markup — so the tags change with the theme on a page already drawn.
     The fallbacks are the neutral pair, for anything drawn before app/dialogs.js set them. */
  .team-tag, .cell-placeholder-btn[style*="--tag-bg"] {
    background: var(--tag-bg, var(--row-hover)); color: var(--tag-fg, var(--text-soft));
  }
  .team-tag { display: inline-flex; align-items: center; font-size: 13px; font-weight: 400; border-radius: 6px; padding: 1px 9px; white-space: nowrap; }
  .team-tag-fill { display: flex; width: calc(100% - 14px); justify-content: space-between; box-sizing: border-box; }
  .team-menu-row { padding: 3px 6px; }
  .team-menu-row:hover { background: none; }
  .team-menu-row:hover .team-tag { filter: brightness(0.94); }
  @media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .team-tag,
    :root:not([data-theme="light"]) .cell-placeholder-btn[style*="--tag-bg"] {
      background: var(--tag-bg-dark, var(--row-hover)); color: var(--tag-fg-dark, var(--text-soft));
    }
    /* Hover brightened a pale tag; in the dark it has to lighten instead, or the tag goes out. */
    :root:not([data-theme="light"]) .team-menu-row:hover .team-tag { filter: brightness(1.25); }
  }
  :root[data-theme="dark"] .team-tag,
  :root[data-theme="dark"] .cell-placeholder-btn[style*="--tag-bg"] {
    background: var(--tag-bg-dark, var(--row-hover)); color: var(--tag-fg-dark, var(--text-soft));
  }
  :root[data-theme="dark"] .team-menu-row:hover .team-tag { filter: brightness(1.25); }
  .team-menu-row .team-tag-fill { width: 100%; justify-content: flex-start; }
  .team-menu-input {
    width: 100%; border: 1px solid var(--border); border-radius: 6px; padding: 6px 8px; margin-bottom: 6px;
    outline: none; background: var(--bg); color: var(--text); font-size: 13px; box-sizing: border-box;
  }
  .due-text { font-size: 12px; color: var(--text); }
  .due-text.overdue { color: var(--urgent); font-weight: 600; }
  .due-text.soon { color: #b9770e; font-weight: 600; }
  /* How many subtasks, as a button: larger and plainer than before, and it opens or folds them. */
  .subtask-count { display: inline-flex; align-items: center; gap: 1px; font: inherit; font-size: 12.5px; font-weight: 600; color: var(--text-soft);
    border: none; background: none; padding: 2px 6px; border-radius: 6px; cursor: pointer; flex-shrink: 0; line-height: 1.2; }
  .subtask-count svg { width: 13px; height: 13px; }
  .subtask-count:hover { background: var(--purple-light); color: var(--purple-dark); }
  .expand-btn {
    width: 22px; height: 22px; flex-shrink: 0; border: none; background: none; cursor: pointer; color: var(--text-soft);
    padding: 0; display: inline-flex; align-items: center; justify-content: center; border-radius: 6px;
    transition: transform 0.15s, background 0.1s, color 0.1s;
  }
  .expand-btn:hover { background: var(--purple-light); color: var(--purple-dark); }
  .expand-btn-empty { opacity: 0; transition: opacity 0.12s, background 0.1s, color 0.1s; }
  .task-row:hover .expand-btn-empty { opacity: 1; }
  /* In the margin left of the row, not in it: it takes no room, so every name starts further left. */
  .row-drag-handle {
    position: absolute; left: -1px; top: 50%; transform: translateY(-50%); z-index: 1;
    display: inline-flex; align-items: center; justify-content: center; width: 12px; height: 22px;
    color: var(--placeholder-icon); opacity: 0; cursor: grab; transition: opacity 0.12s, color 0.12s;
  }
  /* Grouped by status, the heading says it: the rows do not repeat it. A subtask under one of them
     may be in another status, and keeps its circle. */
  .group.one-status tr.task-row:not(.subtask-row) td.name-cell .status-icon { display: none; }
  .row-drag-handle:hover { color: var(--hint); }
  .task-row:hover .row-drag-handle { opacity: 1; }
  .row-drag-handle:active { cursor: grabbing; }
  tr.task-row.dragging { opacity: 0.35; }
  tr.task-row.drag-over-top td { box-shadow: inset 0 2px 0 0 var(--purple); }
  tr.task-row.drag-over-bottom td { box-shadow: inset 0 -2px 0 0 var(--purple); }
  tr.task-row.drag-over-top td.name-cell::before,
  tr.task-row.drag-over-bottom td.name-cell::after {
    content: ''; position: absolute; left: var(--tail-x, 0px); width: 0; height: 0;
    border-left: 7px solid var(--purple);
  }
  tr.task-row.drag-over-top td.name-cell::before { top: 0; border-top: 0; border-bottom: 7px solid transparent; }
  tr.task-row.drag-over-bottom td.name-cell::after { bottom: 0; border-bottom: 0; border-top: 7px solid transparent; }
  .group-add-row { cursor: pointer; }
  .group-add-row:hover .group-add-cell { color: var(--text-soft); background: var(--bg); }
  table.task-table td.group-add-cell { display: flex; align-items: center; gap: 8px; color: var(--hint); font-size: 13px; padding-left: 60px; }
  .expand-spacer { display: inline-block; width: 22px; flex-shrink: 0; }
  .inline-add-input { border: none; outline: none; background: none; padding: 4px 8px; width: 100%; max-width: 260px; font-size: 12.5px; color: var(--text); }
  .inline-add-input::placeholder { color: var(--hint); }
  .row-actions {
    position: absolute; right: 8px; top: 50%; transform: translateY(-50%);
    display: flex; gap: 4px; opacity: 0; transition: opacity 0.1s;
  }
  .task-row:hover .row-actions { opacity: 1; }
  .row-icon-btn {
    width: 22px; height: 22px; border-radius: 6px; border: 1px solid var(--border); background: transparent;
    color: var(--hint); cursor: pointer; font-size: 12px; line-height: 1; display: inline-flex; align-items: center; justify-content: center;
  }
  .row-icon-btn:hover { background: var(--purple-light); color: var(--purple-dark); border-color: var(--purple); }
  .task-tag { font-size: 10px; font-weight: 600; background: var(--chip-bg); color: var(--text-soft); border-radius: 6px; padding: 1px 6px; margin-left: 4px; }
  .inline-rename-input { font-size: 13px; border: 1px solid var(--purple); border-radius: 6px; padding: 2px 6px; outline: none; background: var(--panel); color: var(--text); width: 100%; }

  /* Board view */
  .board-wrap { display: flex; gap: 14px; height: 100%; overflow-x: auto; }
  .board-col { flex: 0 0 280px; display: flex; flex-direction: column; background: var(--col-bg); border-radius: 10px; min-height: 0; }
  .board-col-head { padding: 12px 12px 10px; display: flex; align-items: center; justify-content: space-between; gap: 8px; }
  .board-col-body { flex: 1; overflow-y: auto; padding: 6px 8px 12px; display: flex; flex-direction: column; gap: 8px; }
  .board-card {
    background: var(--panel); border-radius: 10px; padding: 10px 11px; box-shadow: 0 1px 2px rgba(0,0,0,0.06);
    cursor: pointer; display: flex; flex-direction: column; gap: 6px; border: 1px solid var(--border);
  }
  .board-card:hover { border-color: var(--purple); }
  /* A picked card, in the same colour the picked row uses, so a selection made in one view is
     recognisable in the other. The border carries it as well as the fill: cards sit on a tinted
     column, where a fill alone is easy to miss. */
  .board-card.picked { background: var(--row-picked); border-color: var(--purple); }
  .board-card[draggable="true"] { cursor: grab; }
  .board-card .task-title { font-size: 14px; }
  .board-card-top { display: flex; align-items: center; gap: 6px; }
  .board-card-top .expand-btn { width: 18px; height: 18px; }
  .board-card-meta { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
  .board-col-body.drag-over { background: var(--purple-light); }
  .board-add { border: 1px dashed #d3cfe6; background: none; border-radius: 8px; padding: 8px; margin: 0 8px 8px; color: var(--hint); cursor: pointer; text-align: left; }

  /* Calendar view */
  .cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; }
  .cal-dow { font-size: 11px; font-weight: 700; color: var(--hint); text-align: center; padding: 4px 0; }
  .cal-cell { background: var(--panel); border: 1px solid var(--border); border-radius: 8px; min-height: 90px; padding: 5px; display: flex; flex-direction: column; gap: 3px; }
  .cal-cell.other-month { opacity: 0.4; }
  .cal-cell.today { border-color: var(--purple); }
  .cal-daynum { font-size: 11px; font-weight: 700; color: var(--hint); }
  .cal-task { font-size: 10.5px; background: var(--purple-light); color: var(--purple-dark); border-radius: 5px; padding: 2px 5px; cursor: pointer; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .cal-task.done { background: var(--ok-bg-3); color: var(--done); text-decoration: line-through; }
  .cal-nav { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; }
  .cal-nav button { background: var(--panel); border: 1px solid var(--border); border-radius: 8px; padding: 5px 10px; cursor: pointer; }
  .cal-nav .label { font-weight: 700; }

  /* Table view: one table per list, each under its own name with the space's colour down its edge.
     The caret turns rather than the rows vanishing without explanation. */
  /* The Table view (renderTable in app/columns.js): the group's name large in its colour, the
     group's colour as a thick edge on the table itself, every cell ruled, statuses and priorities
     filling their cells. There is no summary row under it (taken out on 24 Sep 2026). */
  .table-group { margin-bottom: 34px; }
  .table-group-head { display: flex; align-items: center; gap: 8px; padding: 2px 0 10px; cursor: pointer; user-select: none; }
  .table-group-name { font-weight: 650; font-size: 18px; color: var(--group-colour, var(--purple)); }
  .table-group-caret { display: inline-flex; color: var(--group-colour, var(--hint)); transform: rotate(90deg); transition: transform 0.15s; }
  .table-group .table-scroll {
    border: 1px solid var(--table-rule); border-left: 6px solid var(--group-colour, var(--purple));
    border-radius: 8px 4px 4px 8px; background: var(--panel);
  }
  .table-group table.task-table { border-radius: 0; }
  .table-group table.task-table th, .table-group table.task-table td { border-right: 1px solid var(--table-rule); border-bottom: 1px solid var(--table-rule); }
  .table-group table.task-table th.spacer-cell, .table-group table.task-table td.spacer-cell { border-right: none; }
  .table-group table.task-table th {
    text-transform: none; letter-spacing: 0; font-size: 13px; font-weight: 500; color: var(--text-soft);
    text-align: center; height: 38px; padding: 0 8px;
  }
  .table-group table.task-table th:first-child { text-align: left; padding-left: 14px; }
  .table-group table.task-table th .th-inner { justify-content: center; }
  .table-group table.task-table td.editable-cell { text-align: center; }
  .table-group table.task-table td.tv-fill {
    background: var(--fill); color: #fff; font-size: 13px; font-weight: 500; padding: 0 6px;
    border-right-color: var(--panel); border-bottom-color: var(--panel); white-space: nowrap;
  }
  .table-group table.task-table td.tv-fill:hover { filter: brightness(0.93); cursor: pointer; }
  .table-group table.task-table td.tv-fill.tv-empty { background: var(--row-hover); }
  .table-group .tv-add td { padding: 0; height: 38px; }
  .tv-add-input {
    width: 100%; height: 100%; border: none; outline: none; background: transparent; font: inherit; font-size: 13.5px;
    color: var(--text); padding: 0 14px 0 40px;
  }
  .tv-add-input::placeholder { color: var(--hint); }
  .tv-add-input:focus { background: var(--purple-light); }
  .table-group.collapsed .table-group-caret { transform: none; }
  @media (max-width: 780px) {
    .table-group { padding-left: 8px; margin-left: 4px; }
  }

  /* Gantt view, after the roadmap Andrey sent: a sticky column of names with their dates, a sticky
     header of weeks and months, bands per list, and bars that carry their length. Every row is the
     same two-column grid — names, then the track — so a name can never drift out of line with its
     bar. In the app's own colours, so it holds in the dark theme as well as the light one. */
  .gantt-wrap { display: flex; flex-direction: column; gap: 12px; min-width: 0; }
  .g-top { display: flex; align-items: center; justify-content: space-between; gap: 10px 18px; flex-wrap: wrap; }
  .g-controls { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
  .gantt-zoom { display: inline-flex; border: 1px solid var(--border); border-radius: 9px; overflow: hidden; }
  .gantt-zoom button, .g-toggle {
    border: none; background: var(--panel); color: var(--hint); font: inherit; font-size: 13px;
    padding: 5px 12px; cursor: pointer;
  }
  .gantt-zoom button.on { background: var(--purple); color: #fff; }
  .g-toggle { border: 1px solid var(--border); border-radius: 9px; }
  .g-toggle:hover { background: var(--bg); }
  .g-toggle.on { border-color: var(--purple); color: var(--purple); }
  .gantt-count { font-size: 13px; }
  .g-legend { display: flex; align-items: center; justify-content: flex-end; gap: 7px; flex-wrap: wrap; }
  .g-key {
    display: inline-flex; align-items: center; gap: 7px; padding: 5px 10px; border: 1px solid var(--border);
    border-radius: 999px; background: var(--panel); color: var(--text-soft); font-size: 11.5px; font-weight: 600;
    white-space: nowrap;
  }
  .g-key i { width: 8px; height: 8px; border-radius: 50%; background: var(--dot, var(--purple)); display: block; }
  .g-key.milestone i { border-radius: 2px; width: 3px; height: 12px; background: var(--urgent); }

  /* The frame scrolls both ways inside itself, so the header can stick to its top and the names to
     its left; its height is set from what the window leaves (fitGantt). */
  .g-frame {
    border: 1px solid var(--border); border-radius: 16px; overflow: auto; background: var(--panel);
    box-shadow: 0 16px 40px rgba(31, 42, 61, 0.08), 0 2px 8px rgba(31, 42, 61, 0.04);
    min-height: 320px; scrollbar-width: thin;
  }
  /* The frame and the handle on the names column's edge. The handle sits outside the scrolling
     frame, so it stays on the edge however far the chart is scrolled. */
  .g-stage { position: relative; min-width: 0; }
  .g-lab-grip {
    position: absolute; top: 1px; bottom: 1px; left: calc(var(--lab) - 3px); width: 7px; z-index: 8;
    cursor: col-resize; touch-action: none;
  }
  .g-lab-grip::after {
    content: ""; position: absolute; top: 0; bottom: 0; left: 3px; width: 1px; background: transparent;
    transition: background 0.12s;
  }
  .g-lab-grip:hover::after, .g-lab-grip.dragging::after { background: var(--purple); width: 2px; left: 2px; }
  /* The date axis stretches the chart when dragged (startGanttStretch). */
  .g-head .g-axis { cursor: ew-resize; user-select: none; touch-action: none; }
  body.g-stretching, body.g-stretching * { cursor: ew-resize !important; user-select: none; }
  .g-inner { width: max-content; min-width: 100%; --g-row: 52px; }
  .g-row { display: grid; grid-template-columns: var(--lab) var(--g-w); align-items: stretch; border-bottom: 1px solid var(--row-hover); }
  .g-task:hover, .g-task:hover .g-label { background: var(--row-hover); }
  .g-label {
    position: sticky; left: 0; z-index: 3; background: var(--panel); border-right: 1px solid var(--border);
    display: flex; flex-direction: column; justify-content: center; gap: 2px; padding: 0 16px 0 20px;
    min-width: 0; cursor: pointer; box-shadow: 8px 0 18px -18px rgba(35, 44, 62, 0.7);
  }
  /* The same size and weight as a task's name in the list (.task-title, 14px). */
  .g-title {
    display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;
    font-size: 14px; font-weight: 400; line-height: 1.25; color: var(--title-text);
  }
  .g-one-line .g-title { -webkit-line-clamp: 1; }
  .g-dates { font-size: 11px; line-height: 1.1; font-weight: 650; letter-spacing: 0.02em; color: var(--hint); }
  .g-label.done .g-title { color: var(--hint); }
  .g-task, .g-task .g-track { height: var(--g-row); }
  .g-track { position: relative; }

  /* The header: the date each week begins, and the month beneath, both sticky with the chart. */
  .g-head { position: sticky; top: 0; z-index: 5; border-bottom: 1px solid var(--border); }
  /* Three tiers — the week dates, the Today and milestone pills, the months — so it is as tall as
     the roadmap's; at 66px the pills sat on top of the month names. */
  .g-head, .g-head .g-label, .g-head .g-track { height: 84px; background: var(--glass-strong); }
  .g-head .g-label { z-index: 6; cursor: default; backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); }
  .g-head .g-track { backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); overflow: hidden; }
  .g-week {
    position: absolute; top: 9px; transform: translateX(-50%); padding: 2px 5px; border-radius: 5px;
    background: var(--row-hover); color: var(--text-soft); font-size: 10.5px; line-height: 1.2; font-weight: 700;
    letter-spacing: 0.02em; white-space: nowrap; z-index: 2;
  }
  .g-week.edge { transform: none; }
  .g-month {
    position: absolute; bottom: 9px; font-size: 12px; color: var(--hint); font-weight: 700; letter-spacing: 0.07em;
    text-align: center; text-transform: uppercase; overflow: hidden; white-space: nowrap;
  }
  .g-line { position: absolute; top: 0; bottom: 0; width: 1px; background: var(--row-hover); }
  .g-line.strong { background: var(--border); }

  /* One band per list, like the roadmap's "До релиза" / "После релиза". */
  .g-sect, .g-sect .g-label, .g-sect .g-track { background: var(--bg); }
  .g-sect { border-top: 1px solid var(--border); }
  .g-sect-name {
    cursor: default; padding: 10px 8px 10px 20px; font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase;
    color: var(--hint); font-weight: 750; white-space: nowrap; box-shadow: none;
  }

  /* The body carries the grid once, behind every row, rather than a copy of it in each. */
  .g-body { position: relative; }
  .g-grid { position: absolute; top: 0; bottom: 0; left: var(--lab); width: var(--g-w); pointer-events: none; z-index: 0; }
  .g-row .g-track { z-index: 1; }
  .gantt-today, .g-mark.today { position: absolute; top: 0; bottom: 0; width: 2px; background: var(--purple); opacity: 0.45; }
  .g-milestone, .g-mark.milestone {
    position: absolute; top: 0; bottom: 0; width: 2px; background: var(--urgent); z-index: 2;
    box-shadow: 0 0 0 5px rgba(228, 71, 62, 0.06);
  }
  .g-pill {
    position: absolute; top: 32px; transform: translateX(-50%); white-space: nowrap; z-index: 4;
    font-size: 11px; font-weight: 800; letter-spacing: 0.08em; text-transform: uppercase; padding: 4px 10px;
    border-radius: 999px; max-width: 260px; overflow: hidden; text-overflow: ellipsis;
  }
  .g-pill.today { background: var(--purple); color: #fff; opacity: 0.9; }
  .g-pill.milestone { background: var(--urgent); color: #fff; box-shadow: 0 5px 14px rgba(228, 71, 62, 0.24); }
  .g-diamond {
    position: absolute; top: calc(var(--g-row) / 2 - 8px); width: 16px; height: 16px; transform: rotate(45deg);
    border-radius: 3px; background: var(--urgent); cursor: pointer; box-shadow: 0 3px 8px rgba(228, 71, 62, 0.3);
  }
  .g-milestone.done, .g-mark.milestone.done { background: var(--hint); box-shadow: none; opacity: 0.6; }
  .g-pill.milestone.done { background: var(--row-hover); color: var(--text-soft); box-shadow: none; }
  .g-diamond.done { background: var(--hint); box-shadow: none; }

  /* The diamond beside a milestone's name, wherever it is listed (milestoneMark in app/addtask.js). */
  .ms-diamond {
    display: inline-block; flex-shrink: 0; width: 10px; height: 10px; margin: 0 3px 0 2px; transform: rotate(45deg);
    border-radius: 2px; background: var(--urgent);
  }
  .card-top .ms-diamond { width: 13px; height: 13px; margin: 12px 6px 0 4px; }
  .quick-add-milestone { color: var(--placeholder-icon); }
  .quick-add-milestone.on { color: var(--urgent); }
  .quick-add-milestone.on svg path { fill: currentColor; }

  /* Under the bars, over the grid: an arrow runs between bars, it should not be drawn across them. */
  .gantt-arrows { position: absolute; inset: 0; pointer-events: none; z-index: 1; overflow: visible; }
  .gantt-arrows path { fill: none; stroke: var(--hint); stroke-width: 1.4; }
  .gantt-arrows polygon { fill: var(--hint); }
  .gantt-bar {
    position: absolute; top: calc((var(--g-row) - var(--g-bar, 30px)) / 2); height: var(--g-bar, 30px);
    border-radius: 8px; background: var(--bar, var(--purple)); color: #fff;
    display: flex; align-items: center; justify-content: center; padding: 0 6px;
    font-size: 13px; font-weight: 720; white-space: nowrap; overflow: hidden; cursor: pointer; touch-action: none;
    box-shadow: 0 4px 10px rgba(29, 37, 52, 0.13); text-shadow: 0 1px 1px rgba(0, 0, 0, 0.08);
  }
  .gantt-bar-text { overflow: hidden; text-overflow: ellipsis; }
  /* Started, and nobody has said when it ends: the roadmap's "без даты" — an outline to the edge. */
  .gantt-bar.open {
    background: color-mix(in srgb, var(--bar) 6%, transparent); border: 2px dashed var(--bar); color: var(--bar);
    box-shadow: none; text-shadow: none; justify-content: flex-start; padding-left: 10px;
  }
  .gantt-bar.done { opacity: 0.5; }
  .gantt-bar.late { outline: 2px solid var(--urgent); outline-offset: 1px; }
  .gantt-bar.dragging { opacity: 0.85; cursor: grabbing; }
  /* The ends are handles: a few pixels of bar that mean "this date", and the rest means "both". */
  .gantt-grip { position: absolute; top: 0; bottom: 0; width: 7px; cursor: ew-resize; }
  .gantt-grip.from { left: 0; }
  .gantt-grip.to { right: 0; }
  .g-undated .g-dates { font-style: italic; }
  @media (max-width: 780px) {
    .g-legend { justify-content: flex-start; }
    .g-label { padding: 0 10px 0 12px; }
  }

  /* Journal view */
  .week-nav { display: flex; align-items: center; justify-content: space-between; padding: 4px 0 14px; }
  .week-nav button { background: var(--panel); border: 1px solid var(--border); border-radius: 8px; padding: 6px 12px; cursor: pointer; }
  .week-grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 8px; margin-bottom: 20px; }
  @media (max-width: 900px) { .week-grid { grid-template-columns: repeat(2, 1fr); } }
  .day-cell { background: var(--panel); border: 1px solid var(--border); border-radius: 10px; padding: 10px 10px 34px; position: relative; display: flex; flex-direction: column; gap: 4px; }
  .day-cell.today { border-color: var(--purple); }
  .day-name { font-size: 11px; font-weight: 700; text-transform: uppercase; color: var(--hint); }
  .day-date { font-size: 16px; font-weight: 700; }
  .day-notes { width: 100%; border: none; background: transparent; resize: none; font-size: 12px; line-height: 1.5; outline: none; min-height: 160px; font-family: inherit; color: var(--text); }
  .day-rating-btn { position: absolute; bottom: 8px; right: 8px; background: none; border: none; font-size: 18px; cursor: pointer; opacity: 0.4; }
  .day-rating-btn.rated { opacity: 1; }

  /* Task drawer */
  #overlay { display: none; position: fixed; inset: 0; background: rgba(20,15,40,0.35); z-index: 200; }
  #overlay.open { display: block; }
  /* Task card: a large centred window, details on the left, activity on the right */
  #drawer {
    position: fixed; inset: 50% auto auto 50%; transform: translate(-50%, -50%) scale(0.98);
    width: min(1180px, 94vw); height: min(880px, 88vh);
    background: var(--panel); border-radius: 14px; box-shadow: 0 24px 70px rgba(20,15,40,0.28);
    z-index: 201; display: none; flex-direction: column; overflow: hidden; opacity: 0; transition: opacity 0.14s, transform 0.14s;
  }
  #drawer.open { display: flex; opacity: 1; transform: translate(-50%, -50%) scale(1); }
  /* Docked to the right: the same card, moved to the edge and given the window's full height, so
     opening a task stops covering the list it came from. There is no overlay in this mode — the
     list stays lit and clickable, and clicking another row moves the panel to it. */
  #drawer.docked, #drawer.docked.open {
    inset: 8px 8px 8px auto; transform: none;
    width: var(--drawer-w, 560px); height: auto; border-radius: 18px;
  }
  #app.docked-open { margin-right: calc(var(--drawer-w, 560px) + 10px); transition: margin-right 0.14s; }
  /* The handle sits on the panel's left edge, which is the edge that moves. It is wider than it
     looks: 8px is about the narrowest thing a person can reliably catch with a mouse. */
  #drawer-resize { display: none; }
  #drawer.docked #drawer-resize {
    display: block; position: absolute; left: 0; top: 0; bottom: 0; width: 8px; z-index: 3; cursor: ew-resize;
  }
  #drawer.docked #drawer-resize:hover, body.drawer-sizing #drawer-resize { background: var(--purple-light); }
  body.drawer-sizing { cursor: ew-resize; user-select: none; }
  /* Beside the list there is no room for two columns, so the fields go under the body — and the two
     of them scroll as one column rather than as two boxes each with its own scrollbar, which at
     this width leaves half a comment box showing above a wall of fields. */
  #drawer.docked #drawer-cols { flex-direction: column; overflow-y: auto; }
  #drawer.docked #drawer-body { overflow: visible; flex: 0 0 auto; }
  #drawer.docked .card-props { grid-template-columns: 1fr; }
  #drawer-cols { flex: 1; display: flex; min-height: 0; }
  /* The fields, under the title. Two columns where there is room for two, one where there is not —
     a card opened in the docked panel is narrow, and a 126px label beside a value in 280px of
     space is how the old layout came apart. */
  .card-fields {
    display: grid; grid-template-columns: repeat(auto-fit, minmax(290px, 1fr));
    gap: 0 20px; margin: 2px 0 16px;
  }
  #card-fields { background: var(--bg); border: 1px solid var(--border); border-radius: 14px; padding: 12px 14px; }
  .jf-row { display: flex; align-items: flex-start; gap: 10px; padding: 6px 6px; border-radius: 8px; font-size: 14px; }
  .jf-row:hover { background: var(--row-hover-soft); }
  .jf-row.dragging { opacity: 0.45; }
  .jf-row.drop-above { box-shadow: inset 0 2px 0 0 var(--purple); }
  .jf-row.drop-below { box-shadow: inset 0 -2px 0 0 var(--purple); }
  .jf-label { width: 120px; flex-shrink: 0; color: var(--text-soft); font-size: 14px; cursor: grab; padding-top: 1px; }
  .jf-value { flex: 1; min-width: 0; display: flex; align-items: center; gap: 6px; flex-wrap: wrap; border-radius: 6px; padding: 2px 6px; margin: -2px -6px; }
  .jf-value.editable { cursor: pointer; }
  .jf-value.editable:hover { background: var(--row-hover-strong); }
  .jf-value, .jf-value a { color: #1d4ed8; font-size: 14px; text-decoration: none; }
  .jf-value a { overflow: hidden; text-overflow: ellipsis; }
  .jf-value .v-empty { color: var(--placeholder-icon); }
  .jf-value .v-chip, .jf-value .v-muted { color: #1d4ed8; font-size: 14px; }
  .jf-value .team-tag, .jf-value .task-tag { flex: 0 0 auto; width: auto; }
  .v-muted { color: var(--text-soft); font-size: 12.5px; }
  .card-top { display: flex; align-items: flex-start; gap: 10px; }
  .card-top-actions { display: flex; gap: 2px; padding-top: 6px; }
  .quiet-icon { border: none; background: none; color: var(--hint); cursor: pointer; width: 28px; height: 28px; border-radius: 7px; display: inline-flex; align-items: center; justify-content: center; }
  .quiet-icon:hover { background: var(--bg); color: var(--purple-dark); }
  .quiet-icon.danger:hover { color: var(--urgent); }
  .quiet-link { margin-left: auto; border: none; background: none; color: var(--purple-dark); cursor: pointer; font: inherit; font-size: 12.5px; }
  .card-block { border-top: 1px solid var(--border); padding-top: 12px; margin-top: 14px; }
  .card-block-head { display: flex; align-items: center; gap: 8px; font-size: 13px; font-weight: 700; margin-bottom: 8px; }
  .card-block-head .count { font-weight: 500; color: var(--hint); font-size: 12px; }
  .card-none { color: var(--hint); font-size: 12.5px; padding: 2px 0 4px; }
  .link-group { margin-bottom: 12px; }
  .related-block { margin-top: 10px; }
  .related-block .linked-row { background: var(--row-linked); }
  .link-group-title { font-size: 11px; font-weight: 700; letter-spacing: 0.4px; text-transform: uppercase; color: var(--hint); margin: 0 0 4px 2px; }
  .link-add-box { margin-top: 10px; border: 1px solid var(--border); border-radius: 12px; padding: 10px; background: var(--panel); }
  .seg { display: inline-flex; background: var(--bg); border-radius: 9px; padding: 3px; gap: 2px; margin-bottom: 8px; }
  .seg button { border: none; background: none; font: inherit; font-size: 12.5px; color: var(--text-soft); padding: 5px 12px; border-radius: 7px; cursor: pointer; }
  .seg button.active { background: var(--panel); color: var(--text); box-shadow: 0 1px 3px rgba(20,15,40,0.12); font-weight: 600; }
  .link-search-wrap { position: relative; }
  .link-search-wrap input { width: 100%; border: 1px solid var(--border); border-radius: 9px; padding: 8px 10px; outline: none; font: inherit; font-size: 13px; }
  .link-search-wrap input:focus { border-color: var(--purple); }
  /* A commit, a branch or a merge request that named this task. Read like a list of links,
     because that is what it is: the repository stays the truth about the code. */
  .commit-row { display: flex; align-items: baseline; gap: 8px; padding: 5px 0; font-size: 13px; }
  .commit-kind { color: var(--hint); flex-shrink: 0; line-height: 0; }
  .commit-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--purple-dark); text-decoration: none; }
  a.commit-title:hover { text-decoration: underline; }
  .commit-meta { font-size: 11.5px; color: var(--hint); white-space: nowrap; }
  .commit-meta code { font-size: 11px; background: var(--bg); border-radius: 5px; padding: 1px 4px; }
  .linked-row { display: flex; align-items: center; gap: 10px; padding: 8px 10px; border: 1px solid var(--border); border-radius: 10px;
    margin-bottom: 6px; cursor: pointer; font-size: 13px; background: var(--panel); }
  .linked-row:hover { border-color: #cfc9ee; background: var(--row-hover); }
  .linked-id { color: var(--hint); font-size: 12px; min-width: 62px; }
  .linked-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .linked-name.done { text-decoration: line-through; color: var(--hint); }
  .linked-remove { border: none; background: none; color: var(--hint); cursor: pointer; visibility: hidden; }
  .linked-row:hover .linked-remove { visibility: visible; }
  .attach-row { display: flex; gap: 8px; align-items: center; margin-top: 8px; }
  .attach-row .file-drop { flex: 1; padding: 8px 10px; }
  .attach-row #url-input { flex: 1; border: 1px solid var(--border); border-radius: 8px; padding: 8px 10px; outline: none; font: inherit; font-size: 12.5px; background: var(--panel); }
  .card-tabs { display: flex; gap: 14px; margin-bottom: 8px; }
  .card-tabs button { border: none; background: none; padding: 4px 0; font: inherit; font-size: 13px; font-weight: 600; color: var(--hint); cursor: pointer; border-bottom: 2px solid transparent; }
  .card-tabs button.active { color: var(--text); border-bottom-color: var(--text); }

  #activity-list { max-height: 340px; overflow-y: auto; display: flex; flex-direction: column; gap: 8px; padding: 2px 0 10px; }
  .act-event { font-size: 12.5px; color: var(--text-soft); display: flex; gap: 8px; line-height: 1.45; }
  .act-event::before { content: '·'; color: var(--hint); }
  .act-event .when, .act-comment .when { color: var(--hint); font-size: 11px; white-space: nowrap; }
  .act-event b { font-weight: 600; }
  .act-comment { background: var(--panel); border: 1px solid var(--border); border-radius: 10px; padding: 8px 10px; font-size: 13px; }
  .act-comment .meta { display: flex; gap: 6px; align-items: center; margin-top: 5px; font-size: 11px; color: var(--hint); }
  .act-comment .resolve-btn { border: none; background: none; color: var(--hint); cursor: pointer; font-size: 11px; padding: 0; text-decoration: none; }
  .act-comment .resolve-btn:hover { color: var(--purple-dark); text-decoration: underline; }
  /* Reacting to a comment: the chips sit under it, the button appears with the rest of the line's
     controls. A chip you are part of is filled in, so "did I already say yes" is answerable by eye. */
  /* A thread: replies indented under the comment they answer, with a rule down the left so the
     shape is visible at a glance rather than inferred from the indent. */
  .thread { margin: 4px 0 0 14px; padding-left: 10px; border-left: 2px solid var(--border); }
  .act-comment.reply { background: var(--bg); }
  .thread-reply, .thread-more {
    border: none; background: none; color: var(--hint); cursor: pointer; font: inherit; font-size: 11.5px;
    padding: 3px 0;
  }
  .thread-reply:hover, .thread-more:hover { color: var(--purple-dark); text-decoration: underline; }
  .reply-box { display: flex; gap: 6px; align-items: center; margin-top: 6px; }
  .reply-box input {
    flex: 1; min-width: 0; border: 1px solid var(--border); border-radius: 9px; padding: 6px 9px;
    outline: none; font: inherit; font-size: 12.5px; background: var(--panel);
  }
  .reply-box input:focus { border-color: var(--purple); }
  .reply-box .primary-btn { padding: 5px 12px; font-size: 12.5px; }

  .react-btn { border: none; background: none; color: var(--hint); cursor: pointer; padding: 0 2px; display: inline-flex; align-items: center; }
  .react-btn:hover { color: var(--purple-dark); }
  .react-row { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 6px; }
  .react-chip {
    border: 1px solid var(--border); background: var(--panel); border-radius: 11px; padding: 1px 7px;
    font-size: 12px; line-height: 18px; cursor: pointer; color: var(--text-soft);
  }
  .react-chip:hover { border-color: #cfc9ee; }
  .react-chip.mine { background: var(--purple-light); border-color: var(--purple); color: var(--purple-dark); font-weight: 600; }
  .react-picker { display: flex; gap: 2px; padding: 4px; }
  .react-picker button {
    border: none; background: none; font-size: 18px; line-height: 1; padding: 5px 6px; border-radius: 8px; cursor: pointer;
  }
  .react-picker button:hover { background: var(--bg); }

  .act-comment.resolved { opacity: 0.55; }
  .breadcrumb { font-size: 12px; color: var(--hint); display: flex; align-items: center; gap: 5px; flex-wrap: wrap; }
  .breadcrumb .crumb { border: none; background: none; font: inherit; font-size: 12.5px; font-weight: 600; color: #55555f;
    padding: 3px 6px; border-radius: 6px; cursor: pointer; max-width: 260px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .breadcrumb .crumb:hover { background: var(--bg); color: var(--text); text-decoration: underline; }
  .breadcrumb .crumb-sep { color: var(--placeholder-icon); }
  .breadcrumb .crumb-copy { border: none; background: none; color: var(--hint); cursor: pointer; padding: 3px 5px; border-radius: 6px; display: inline-flex; }
  .breadcrumb .crumb-copy:hover { background: var(--bg); color: var(--purple-dark); }
  .card-props { display: grid; grid-template-columns: repeat(2, minmax(240px, 1fr)); gap: 2px 26px; }
  .card-empty-btn { background: none; border: none; color: var(--hint); cursor: pointer; font-size: 12.5px; padding: 4px 0; text-align: left; }
  #custom-fields .prop { min-height: 32px; }
  #custom-fields .prop-key { width: 200px; }
  .file-drop { display: block; border: 1px dashed var(--border); border-radius: 10px; padding: 12px; text-align: center; color: var(--hint); font-size: 12.5px; cursor: pointer; }
  .file-drop:hover, .file-drop.dragover { border-color: var(--purple); color: var(--purple-dark); background: var(--purple-light); }
  .file-item { display: flex; align-items: center; gap: 8px; font-size: 13px; padding: 5px 0; }
  .file-item a { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--purple-dark); }
  .file-item .size { color: var(--hint); font-size: 11.5px; }
  .file-item button { border: none; background: none; color: var(--hint); cursor: pointer; }
  .file-item button:hover { color: var(--urgent); }
  .checklist { border: 1px solid var(--border); border-radius: 10px; padding: 10px 12px; margin-bottom: 8px; }
  .checklist-head { display: flex; align-items: center; gap: 8px; font-weight: 600; font-size: 13px; }
  .checklist-head .count { color: var(--hint); font-weight: 400; font-size: 12px; }
  .checklist-head button { margin-left: auto; border: none; background: none; color: var(--hint); cursor: pointer; }
  .checklist-item { display: flex; align-items: center; gap: 8px; padding: 4px 0; font-size: 13px; }
  .checklist-item.done span.text { text-decoration: line-through; color: var(--hint); }
  .checklist-item button.del { margin-left: auto; border: none; background: none; color: var(--hint); cursor: pointer; visibility: hidden; }
  .checklist-item:hover button.del { visibility: visible; }
  .checklist input.add-item, #checklists input.add-list { border: 1px dashed var(--border); border-radius: 8px; padding: 6px 8px; width: 100%; outline: none; background: none; font: inherit; font-size: 13px; margin-top: 6px; }
  @media (max-width: 900px) {
    #drawer { width: 96vw; height: 92vh; }
    #drawer-cols { flex-direction: column; }
    .card-props { grid-template-columns: 1fr; }
  }
  /* Who else has this card open. Faces, not names: the question is "is anyone else in here", and
     the answer has to survive being glanced at rather than read. */
  /* The overlap is the negative margin on each face, not a gap: `gap` cannot be negative. */
  #drawer-watchers { display: flex; align-items: center; margin-left: auto; padding-right: 6px; }
  .watcher {
    width: 22px; height: 22px; border-radius: 50%; object-fit: cover; margin-left: -4px;
    border: 2px solid var(--panel); background: var(--purple-light); flex-shrink: 0;
  }
  .watcher.letter {
    display: inline-flex; align-items: center; justify-content: center;
    font-size: 10px; font-weight: 700; color: var(--purple-dark); text-transform: uppercase;
  }

  #drawer-header { padding: 12px 18px; border-bottom: 1px solid var(--border); display: flex; align-items: center; gap: 10px; }
  #drawer-close { margin-left: auto; border: none; background: none; color: var(--hint); cursor: pointer; width: 28px; height: 28px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; }
  #drawer-close:hover { background: var(--bg); color: var(--text); }
  .status-pill {
    display: inline-flex; align-items: center; border-radius: 6px; padding: 3px 10px; font-weight: 700; font-size: 11px;
    text-transform: uppercase; letter-spacing: 0.3px; background: var(--chip-bg); color: var(--chip-fg);
  }
  .status-pill.inprogress { background: var(--inprogress); color: #fff; }
  .status-pill.done { background: var(--done); color: #fff; }
  #drawer-close { background: none; border: none; font-size: 18px; cursor: pointer; color: var(--hint); margin-left: auto; }
  #drawer-body { flex: 1; overflow-y: auto; padding: 22px 34px 48px; display: flex; flex-direction: column; gap: 10px; min-width: 0; }
  /* quiet label/value rows: no boxes until you interact */
  .card-props { display: grid; grid-template-columns: repeat(2, minmax(260px, 1fr)); gap: 0 40px; margin: 10px 0 4px; }
  .prop { display: flex; align-items: center; gap: 10px; min-height: 30px; }
  .prop-key { display: inline-flex; align-items: center; gap: 8px; width: 132px; flex-shrink: 0; color: var(--hint); font-size: 12.5px; }
  .prop-key svg { width: 14px; height: 14px; flex-shrink: 0; }
  .prop-val { flex: 1; min-width: 0; display: inline-flex; align-items: center; gap: 6px; padding: 3px 8px; margin-left: -8px;
    border-radius: 7px; cursor: pointer; font-size: 13px; min-height: 26px; overflow: hidden; }
  .prop-val:hover { background: var(--bg); }
  .prop-val a { color: var(--purple-dark); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .v-empty { color: var(--placeholder-icon); font-size: 13px; }
  .v-chip { color: var(--text); }
  .v-chip.overdue { color: var(--urgent); font-weight: 600; }
  .v-arrow { color: var(--hint); }
  .dates-pair { display: inline-flex; align-items: center; gap: 8px; }
  #drawer-desc { width: calc(100% + 8px); min-height: 40px; border: none; border-radius: 8px; padding: 8px; margin-left: -8px; outline: none;
    resize: none; overflow: hidden; background: none; color: var(--text); font: inherit; font-size: 13.5px; line-height: 1.55; }
  .desc-placeholder { border: none; background: none; color: var(--hint); font: inherit; font-size: 13.5px; text-align: left;
    padding: 8px; margin-left: -8px; border-radius: 8px; cursor: pointer; width: calc(100% + 8px); }
  .desc-placeholder:hover { background: var(--bg); }
  .md-editor { margin: 2px 0 4px; }
  .md-tabs { display: flex; align-items: center; gap: 12px; margin-bottom: 6px; }
  /* The writing tools appear when somebody starts writing. A card is read far more often than it
     is edited, and a toolbar over every description was a row of controls above text nobody was
     about to change. Focus inside the editor — the text, a tab, or a button on the bar — brings
     them back.
     Hidden by visibility rather than display, deliberately: taking the row out of the layout moved
     the text down the instant somebody clicked into it, which is to say the click landed one line
     from where they aimed. The strip keeps its place and only its contents come and go. */
  .md-editor .md-tabs, .md-editor .rich-bar { visibility: hidden; pointer-events: none; }
  .md-editor:focus-within .md-tabs,
  .md-editor:focus-within .rich-bar { visibility: visible; pointer-events: auto; }
  .md-tabs button { border: none; background: none; font: inherit; font-size: 12.5px; font-weight: 600; color: var(--hint); cursor: pointer; padding: 3px 0; border-bottom: 2px solid transparent; }
  .md-tabs button.active { color: var(--text); border-bottom-color: var(--text); }
  .md-hint { margin-left: auto; font-size: 11px; color: var(--placeholder-icon); }
  .md-view { font-size: 13.5px; line-height: 1.6; color: var(--text); border-radius: 8px; padding: 8px; margin-left: -8px; cursor: text; }
  .md-view:hover { background: var(--bg); }
  .md-view h3 { font-size: 17px; margin: 10px 0 6px; }
  .md-view h4 { font-size: 15px; margin: 10px 0 6px; }
  .md-view h5, .md-view h6 { font-size: 13.5px; margin: 8px 0 4px; }
  .md-view p { margin: 6px 0; }
  .md-view ul, .md-view ol { margin: 6px 0 6px 20px; }
  .md-view li { margin: 2px 0; }
  .md-view code { background: var(--bg); border: 1px solid var(--border); border-radius: 5px; padding: 1px 5px; font-family: ui-monospace, Menlo, monospace; font-size: 12.5px; }
  .md-view pre { background: var(--bg); border: 1px solid var(--border); border-radius: 8px; padding: 10px 12px; overflow-x: auto; margin: 8px 0; }
  .md-view pre code { border: none; background: none; padding: 0; }
  .md-view blockquote { border-left: 3px solid var(--border); margin: 8px 0; padding: 2px 0 2px 12px; color: var(--text-soft); }
  .md-view a { color: var(--purple-dark); }
  .md-view .md-img, .md-view img { max-width: 100%; border-radius: 8px; margin: 6px 0; }
  /* attachments */
  #file-list { display: flex; flex-wrap: wrap; gap: 10px; }
  .att { display: flex; flex-direction: column; border: 1px solid var(--border); border-radius: 10px; overflow: hidden; width: 200px; background: var(--panel); margin: 0; }
  .att img { width: 100%; height: 118px; object-fit: cover; display: block; background: var(--bg); }
  .att-badge { display: flex; align-items: center; justify-content: center; height: 118px; background: var(--bg); color: var(--text-soft); font-weight: 700; font-size: 13px; letter-spacing: 0.5px; }
  .att figcaption { display: flex; align-items: center; gap: 6px; padding: 7px 9px; font-size: 12px; }
  .att .att-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text); text-decoration: none; }
  .att .size { color: var(--hint); font-size: 11px; }
  .att button { border: none; background: none; color: var(--hint); cursor: pointer; }
  .att button:hover { color: var(--urgent); }
  /* subtasks reuse the list table, just tighter */
  .subtask-table table.task-table { font-size: 12.5px; }
  .subtask-table { overflow-x: auto; margin: 0 -4px 6px; }
  #drawer-desc:hover { background: var(--bg); }
  #drawer-desc:focus { background: var(--bg); }
  .card-section { border-top: 1px solid var(--border); padding-top: 14px; margin-top: 8px; }
  .card-section-head { font-size: 13px; font-weight: 700; color: var(--text); margin-bottom: 8px; display: flex; align-items: center; gap: 8px; }
  .card-section-head .count { font-weight: 500; color: var(--hint); font-size: 12px; }
  .card-sub-title { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.4px; color: var(--hint); margin: 14px 0 6px; }
  .quiet-add { border: none; border-radius: 8px; padding: 7px 8px; margin-left: -8px; width: calc(100% + 8px); outline: none; background: none;
    font: inherit; font-size: 13px; color: var(--text); }
  .quiet-add::placeholder { color: var(--hint); }
  .quiet-add:hover, .quiet-add:focus { background: var(--bg); }
  .quiet-btn { border: 1px solid var(--border); background: var(--panel); border-radius: 8px; padding: 6px 12px; cursor: pointer; font: inherit; font-size: 12.5px; color: var(--text-soft); }
  .quiet-btn:hover { border-color: var(--purple); color: var(--purple-dark); }
  .card-actions { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; margin-top: 18px; }
  .card-actions button { display: inline-flex; align-items: center; gap: 8px; border: none; background: none; color: var(--text-soft);
    font: inherit; font-size: 13px; cursor: pointer; padding: 7px 8px; margin-left: -8px; border-radius: 8px; }
  .card-actions button:hover { background: var(--bg); color: var(--purple-dark); }
  .card-actions svg { width: 15px; height: 15px; }
  .card-meta { color: var(--hint); font-size: 11.5px; margin-top: 22px; }
  #drawer-title { font-size: 24px; font-weight: 700; border: none; outline: none; width: calc(100% + 8px); margin-left: -8px; padding: 4px 8px;
    background: none; color: var(--text); resize: none; min-height: 34px; line-height: 1.25; border-radius: 8px; }
  #drawer-title:hover, #drawer-title:focus { background: var(--bg); }
  .field-row { display: flex; align-items: center; gap: 10px; }
  .field-label { width: 100px; flex-shrink: 0; color: var(--hint); font-size: 12.5px; }
  .field-row select, .field-row input[type=date] {
    border: 1px solid var(--border); border-radius: 8px; padding: 6px 9px; background: var(--bg); color: var(--text); outline: none;
  }
  .section-title { font-size: 12px; font-weight: 700; text-transform: uppercase; color: var(--hint); margin-top: 4px; }
  .subtask-item { display: flex; align-items: center; gap: 8px; padding: 4px 0; }
  .subtask-item input[type=text] { flex: 1; border: none; background: none; outline: none; color: var(--text); }
  .subtask-item.done span { text-decoration: line-through; color: var(--hint); }
  #add-subtask-input { border: 1px dashed var(--border); border-radius: 8px; padding: 6px 9px; width: 100%; outline: none; background: none; }
  .link-add { display: flex; gap: 6px; align-items: center; position: relative; margin-top: 6px; }
  .link-add input { flex: 1; min-width: 0; border: 1px solid var(--border); border-radius: 8px; padding: 6px 9px; background: var(--bg); color: var(--text); outline: none; }
  .link-add select { border: 1px solid var(--border); border-radius: 8px; padding: 6px; background: var(--bg); font-size: 12.5px; }
  #link-suggestions { position: absolute; top: 100%; left: 0; right: 0; z-index: 30; background: var(--panel); border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 6px 20px rgba(20,15,40,0.14); max-height: 220px; overflow-y: auto; display: none; }
  #link-suggestions.open { display: block; }
  #link-suggestions div { padding: 7px 10px; font-size: 13px; cursor: pointer; }
  #link-suggestions div:hover { background: var(--bg); }
  .link-item, .url-item { display: flex; align-items: center; gap: 7px; font-size: 13px; padding: 5px 0; }
  .link-item .kind { font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.3px; color: var(--hint); flex-shrink: 0; }
  .link-item .title, .url-item a { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .link-item .title.done { text-decoration: line-through; color: var(--hint); }
  .link-item button, .url-item button { border: none; background: none; color: var(--hint); cursor: pointer; font-size: 15px; padding: 0 2px; }
  .link-item button:hover, .url-item button:hover { color: var(--urgent); }
  .composer { border: 1px solid var(--border); border-radius: 12px; background: var(--panel); overflow: hidden; }
  .composer:focus-within { border-color: #c9c4e8; box-shadow: 0 0 0 3px rgba(123,104,238,0.08); }
  .composer textarea { width: 100%; border: none; outline: none; resize: none; padding: 12px 14px 6px; font: inherit; font-size: 13.5px;
    line-height: 1.5; background: none; color: var(--text); min-height: 22px; max-height: 220px; overflow-y: auto; }
  .composer textarea::placeholder { color: var(--hint); }
  .composer-bar { display: flex; align-items: center; gap: 4px; padding: 6px 8px 8px; }
  .composer-btn { width: 30px; height: 30px; border: none; background: none; border-radius: 8px; color: var(--hint); cursor: pointer;
    display: inline-flex; align-items: center; justify-content: center; }
  .composer-btn:hover { background: var(--bg); color: var(--text-soft); }
  .composer-btn.on { color: var(--purple-dark); background: var(--purple-light); }
  .composer-assignee { font-size: 11.5px; color: var(--purple-dark); background: var(--purple-light); border-radius: 20px; padding: 3px 4px 3px 9px; display: inline-flex; align-items: center; gap: 4px; }
  .composer-assignee button { border: none; background: none; color: inherit; cursor: pointer; font-size: 11px; }
  .composer-send { margin-left: auto; width: 32px; height: 30px; border: none; border-radius: 8px; background: var(--purple); color: #fff; cursor: pointer;
    display: inline-flex; align-items: center; justify-content: center; }
  .composer-send:hover { background: var(--purple-dark); }
  .comment-item.resolved { opacity: 0.55; }
  .comment-item .assigned { font-size: 10.5px; font-weight: 700; color: var(--purple-dark); }
  .comment-item .resolve-btn { border: none; background: none; color: var(--hint); cursor: pointer; font-size: 11.5px; padding: 0; text-decoration: underline; }
  .comment-item { background: var(--bg); border-radius: 8px; padding: 8px 10px; font-size: 13px; }
  .comment-meta { font-size: 10.5px; color: var(--hint); margin-top: 3px; }
  #comment-input { width: 100%; border: 1px solid var(--border); border-radius: 8px; padding: 7px 10px; outline: none; background: var(--bg); color: var(--text); }
  #drawer-delete { color: var(--urgent); background: none; border: none; cursor: pointer; font-size: 12.5px; padding: 4px 0; text-align: left; }

  /* Generic sheet/modal (add list) */
  .modal-overlay { display: none; position: fixed; inset: 0; background: rgba(20,15,40,0.35); z-index: 300; align-items: center; justify-content: center; }
  .modal-overlay.open { display: flex; }
  .modal-box { background: var(--panel); border-radius: 12px; padding: 18px; width: 320px; max-width: 92vw; }
  .modal-box h3 { font-size: 15px; margin-bottom: 12px; }
  .modal-box input { width: 100%; border: 1px solid var(--border); border-radius: 8px; padding: 8px 10px; outline: none; margin-bottom: 12px; }
  .modal-btns { display: flex; gap: 8px; }
  .modal-btns button { flex: 1; padding: 9px; border-radius: 8px; border: none; font-weight: 600; cursor: pointer; }
  .btn-secondary { background: var(--bg); color: var(--hint); }
  .btn-primary { background: var(--purple); color: #fff; }

  .quick-add-row {
    display: flex; align-items: center; gap: 10px; padding: 9px 12px; margin-bottom: 10px;
    background: var(--panel); border-bottom: 1px solid var(--border);
  }
  .quick-add-row input {
    flex: 1; border: none; outline: none; background: none; font-size: 13px; color: var(--text);
  }
  .quick-add-row input::placeholder { color: var(--hint); }
  .quick-add-cancel, .quick-add-save { padding: 6px 12px; border-radius: 6px; border: none; font-weight: 600; cursor: pointer; font-size: 12.5px; }

  .empty-state { color: var(--hint); text-align: center; padding: 40px 10px; font-size: 13px; }

  /* ---------------- Phone layout ----------------
     A phone is not a narrow desktop: the menu becomes a drawer, navigation moves to a bar at
     the bottom where a thumb reaches it, menus arrive as sheets from the bottom edge, the task
     table keeps its Name column pinned while the rest scrolls sideways, and the board shows one
     column at a time with a snap. */
  #side-scrim, #tabbar { display: none; }

  @media (max-width: 780px) {
    body { padding: 0; }
    #app { gap: 0; padding: 0; height: 100%; }

    /* the menu slides over the content instead of taking a column of it */
    #sidebar {
      position: fixed; left: 0; top: 0; height: 100%; z-index: 150;
      width: min(80vw, 310px); margin-left: 0; transform: translateX(-102%);
      border-radius: 0 18px 18px 0; border-left: none;
      transition: transform 0.22s ease; padding-bottom: calc(18px + env(safe-area-inset-bottom, 0px));
    }
    #sidebar.open { transform: none; }
    #side-scrim {
      display: block; position: fixed; inset: 0; z-index: 140; background: rgba(12, 10, 24, 0.44);
      opacity: 0; pointer-events: none; transition: opacity 0.2s;
    }
    body.side-open #side-scrim { opacity: 1; pointer-events: auto; }
    .side-search kbd { display: none; }

    #main { border-radius: 0; border: none; box-shadow: none; background: var(--panel); }

    /* header on two rows: title and actions, then the views as a scrolling strip */
    #topbar { flex-wrap: wrap; height: auto; padding: 8px 12px 0; row-gap: 8px; align-items: center; }
    #hamburger { display: inline-flex; align-items: center; padding: 0 2px; margin-left: -4px; }
    /* The Spaces page has its own title and search, so the app's bar gives way, as it does in Chats. */
    body.view-spaces #topbar { display: none; }
    body.view-spaces #view-body { padding-top: calc(6px + env(safe-area-inset-top, 0px)); }
    #view-title { font-size: 15px; flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
    #topbar-spacer, #properties-btn { display: none; }
    #add-task-btn { display: none; }                 /* the round button in the bar does this */
    .view-tabs {
      order: 3; width: 100%; overflow-x: auto; padding-bottom: 6px;
      scrollbar-width: none; -ms-overflow-style: none;
    }
    .view-tabs::-webkit-scrollbar { display: none; }
    .view-tab { flex: 0 0 auto; }

    #view-body { padding: 12px 0 calc(96px + env(safe-area-inset-bottom, 0px)); }
    /* the board carries its own bottom clearance, so it can fill the screen */
    #view-body:has(.board-wrap), #view-body:has(.wb-wrap) { padding-bottom: 0; }
    .list-section-head, .group-head, .overdue-banner, .meaning-block { padding-left: 12px; padding-right: 12px; }
    .empty-state { padding-left: 12px; padding-right: 12px; }
    /* The view itself has no side padding so a task table can run edge to edge and scroll under a
       pinned column. Everything that is read rather than scrolled sideways needs the margin back,
       or the words start at the glass: an article, the settings, the calendar. */
    #view-body:has(.doc-layout), #view-body:has(.settings), #view-body:has(.cal-grid),
    #view-body:has(.gantt-wrap) {
      padding-left: 14px; padding-right: 14px;
    }


    /* the table scrolls sideways under a pinned Name column */
    .table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
    /* Chromium will not stick a cell inside a table with collapsed borders, nor inside one that
       clips its own overflow — so on a phone the table separates its borders instead. */
    table.task-table { min-width: 0; border-collapse: separate; border-spacing: 0; overflow: visible; }
    /* The name takes the whole width at rest and gives way to the other columns as the table is
       scrolled, down to half the screen (fitNameColumn in app/views.js sets both numbers). Its
       layout width stays the screen's; only what is shown of it narrows, by clipping, and the text
       inside is held to that shown width so its "…" sits at the visible edge. */
    table.task-table col[data-colkey="name"] { width: var(--name-w, 208px) !important; }
    td.name-cell .task-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    table.task-table th:first-child, table.task-table td.name-cell {
      position: sticky; left: 0; z-index: 3; background: var(--panel);
      clip-path: inset(0 calc(100% - var(--name-vis, 100%)) 0 0);
    }
    table.task-table th:first-child > *, table.task-table td.name-cell > * {
      max-width: calc(var(--name-vis, 100%) - 16px); box-sizing: border-box;
    }
    /* Once the columns have come in, a hairline marks where the name ends. */
    /* "Add Task" is one cell a screen wide (it is laid out as a flex box, not a spanning cell), so
       it is pinned the way the names are, or it scrolls away sideways with nothing to replace it. */
    table.task-table td.group-add-cell { position: sticky; left: 0; z-index: 3; background: var(--panel); }
    .table-scroll.shifted table.task-table th:first-child::after,
    .table-scroll.shifted table.task-table td.name-cell::after {
      content: ''; position: absolute; top: 0; bottom: 0; left: calc(var(--name-vis, 100%) - 1px);
      width: 1px; background: var(--border);
    }
    tr.task-row.picked td.name-cell { background: var(--row-picked); }
    tr.task-row:hover td.name-cell { background: var(--row-hover); }
    .row-actions { display: none; }                  /* nothing hovers on a touch screen */
    .row-check { opacity: 1; }                       /* so picking is reachable without hover */
    .row-drag-handle { display: none; }

    /* one column per screen, with a snap, and a header you can hit */
    .board-wrap { gap: 10px; padding: 0 12px calc(90px + env(safe-area-inset-bottom, 0px));
      scroll-snap-type: x mandatory; scroll-padding-left: 12px; }
    .board-col { flex: 0 0 86vw; scroll-snap-align: start; }
    .board-col-head { padding: 10px 12px; }
    .board-col-head .status-chip { flex: 1; justify-content: center; padding: 5px 11px; }

    /* full-screen surfaces */
    #drawer { inset: 0; width: 100%; height: 100%; transform: none; border-radius: 0; }
    #drawer.open { transform: none; }
    #assistant {
      position: fixed; inset: 0; z-index: 160; width: 100%; height: 100%;
      border-radius: 0; border: none; background: var(--panel);
    }
    body.with-assistant #tabbar { display: none; }

    /* menus arrive from the bottom edge, not from a point on the screen */
    #popup-menu.sheet {
      position: fixed; left: 0; right: 0; bottom: 0; top: auto !important;
      width: 100%; max-width: none; max-height: 72vh; overflow-y: auto;
      border-radius: 18px 18px 0 0; padding: 8px 10px calc(14px + env(safe-area-inset-bottom, 0px));
      box-shadow: 0 -12px 40px rgba(16, 16, 30, 0.22); animation: sheet-up 0.2s ease;
      z-index: 240;
      background: var(--panel); backdrop-filter: none; -webkit-backdrop-filter: none;
    }
    #popup-menu.sheet::before {
      content: ''; display: block; width: 38px; height: 4px; border-radius: 2px;
      background: var(--border); margin: 2px auto 10px;
    }
    #popup-menu.sheet .status-menu-item { padding: 12px 12px; font-size: 14.5px; border-radius: 10px; }
    #sheet-scrim { position: fixed; inset: 0; background: rgba(12, 10, 24, 0.38); z-index: 235; }
    @keyframes sheet-up { from { transform: translateY(14px); opacity: 0.6; } to { transform: none; opacity: 1; } }

    /* dialogs sit on the bottom edge too, where the keyboard leaves them visible */
    .app-dialog-overlay { align-items: flex-end; padding: 0; }
    .app-dialog { max-width: none; border-radius: 18px 18px 0 0; padding: 18px 16px calc(18px + env(safe-area-inset-bottom, 0px)); }

    #bulk-bar { left: 12px; right: 12px; transform: none; bottom: calc(80px + env(safe-area-inset-bottom, 0px));
      flex-wrap: wrap; justify-content: center; }

    /* the bar itself */
    /* The bar floats, the way Telegram's does: a rounded pill of frosted glass above the bottom
       edge, the current section sitting in a pill of its own. */
    #tabbar {
      display: flex; align-items: center; justify-content: space-around; gap: 2px;
      position: fixed; left: 10px; right: 10px; z-index: 130;
      bottom: calc(8px + env(safe-area-inset-bottom, 0px));
      padding: 5px; border-radius: 30px;
      background: var(--glass); backdrop-filter: blur(22px) saturate(180%);
      -webkit-backdrop-filter: blur(22px) saturate(180%);
      border: 1px solid var(--glass-edge);
      box-shadow: 0 10px 28px rgba(16, 16, 30, 0.16), 0 1px 3px rgba(16, 16, 30, 0.08);
    }
    .tab-item {
      position: relative; flex: 1; min-width: 0; border: none; background: none; cursor: pointer;
      padding: 6px 2px 5px; border-radius: 24px;
      display: flex; flex-direction: column; align-items: center; gap: 2px;
      color: var(--text-soft); font: inherit; font-size: 11px; font-weight: 600; letter-spacing: 0;
    }
    .tab-item svg { width: 23px; height: 23px; }
    .tab-item span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; }
    .tab-item.active { color: var(--purple-dark); background: var(--purple-light); }
    /* Unread, on the icon's shoulder, the way a messenger shows it. */
    .tab-count {
      position: absolute; top: 1px; left: calc(50% + 4px); min-width: 18px; height: 18px;
      padding: 0 5px; box-sizing: border-box; border-radius: 9px; background: var(--purple); color: #fff;
      font-size: 10.5px; font-weight: 700; line-height: 18px; text-align: center;
      border: 2px solid #fff;
    }
    /* In a chat the app's own bar above was a second header saying less than the chat's. */
    body.view-chat #view-body { padding-top: calc(10px + env(safe-area-inset-top, 0px)); }
    /* The list of chats runs down behind the floating bar, so the bar's glass has something to show
       through it; the rows keep clear of it at the very end of the list with their own padding. */
    body.view-chat:not(.chat-open) #view-body { padding-top: 0; padding-bottom: 0; }
    body.view-chat:not(.chat-open) .chat-rows {
      padding-top: calc(66px + env(safe-area-inset-top, 0px));
      padding-bottom: calc(96px + env(safe-area-inset-bottom, 0px));
    }
    /* And the search along the top is glass too: the rows run up behind it as well. */
    body.view-chat:not(.chat-open) .ch-list { position: relative; }
    body.view-chat:not(.chat-open) .chat-list-head {
      position: absolute; top: 0; left: 0; right: 0; z-index: 5;
      padding: calc(10px + env(safe-area-inset-top, 0px)) 10px 10px;
      background: var(--glass); backdrop-filter: blur(22px) saturate(180%);
      -webkit-backdrop-filter: blur(22px) saturate(180%);
      border-bottom: 1px solid var(--border);
    }
    body.view-chat:not(.chat-open) .chat-search { background: var(--glass-strong); }
    .tab-item.has-news svg { color: var(--purple); }   /* something waiting in Chats: the app's own colour, as elsewhere */
    .tab-fab {
      flex: 0 0 auto; width: 44px; height: 44px; margin-left: 4px; border: none; border-radius: 50%;
      background: var(--ink); color: var(--ink-text); cursor: pointer; display: grid; place-items: center;
      box-shadow: 0 8px 20px rgba(16, 16, 30, 0.28);
    }
    .tab-fab svg { width: 20px; height: 20px; }
  }

  @media (max-width: 780px) and (display-mode: standalone) {
    #topbar { padding-top: calc(8px + env(safe-area-inset-top, 0px)); }
  }

  /* Repeat and Remind me (app/fields.js): the small forms in their popups, the ↻ beside a date. */
  .repeat-form { display: flex; flex-direction: column; gap: 8px; padding: 10px 12px; min-width: 250px; font-size: 13px; }
  .repeat-row { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; }
  .repeat-row input[type="number"] { width: 58px; }
  .repeat-row input, .repeat-row select, .repeat-form input[type="datetime-local"] {
    padding: 4px 6px; border: 1px solid var(--border); border-radius: 6px; background: var(--input-bg, var(--panel)); color: var(--text); font: inherit;
  }
  .repeat-days { display: flex; flex-wrap: wrap; gap: 4px; }
  .repeat-days label { display: inline-flex; align-items: center; gap: 3px; padding: 3px 6px; border: 1px solid var(--border); border-radius: 6px; cursor: pointer; }
  .repeat-days label:has(input:checked) { background: var(--purple-light); border-color: var(--purple); color: var(--purple-dark); }
  .repeat-days input { display: none; }
  .repeat-form .btn-primary { align-self: flex-start; }
  .repeat-mark { margin-left: 5px; color: var(--purple); font-weight: 700; font-size: 13px; }
  .menu-note { padding: 6px 12px 8px; font-size: 11.5px; color: var(--hint); max-width: 240px; }
  .reminder-chip { display: inline-flex; align-items: center; gap: 4px; }
  .chip-x { border: none; background: none; color: var(--hint); cursor: pointer; font-size: 14px; line-height: 1; padding: 0 2px; }
  .chip-x:hover { color: var(--urgent); }

  /* Time on tasks (app/journal.js): the running timer in the top bar, the button on the card, and
     the week's timesheet in Journal. */
  #timer-pill {
    display: inline-flex; align-items: center; gap: 7px; max-width: 260px; height: 32px; padding: 0 12px;
    border: 1px solid var(--border); border-radius: 999px; background: var(--panel); color: var(--text); cursor: pointer; font: inherit; font-size: 13px;
  }
  #timer-pill[hidden] { display: none; }
  .timer-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--urgent); flex-shrink: 0; animation: timer-blink 1.6s ease-in-out infinite; }
  @keyframes timer-blink { 50% { opacity: 0.3; } }
  .timer-clock { font-variant-numeric: tabular-nums; font-weight: 650; }
  .timer-task { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text-soft); }
  .timer-btn {
    height: 30px; padding: 0 11px; border: 1px solid var(--border); border-radius: 8px; background: var(--panel);
    color: var(--text-soft); font: inherit; font-size: 12.5px; cursor: pointer; font-variant-numeric: tabular-nums; white-space: nowrap;
  }
  .timer-btn:hover { border-color: var(--purple); color: var(--purple-dark); }
  .timer-btn.on { background: var(--urgent); border-color: var(--urgent); color: #fff; }
  .journal-tabs { display: inline-flex; border: 1px solid var(--border); border-radius: 9px; overflow: hidden; margin-bottom: 12px; }
  .journal-tabs button { border: none; background: var(--panel); padding: 6px 16px; font: inherit; font-size: 13px; cursor: pointer; color: var(--text-soft); }
  .journal-tabs button.on { background: var(--purple); color: #fff; }
  .sheet-bar { display: flex; align-items: center; gap: 12px; margin: 4px 0 12px; }
  .sheet-who { padding: 5px 8px; border: 1px solid var(--border); border-radius: 7px; background: var(--panel); color: var(--text); font: inherit; }
  table.timesheet { width: 100%; border-collapse: collapse; background: var(--panel); border: 1px solid var(--border); border-radius: 10px; overflow: hidden; font-size: 13px; }
  table.timesheet th, table.timesheet td { padding: 8px 10px; border-bottom: 1px solid var(--border); text-align: center; font-variant-numeric: tabular-nums; }
  table.timesheet th { font-weight: 600; color: var(--text-soft); }
  table.timesheet th small { display: block; font-weight: 500; color: var(--hint); }
  table.timesheet td:first-child, table.timesheet th:first-child { text-align: left; }
  .sheet-task { cursor: pointer; max-width: 380px; }
  .sheet-task:hover { color: var(--purple-dark); }
  .sheet-task small { display: block; color: var(--hint); font-size: 11.5px; }
  .sheet-total { font-weight: 650; }
  table.timesheet tfoot td { font-weight: 650; background: var(--bg); border-bottom: none; }

  /* Workload (renderWorkload in app/board-view.js): people × weeks, coloured by how full each week is. */
  .wl-legend { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; font-size: 12px; margin: 2px 0 12px; }
  .wl-key { display: inline-block; width: 12px; height: 12px; border-radius: 3px; margin-left: 6px; }
  .wl-key.ok, .wl-cell.ok { background: color-mix(in srgb, #00a35a 18%, var(--panel)); }
  .wl-key.full, .wl-cell.full { background: color-mix(in srgb, #f5a623 30%, var(--panel)); }
  .wl-key.over, .wl-cell.over { background: color-mix(in srgb, #e2445c 32%, var(--panel)); }
  table.workload-table { width: 100%; border-collapse: separate; border-spacing: 0; background: var(--panel); border: 1px solid var(--border); border-radius: 10px; overflow: hidden; font-size: 13px; table-layout: fixed; }
  table.workload-table th { font-weight: 600; color: var(--text-soft); padding: 9px 6px; border-bottom: 1px solid var(--border); font-size: 12px; }
  table.workload-table th:first-child { width: 190px; text-align: left; padding-left: 14px; }
  table.workload-table td { height: 50px; border-bottom: 1px solid var(--border); border-right: 1px solid var(--panel); text-align: center; }
  .wl-person { text-align: left !important; padding-left: 14px; display: flex; align-items: center; gap: 8px; height: 50px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .wl-cell { cursor: pointer; font-variant-numeric: tabular-nums; }
  .wl-cell.empty { cursor: default; }
  .wl-cell b { display: block; font-size: 13.5px; }
  .wl-cell small { display: block; font-size: 11px; color: var(--text-soft); }
  .wl-cell:not(.empty):hover { filter: brightness(0.96); }

  /* New list from a template (openTemplatePicker in app/sidebar-tree.js). */
  .tpl-dialog { min-width: min(420px, 92vw); }
  .tpl-field { display: flex; flex-direction: column; gap: 5px; margin: 0 0 12px; font-size: 13px; color: var(--text-soft); }
  .tpl-field select, .tpl-field input {
    padding: 8px 10px; border: 1px solid var(--border); border-radius: 8px; background: var(--input-bg, var(--panel)); color: var(--text); font: inherit; font-size: 14px;
  }
  .danger-text { color: var(--urgent); }

  /* Gantt: the baseline under each bar, and the critical path picked out (app/board-view.js). */
  .g-base {
    position: absolute; top: calc((var(--g-row) + var(--g-bar, 30px)) / 2 + 2px); height: 5px; border-radius: 3px;
    background: var(--hint); opacity: 0.45; z-index: 0; pointer-events: auto;
  }
  .g-base.slipped { background: var(--urgent); opacity: 0.35; }
  .gantt-bar.critical { box-shadow: 0 0 0 2px var(--urgent), 0 4px 10px rgba(228, 71, 62, 0.25); }
  .g-diamond.critical { box-shadow: 0 0 0 2px var(--panel), 0 0 0 4px var(--urgent); }
  .gantt-arrows path.crit { stroke: var(--urgent); stroke-width: 2; }
  .gantt-arrows polygon.crit { fill: var(--urgent); }

  /* Request forms (openFormsDialog / openFormEditor in app/sidebar-tree.js). */
  .app-dialog.form-dialog { max-width: none; }
  .form-dialog { width: min(720px, 94vw); max-height: 88vh; overflow-y: auto; }
  .form-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 10px 0; border-bottom: 1px solid var(--border); }
  .form-row code.form-link { font-size: 11.5px; color: var(--hint); word-break: break-all; }
  .form-row-acts { display: flex; gap: 6px; flex-shrink: 0; }
  .form-flags { display: flex; flex-wrap: wrap; gap: 14px; margin: 0 0 12px; font-size: 13px; }
  .form-q { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; padding: 8px 0; border-bottom: 1px dashed var(--border); font-size: 13px; }
  .form-q input:not([type="checkbox"]) { flex: 1; min-width: 180px; }
  .form-q input, .form-q select, .form-q textarea { padding: 6px 8px; border: 1px solid var(--border); border-radius: 7px; background: var(--input-bg, var(--panel)); color: var(--text); font: inherit; }
  .form-q textarea { flex-basis: 100%; }

  /* Favourites and Recent at the top of the menu (keptHtml in app/space.js). */
  .side-kept-title { margin: 10px 10px 2px; font-size: 10.5px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--side-hint, var(--hint)); }
  .fav-item .side-icon { font-size: 12px; }
  .fav-dot { display: inline-block; width: 10px; height: 10px; border-radius: 3px; }
  .fav-star { color: var(--hint); font-size: 15px; line-height: 1; }
  .fav-star.on { color: #f5a623; }
  .fav-item .fav-star { opacity: 0; }
  .fav-item:hover .fav-star { opacity: 1; }

  /* The shortcuts overlay (showShortcuts in app/views.js). */
  .app-dialog.shortcuts table { border-collapse: collapse; width: 100%; font-size: 13.5px; }
  .app-dialog.shortcuts td { padding: 5px 8px; border-bottom: 1px solid var(--border); }
  .app-dialog.shortcuts td:first-child { white-space: nowrap; color: var(--hint); }
  kbd { display: inline-block; min-width: 20px; padding: 1px 6px; border: 1px solid var(--border); border-bottom-width: 2px; border-radius: 5px;
    background: var(--panel); color: var(--text); font: 600 12px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace; text-align: center; }

  /* A space's files (openSpaceFiles) */
  .app-dialog.files-dialog { width: min(980px, 95vw); max-width: none; max-height: 90vh; display: flex; flex-direction: column; }
  .files-head { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
  .files-head h3 { flex: 1; margin: 0; }
  .files-search { width: 220px; max-width: 100%; padding: 7px 10px; border: 1px solid var(--border); border-radius: 8px; background: var(--panel); color: var(--text); font: inherit; }
  .files-kinds { display: flex; gap: 6px; flex-wrap: wrap; margin: 12px 0; }
  .files-kinds .chip { border: 1px solid var(--border); background: var(--panel); color: var(--text-soft); border-radius: 20px; padding: 4px 12px; font: inherit; font-size: 13px; cursor: pointer; }
  .files-kinds .chip.on { background: var(--purple-light); border-color: var(--purple); color: var(--purple-dark); }
  .files-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 12px; overflow-y: auto; min-height: 120px; padding: 2px; }
  .file-tile { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
  .file-thumb { aspect-ratio: 4 / 3; border: 1px solid var(--border); border-radius: 10px; background: var(--bg); overflow: hidden; padding: 0; cursor: pointer; display: flex; align-items: center; justify-content: center; }
  .file-thumb:hover { border-color: var(--purple); }
  .file-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
  .file-ext { font-weight: 700; font-size: 15px; color: var(--hint); letter-spacing: 0.04em; }
  .file-name { font-size: 13px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .file-meta { font-size: 11.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .file-from { border: none; background: none; padding: 0; text-align: left; font: inherit; font-size: 11.5px; color: var(--purple); cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .file-from:hover { text-decoration: underline; }
  .files-empty { grid-column: 1 / -1; text-align: center; padding: 30px 0; }
  .file-picture { position: fixed; inset: 0; z-index: 3000; background: rgba(10, 10, 16, 0.86); display: flex; align-items: center; justify-content: center; padding: 24px; }
  .file-picture figure { margin: 0; max-width: 100%; max-height: 100%; display: flex; flex-direction: column; align-items: center; gap: 10px; }
  .file-picture img { max-width: 92vw; max-height: 82vh; object-fit: contain; border-radius: 6px; }
  .file-picture figcaption { color: #eee; font-size: 13px; }
  .file-picture figcaption a { color: #c9c1ff; }
  @media (max-width: 600px) { .files-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } .files-search { width: 100%; } }

  /* Sign-off on the card (signoffHtml) */
  .signoff-ask-row { margin: 2px 0 10px; }
  .signoff-row { display: flex; align-items: baseline; gap: 10px; padding: 6px 0; border-bottom: 1px solid var(--border); flex-wrap: wrap; }
  .signoff-row:last-of-type { border-bottom: none; }
  .signoff-state { font-size: 11.5px; font-weight: 600; border-radius: 20px; padding: 1px 9px; background: var(--bg); color: var(--text-soft); white-space: nowrap; }
  .signoff-row.approved .signoff-state { background: rgba(38, 166, 106, 0.14); color: #1f8a57; }
  .signoff-row.changes .signoff-state { background: rgba(214, 66, 90, 0.12); color: var(--urgent); }
  .signoff-who { font-weight: 600; }
  .signoff-note { color: var(--text-soft); font-size: 13px; flex-basis: 100%; padding-left: 2px; }
  .signoff-acts { margin-left: auto; display: flex; gap: 10px; }
  .signoff-mine { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 10px; padding: 10px 12px; border-radius: 10px; background: var(--purple-light); }
  .signoff-mine span { flex: 1; min-width: 180px; color: var(--purple-dark); font-weight: 600; font-size: 13px; }
  @media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .signoff-row.approved .signoff-state { color: #5fd49a; } }
  :root[data-theme="dark"] .signoff-row.approved .signoff-state { color: #5fd49a; }

  /* Rules (openRulesDialog, openRuleEditor) */
  .rule-row { display: flex; align-items: center; gap: 12px; padding: 10px 0; border-bottom: 1px solid var(--border); }
  .rule-text { flex: 1; min-width: 0; }
  .rule-error { color: var(--urgent); font-size: 12.5px; margin-top: 2px; }
  .rule-part { margin: 14px 0; }
  .rule-label { font-weight: 700; font-size: 12px; text-transform: uppercase; letter-spacing: 0.05em; color: var(--hint); margin-bottom: 6px; }
  .rule-line { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-bottom: 6px; }
  .rules-dialog select, .rules-dialog input:not([type="checkbox"]) { padding: 6px 8px; border: 1px solid var(--border); border-radius: 8px; background: var(--panel); color: var(--text); font: inherit; font-size: 13.5px; max-width: 100%; }
  .rules-dialog .rule-line input:not([type="number"]) { flex: 1; min-width: 160px; }
  .rules-dialog .rule-line input[type="number"] { width: 80px; }
  .rule-toggle { width: 18px; height: 18px; accent-color: var(--purple); flex-shrink: 0; cursor: pointer; }
  .rule-name { display: flex; align-items: center; gap: 10px; font-weight: 600; font-size: 13px; }
  .rules-dialog .rule-name input { flex: 1; }
  .rules-dialog .rule-line input, .rules-dialog .rule-line select, .rules-dialog .rule-name input { margin: 0; }

  /* Goals (app/goals.js) */
  .goals-page { max-width: 900px; margin: 0 auto; padding: 8px 4px 40px; }
  .goals-head { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 16px; }
  .goals-head select { padding: 7px 10px; border: 1px solid var(--border); border-radius: 8px; background: var(--panel); color: var(--text); font: inherit; }
  .goals-archived { display: flex; align-items: center; gap: 6px; color: var(--text-soft); font-size: 13px; }
  .goal-card { background: var(--panel); border: 1px solid var(--border); border-radius: 14px; padding: 16px 18px; margin-bottom: 14px; }
  .goal-card.archived { opacity: 0.65; }
  .goal-top { display: flex; align-items: flex-start; gap: 12px; }
  .goal-title { flex: 1; min-width: 0; }
  .goal-title b { font-size: 16px; }
  .goal-title .muted { font-size: 12.5px; margin-top: 2px; }
  .goal-total b { font-size: 20px; color: var(--purple-dark); }
  .goal-bar { height: 6px; border-radius: 3px; background: var(--bg); overflow: hidden; }
  .goal-bar span { display: block; height: 100%; background: var(--purple); border-radius: 3px; transition: width 0.3s; }
  .goal-bar.big { height: 9px; margin: 10px 0 6px; }
  .goal-desc { color: var(--text-soft); white-space: pre-wrap; margin: 6px 0 4px; font-size: 13.5px; }
  .goal-results { margin-top: 8px; }
  .goal-result { display: grid; grid-template-columns: minmax(140px, 1.3fr) minmax(120px, 1fr) minmax(80px, 1fr) auto; gap: 12px; align-items: center; padding: 8px 0; border-top: 1px solid var(--border); }
  .goal-result-name { font-weight: 600; font-size: 13.5px; text-align: left; }
  button.goal-result-name.editable { border: none; background: none; padding: 0; font: inherit; font-weight: 600; font-size: 13.5px; color: var(--text); cursor: pointer; }
  button.goal-result-name.editable:hover { color: var(--purple); }
  .goal-result-value { font-size: 13px; }
  .goal-foot { display: flex; gap: 16px; margin-top: 8px; }
  .goal-checkins { margin-top: 8px; padding: 8px 10px; background: var(--bg); border-radius: 8px; font-size: 12.5px; display: flex; flex-direction: column; gap: 4px; }
  .goals-empty { text-align: center; padding: 40px 10px; }
  .goal-field { display: flex; flex-direction: column; gap: 4px; font-size: 12.5px; font-weight: 600; color: var(--text-soft); margin: 10px 0; }
  .goal-field input, .goal-field select, .goal-field textarea { padding: 8px 10px; border: 1px solid var(--border); border-radius: 8px; background: var(--panel); color: var(--text); font: inherit; font-weight: 400; margin: 0; }
  @media (max-width: 600px) {
    .goal-result { grid-template-columns: 1fr auto; }
    .goal-result .goal-bar { grid-column: 1 / -1; }
  }

  /* Sprints (app/sprints.js) */
  .sprints-page { padding: 4px 2px 40px; }
  .sprints-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 14px; }
  .sprints-head select { padding: 7px 10px; border: 1px solid var(--border); border-radius: 8px; background: var(--panel); color: var(--text); font: inherit; max-width: 100%; }
  .sprint-summary { display: grid; grid-template-columns: minmax(220px, 1fr) minmax(280px, 1.4fr); gap: 20px; background: var(--panel); border: 1px solid var(--border); border-radius: 14px; padding: 16px 18px; margin-bottom: 16px; }
  .sprint-facts { display: flex; flex-direction: column; gap: 8px; }
  .sprint-goal { color: var(--text-soft); font-size: 13.5px; }
  .sprint-numbers { display: flex; gap: 16px; flex-wrap: wrap; font-size: 13px; }
  .burndown { width: 100%; height: auto; }
  .bd-grid { stroke: var(--border); stroke-width: 1; }
  .bd-label { fill: var(--hint); font-size: 10px; }
  .bd-ideal { fill: none; stroke: var(--hint); stroke-width: 1.5; stroke-dasharray: 5 4; }
  .bd-actual { fill: none; stroke: var(--purple); stroke-width: 2.2; }
  .bd-dot { fill: var(--purple); }
  .sprint-columns { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 16px; }
  .sprint-col h4 { margin: 0 0 8px; font-size: 13.5px; display: flex; gap: 8px; align-items: center; }
  .sprint-task { display: flex; align-items: center; gap: 10px; padding: 7px 10px; border: 1px solid var(--border); border-radius: 10px; background: var(--panel); margin-bottom: 6px; }
  .sprint-task.done .sprint-task-name { text-decoration: line-through; color: var(--hint); }
  .sprint-task-name { flex: 1; min-width: 0; border: none; background: none; padding: 0; text-align: left; font: inherit; font-size: 13.5px; color: var(--text); cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .sprint-task-name:hover { color: var(--purple); }
  .sprint-status { font-size: 11.5px; color: var(--text-soft); background: var(--bg); border-radius: 20px; padding: 1px 8px; white-space: nowrap; }
  .sprint-points { width: 58px; padding: 4px 6px; border: 1px solid var(--border); border-radius: 7px; background: var(--panel); color: var(--text); font: inherit; font-size: 13px; margin: 0; }
  .sprint-points-ro { font-size: 12.5px; color: var(--text-soft); min-width: 24px; text-align: right; }
  .sprints-empty { text-align: center; padding: 40px 10px; }
  .sprint-spaces { display: flex; gap: 8px; justify-content: center; flex-wrap: wrap; margin-top: 12px; }
  @media (max-width: 700px) { .sprint-summary { grid-template-columns: 1fr; } .sprint-task { flex-wrap: wrap; } }
  .card-sprint-line { display: flex; align-items: center; gap: 8px; margin: 2px 0 10px; font-size: 13px; }
  .card-sprint-line label { display: flex; align-items: center; gap: 6px; color: var(--text-soft); }
  .goals-page.wide { max-width: 1200px; }
  .goals-tabs { flex-shrink: 0; margin-bottom: 0; }
  .portfolio-table { background: var(--panel); border: 1px solid var(--border); border-radius: 12px; overflow: hidden; }
  .pf-row { display: grid; grid-template-columns: minmax(180px, 2fr) 110px minmax(120px, 1.2fr) 50px 190px minmax(120px, 1.4fr); gap: 12px; align-items: center; padding: 10px 14px; border-top: 1px solid var(--border); font-size: 13px; }
  .pf-head { border-top: none; font-size: 11.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; color: var(--hint); background: var(--bg); }
  .pf-name { border: none; background: none; padding: 0; font: inherit; font-weight: 600; color: var(--text); cursor: pointer; text-align: left; }
  .pf-name:hover { color: var(--purple); }
  .pf-space { display: block; font-size: 11.5px; }
  .pf-progress { display: flex; align-items: center; gap: 8px; }
  .pf-progress .goal-bar { flex: 1; }
  .pf-late { color: var(--urgent); font-weight: 700; }
  .pf-people { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .health { display: inline-block; font-size: 11.5px; font-weight: 600; border-radius: 20px; padding: 2px 9px; background: var(--bg); color: var(--text-soft); white-space: nowrap; }
  .health.on { background: rgba(38, 166, 106, 0.14); color: #1f8a57; }
  .health.risk { background: rgba(230, 160, 20, 0.16); color: #a86a00; }
  .health.off { background: rgba(214, 66, 90, 0.13); color: var(--urgent); }
  .health.finished { background: var(--purple-light); color: var(--purple-dark); }
  .health-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; margin: 0 4px 0 2px; background: var(--hint); }
  .health-dot.on { background: #26a66a; } .health-dot.risk { background: #e6a014; } .health-dot.off { background: var(--urgent); }
  @media (max-width: 900px) {
    .pf-row { grid-template-columns: 1fr auto; }
    .pf-head { display: none; }
    .pf-row > span:nth-child(n+3) { grid-column: 1 / -1; }
  }
  .goal-foot .quiet-link { margin: 0; }

  /* A task's picture or recording, large, with its notes (app/fileviewer.js) */
  .file-viewer { position: fixed; inset: 0; z-index: 2500; display: grid; grid-template-columns: 1fr 340px; background: rgba(12, 12, 18, 0.9); }
  .fv-stage { display: flex; align-items: center; justify-content: center; padding: 24px; min-width: 0; min-height: 0; }
  .fv-picture { position: relative; display: inline-block; max-width: 100%; max-height: 100%; }
  .fv-picture img { display: block; max-width: calc(100vw - 340px - 48px); max-height: calc(100vh - 48px); object-fit: contain; cursor: crosshair; border-radius: 4px; }
  .fv-pins { position: absolute; inset: 0; pointer-events: none; }
  .fv-pin { position: absolute; transform: translate(0, -100%); width: 26px; height: 26px; border-radius: 50% 50% 50% 0; border: 2px solid #fff;
    background: var(--purple); color: #fff; font: 700 12px/22px system-ui, sans-serif; text-align: center; padding: 0; cursor: pointer; pointer-events: auto;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.35); }
  .fv-pin.resolved { background: #8e8ba0; }
  .fv-pin.draft { background: #f0a020; pointer-events: none; }
  .fv-pin.lit { outline: 3px solid #ffd54a; }
  .fv-media { max-width: 100%; max-height: calc(100vh - 48px); border-radius: 6px; background: #000; }
  audio.fv-media { width: min(640px, 100%); background: none; }
  .fv-side { background: var(--panel); color: var(--text); display: flex; flex-direction: column; gap: 10px; padding: 16px; overflow-y: auto; }
  .fv-head { display: flex; align-items: center; gap: 8px; }
  .fv-head b { flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .fv-hint { font-size: 12.5px; }
  .fv-draft-box { display: flex; flex-direction: column; gap: 6px; padding: 10px; border: 1px solid var(--purple); border-radius: 10px; }
  .fv-draft-box textarea { width: 100%; box-sizing: border-box; padding: 8px; border: 1px solid var(--border); border-radius: 8px; background: var(--panel); color: var(--text); font: inherit; resize: vertical; margin: 0; }
  .fv-draft-acts { display: flex; justify-content: flex-end; gap: 8px; }
  .fv-notes { display: flex; flex-direction: column; gap: 8px; flex: 1; }
  .fv-note { padding: 8px 10px; border: 1px solid var(--border); border-radius: 10px; cursor: pointer; }
  .fv-note.lit { border-color: var(--purple); }
  .fv-note.resolved { opacity: 0.6; }
  .fv-note-top { display: flex; align-items: center; gap: 8px; font-size: 12.5px; }
  .fv-note-top .muted { margin-left: auto; font-size: 11.5px; }
  .fv-no { min-width: 22px; height: 20px; padding: 0 5px; border-radius: 10px; background: var(--purple); color: #fff; font-size: 11px; font-weight: 700; display: inline-flex; align-items: center; justify-content: center; }
  .fv-note-text { margin-top: 4px; font-size: 13.5px; white-space: pre-wrap; }
  .fv-note-acts { display: flex; gap: 12px; margin-top: 4px; }
  .fv-resolved { display: flex; align-items: center; gap: 6px; font-size: 12.5px; color: var(--text-soft); }
  .fv-empty { font-size: 13px; }
  .att-play { border: none; cursor: pointer; font-size: 16px; color: var(--purple); }
  .linkish { border: none; background: none; padding: 0; font: inherit; color: inherit; cursor: pointer; text-align: left; }
  @media (max-width: 760px) {
    .file-viewer { grid-template-columns: 1fr; grid-template-rows: minmax(0, 55vh) 1fr; }
    .fv-picture img { max-width: calc(100vw - 32px); max-height: calc(55vh - 32px); }
    .fv-stage { padding: 16px; }
  }
  .fv-note-acts .quiet-link, .fv-side > .quiet-link { margin: 0; }

  /* Table view: a column of checkboxes, always showing, and one for comments after the name. */
  table.task-table.tv td.pick-cell, table.task-table.tv th.pick-cell { width: 34px; padding: 0; text-align: center; }
  table.task-table.tv .pick-cell .row-check, table.task-table.tv .pick-cell .group-check { opacity: 1; justify-content: center; width: 100%; }
  table.task-table.tv td.comments-cell, table.task-table.tv th.comments-cell { width: 46px; padding: 0; text-align: center; color: var(--hint); }
  .comments-btn { display: inline-flex; align-items: center; gap: 3px; border: none; background: none; padding: 4px 6px; border-radius: 6px;
    color: var(--hint); font: inherit; font-size: 11.5px; cursor: pointer; opacity: 0.55; }
  .comments-btn.has { color: var(--purple); opacity: 1; font-weight: 600; }
  tr.task-row:hover .comments-btn { opacity: 1; }
  .comments-btn:hover { background: var(--row-hover); color: var(--purple); }

  /* The team picker (openTeamPicker): a dot on each row to recolour it, and the palette. */
  .team-picker { min-width: 220px; }
  .team-menu-row { display: flex; align-items: center; gap: 8px; }
  .team-menu-row .team-tag { flex: 1; }
  .team-recolour { width: 14px; height: 14px; border-radius: 50%; border: 2px solid var(--panel); box-shadow: 0 0 0 1px var(--border);
    padding: 0; cursor: pointer; flex-shrink: 0; opacity: 0; }
  .team-menu-row:hover .team-recolour, .sheet .team-recolour { opacity: 1; }
  .team-add { color: var(--purple); font-weight: 600; }
  .team-new { display: flex; flex-direction: column; gap: 8px; padding: 4px; }
  .team-new-title { font-size: 13px; display: flex; align-items: center; gap: 6px; }
  .team-new-hint { font-size: 12px; }
  .team-swatches { display: grid; grid-template-columns: repeat(6, 26px); gap: 7px; }
  .team-swatch { width: 26px; height: 26px; border-radius: 7px; border: none; cursor: pointer; padding: 0; }
  .team-swatch:hover { transform: scale(1.12); box-shadow: 0 0 0 2px var(--panel), 0 0 0 4px var(--purple); }
  /* A task's teams, like tags: each chip as wide as its name, several side by side. */
  .team-chips { display: inline-flex; gap: 4px; flex-wrap: nowrap; overflow: hidden; max-width: 100%; vertical-align: middle; }
  .team-tag.team-chip { display: inline-block; width: auto; flex-shrink: 0; white-space: nowrap; }
  .team-check { width: 14px; flex-shrink: 0; color: var(--purple); font-weight: 700; text-align: center; }
  .team-menu-row .team-tag.team-chip { flex: 0 0 auto; }
  .team-menu-row { justify-content: flex-start; }
  .team-menu-row .team-recolour { margin-left: auto; }
  /* Parts not shown yet (HIDDEN_FOR_NOW in app/core.js). */
  .hide-goals #rail-goals, .hide-journal #rail-journal, .hide-journal #tab-journal,
  .hide-sprints .view-tab[data-view="sprints"], .hide-workload .view-tab[data-view="workload"] { display: none !important; }

  /* ---------- Chats as lines (Settings → Chats → Lines): a team chat rather than a messenger ----------
     The plain panel instead of the wallpaper; every message on the left, as a line under its
     author's name and time; the list of chats in sections, one short row each. */
  .chat-lines .ch-main, .chat-lines .ch-beside-one { background: var(--panel); }
  .chat-lines .ch-msg, .chat-lines .ch-msg.mine { flex-direction: row; align-items: flex-start; gap: 10px; margin-top: 0; padding: 1px 12px; border-radius: 6px; }
  .chat-lines .ch-msg:not(.run-on) { margin-top: 10px; }
  .chat-lines .ch-msg:hover { background: var(--row-hover); }
  .chat-lines .ch-msg .ch-avatar { width: 36px; height: 36px; border-radius: 8px; flex-shrink: 0; }
  .chat-lines .ch-msg .ch-avatar-gap { height: 1px; }
  .chat-lines .ch-bubble, .chat-lines .ch-msg.mine .ch-bubble {
    background: none; border: none; box-shadow: none; padding: 0; border-radius: 0; max-width: none; flex: 1; min-width: 0; }
  .chat-lines .ch-author { color: var(--text); font-size: 14.5px; font-weight: 700; margin-bottom: 1px; }
  .chat-lines .ch-author-time { font-weight: 400; font-size: 12px; color: var(--hint); margin-left: 8px; }
  .chat-lines .ch-text { font-size: 15px; line-height: 1.45; }
  /* The time is in the heading; a line's own clock shows on hover, and ticks stay for your own. */
  .chat-lines .ch-meta { float: none; display: inline-block; margin: 0 0 0 8px; opacity: 0; transition: opacity 0.1s; }
  .chat-lines .ch-msg:hover .ch-meta, .chat-lines .ch-msg.mine .ch-meta .ch-mark { opacity: 1; }
  .chat-lines .ch-msg.mine:hover .ch-meta { opacity: 1; }
  .chat-lines .ch-replies { margin-top: 4px; }
  .chat-lines .ch-day { margin: 14px 0 6px; }
  /* The list: sections, and one short row a chat. */
  .chat-lines .line-section { margin-bottom: 8px; }
  .line-section-head { display: flex; align-items: center; gap: 6px; width: 100%; border: none; background: none; padding: 6px 10px 4px;
    font: inherit; font-size: 12.5px; font-weight: 700; color: var(--text-soft); cursor: pointer; text-align: left; }
  .line-section-head .ch-count { margin-left: auto; }
  .line-caret { display: inline-flex; transform: rotate(90deg); transition: transform 0.12s; color: var(--hint); }
  .line-section.shut .line-caret { transform: none; }
  .chat-row.line-row { gap: 9px; padding: 5px 10px; border-radius: 8px; margin-bottom: 1px; font-size: 14.5px; }
  .chat-row.line-row .chat-row-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 400; }
  .chat-row.line-row.unread .chat-row-name { font-weight: 700; color: var(--text); }
  .chat-row.line-row .ch-avatar { width: 22px; height: 22px; border-radius: 6px; font-size: 10px; }
  .line-mark { width: 22px; display: inline-flex; justify-content: center; color: var(--hint); font-size: 16px; font-weight: 600; flex-shrink: 0; }
  .line-mark svg { width: 17px; height: 17px; }
  .chat-lines .chat-row.assistant-row .ch-avatar, .chat-lines .chat-row.agents-row .ch-avatar { width: 30px; height: 30px; }
  .chat-lines .chat-row.assistant-row, .chat-lines .chat-row.agents-row { padding: 6px 10px; }
  .chat-lines .ch-msg.run-on .ch-text { line-height: 1.4; }

  /* Message tools: laid out as before in bubbles (the wrapper takes no box of its own)… */
  .ch-acts { display: contents; }
  /* …and in lines, a small card at the top right of the line under the pointer. */
  .chat-lines .ch-msg { position: relative; }
  .chat-lines .ch-acts { display: none; position: absolute; top: -14px; right: 14px; z-index: 2; gap: 1px; padding: 2px;
    background: var(--panel); border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 2px 8px rgba(20, 15, 40, 0.1); }
  .chat-lines .ch-msg:hover .ch-acts { display: inline-flex; }
  .chat-lines .ch-acts .ch-act { position: static; opacity: 1; width: 28px; height: 26px; border-radius: 6px; margin: 0; }
  .chat-lines .ch-acts .ch-act:hover { background: var(--row-hover); }

  /* Lines: one plain column — tabs, header, the lines, the composer — nothing floating over the words. */
  .chat-lines .ch-wrap { background: var(--panel); border-radius: 12px; overflow: hidden; }
  .chat-lines .ch-list { background: var(--bg); border-right: 1px solid var(--border); padding: 10px 8px; }
  .chat-lines .ch-split { display: none; }
  .chat-lines .ch-main { margin-left: 0; border-radius: 0; background: var(--panel); }
  .chat-lines .ch-main::before, .chat-lines .ch-main::after { display: none; }
  .chat-lines .ch-messages { position: static; flex: 1; min-height: 0; padding: 6px 4px 14px; }
  .chat-lines .ch-foot { position: static; padding: 0 16px 14px; }
  .chat-lines .chat-search { border-radius: 8px; background: var(--panel); border: 1px solid var(--border); height: 34px; font-size: 13.5px; }
  .chat-lines .chat-list-head { padding: 0 2px 8px; }

  /* The tabs of chats open lately. */
  .ln-tabs { display: flex; align-items: stretch; gap: 0; border-bottom: 1px solid var(--border); background: var(--bg); min-height: 38px; overflow-x: auto; flex-shrink: 0; }
  .ln-tab { display: flex; align-items: center; gap: 6px; max-width: 220px; padding: 0 8px 0 12px; border-right: 1px solid var(--border);
    font-size: 13px; color: var(--text-soft); cursor: pointer; white-space: nowrap; }
  .ln-tab.on { background: var(--panel); color: var(--text); font-weight: 600; box-shadow: inset 0 -2px 0 var(--purple); }
  .ln-tab:hover:not(.on) { background: var(--row-hover); }
  .ln-tab-mark { color: var(--hint); font-weight: 600; }
  .ln-tab-name { overflow: hidden; text-overflow: ellipsis; }
  .ln-tab-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--purple); flex-shrink: 0; }
  .ln-tab-x { border: none; background: none; color: var(--hint); font-size: 15px; line-height: 1; padding: 2px 4px; border-radius: 4px; cursor: pointer; opacity: 0.6; }
  .ln-tab-x:hover { opacity: 1; background: var(--row-hover); color: var(--text); }
  .ln-tab-new { border: none; background: none; color: var(--hint); font-size: 18px; padding: 0 12px; cursor: pointer; }
  .ln-tab-new:hover { color: var(--purple); }

  /* The header: flat, the name large, who has been talking on the right. */
  .ln-head { display: flex; align-items: center; gap: 8px; padding: 10px 16px; border-bottom: 1px solid var(--border); flex-shrink: 0; min-height: 50px; box-sizing: border-box; }
  .ln-head .chat-back { display: none; }
  .ln-head-mark { color: var(--hint); font-size: 19px; font-weight: 600; display: inline-flex; }
  .ln-head-mark svg { width: 18px; height: 18px; }
  .ln-head .ch-avatar { width: 26px; height: 26px; border-radius: 7px; font-size: 11px; }
  .ln-head-name { font-size: 17px; font-weight: 700; color: var(--text); cursor: pointer; }
  .ln-head-sub { font-size: 13px; color: var(--hint); margin-left: 4px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .ln-faces { display: inline-flex; border: none; background: none; padding: 2px; cursor: pointer; border-radius: 8px; }
  .ln-faces:hover { background: var(--row-hover); }
  .ln-faces .ch-avatar { width: 24px; height: 24px; border-radius: 6px; font-size: 10px; border: 2px solid var(--panel); box-sizing: content-box; }
  .ln-faces .ch-avatar + .ch-avatar { margin-left: -6px; }

  /* Where the unread begins. */
  .ln-new { display: flex; align-items: center; margin: 10px 12px 4px; }
  .ln-new::before { content: ''; flex: 1; border-top: 1px solid var(--urgent); opacity: 0.55; }
  .ln-new span { font-size: 11.5px; font-weight: 700; color: var(--urgent); margin-left: 8px; }
  .chat-lines .ch-day { display: flex; align-items: center; margin: 16px 12px 8px; }
  .chat-lines .ch-day::before, .chat-lines .ch-day::after { content: ''; flex: 1; border-top: 1px solid var(--border); }
  .chat-lines .ch-day span { background: var(--panel); border: 1px solid var(--border); color: var(--text-soft); font-size: 12px; font-weight: 600;
    border-radius: 20px; padding: 2px 12px; box-shadow: none; }

  /* The lines: square-ish faces, the name strong, the words plain. */
  .chat-lines .ch-msg .ch-avatar { border-radius: 8px; }
  .chat-lines .ch-text { color: var(--text); }

  /* The composer: a box, and its tools on a bar underneath. */
  .ln-compose { border: 1px solid var(--border); border-radius: 10px; background: var(--panel); transition: border-color 0.1s, box-shadow 0.1s; }
  .ln-compose:focus-within { border-color: var(--purple); box-shadow: 0 0 0 3px var(--purple-light); }
  .ln-compose textarea { display: block; width: 100%; box-sizing: border-box; border: none; outline: none; resize: none; background: none;
    padding: 11px 14px 6px; font: inherit; font-size: 15px; color: var(--text); max-height: 240px; margin: 0; }
  .ln-tools { display: flex; align-items: center; gap: 2px; padding: 4px 8px 6px; }
  .ln-tools button { border: none; background: none; color: var(--hint); width: 30px; height: 28px; border-radius: 6px; cursor: pointer;
    display: inline-flex; align-items: center; justify-content: center; font: inherit; font-size: 15px; font-weight: 600; }
  .ln-tools button:hover { background: var(--row-hover); color: var(--text); }
  .ln-hint { font-size: 11.5px; color: var(--hint); margin-left: 8px; }
  .ln-tools .ln-send { background: var(--purple); color: #fff; width: 32px; }
  .ln-tools .ln-send:hover { background: var(--purple-dark); color: #fff; }
  @media (max-width: 780px) { .ln-hint { display: none; } .ln-head .chat-back { display: inline-flex; } .ln-tabs { display: none; } }
  /* A line's own time sits in the gutter under the face, shown on hover; the first line's is in the heading. */
  .chat-lines .ch-msg .ch-meta { position: absolute; left: 12px; top: 5px; width: 36px; margin: 0; text-align: center; font-size: 10.5px; float: none; }
  .chat-lines .ch-msg:not(.run-on) .ch-meta { display: none; }
  .ln-tab.on .ln-tab-dot { display: none; }
  .chat-lines .ch-msg .ch-meta { left: 6px; width: 48px; font-size: 10px; white-space: nowrap; }

  /* Table view text: the same size and colour as a task's name — the column names, the dates, the
     numbers, what is typed at the bottom — with colour kept only where it says something (late,
     soon, a status or priority fill). */
  .table-group table.task-table th { font-size: 14px; font-weight: 400; color: var(--title-text); }
  .table-group table.task-table th .th-label { font-weight: 400; }
  .table-group table.task-table td { font-size: 14px; color: var(--title-text); }
  .table-group table.task-table td .due-text { font-size: 14px; }
  .table-group table.task-table td .due-text.overdue, .table-group table.task-table td .due-text.soon { font-weight: 400; }
  .table-group table.task-table td.tv-fill { font-size: 14px; font-weight: 400; }
  .table-group .tv-add-input { font-size: 14px; }
  /* The frame is the table's last line: the last row does not draw one of its own on top of it. */
  .table-group table.task-table tr:last-child td { border-bottom: none; }
  /* The Gantt's dates under a name: the same face as the name, plainer and smaller. */
  .g-dates { font-size: 12.5px; font-weight: 400; letter-spacing: 0; line-height: 1.2; }
  /* Table view column names are words alone: no icon before them (the comments column, which has no
     name, keeps its icon). */
  .table-group table.task-table th .th-inner > svg { display: none; }
  /* Table view: a column's name in the middle of the column, whatever buttons sit beside it — the
     sort button is laid over the right edge rather than taking room from the name. */
  .table-group table.task-table th .th-inner { position: static; justify-content: center; width: 100%; }
  .table-group table.task-table th .sort-btn { position: absolute; right: 6px; top: 50%; transform: translateY(-50%); margin: 0; }
  /* A filled cell (a status, a priority, or an empty one waiting for it) is ruled like every other
     cell: white lines round the fills read as a gap in the grid, between two grey ones. */
  .table-group table.task-table td.tv-fill { border-right-color: var(--table-rule); border-bottom-color: var(--table-rule); }
