/* ============================================================================
   Tickets — personal desk
   Tokens first, then layout, then components.
   ========================================================================== */

*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
html { -webkit-text-size-adjust: 100%; }
body { line-height: 1.5; -webkit-font-smoothing: antialiased; }
img, svg, video { display: block; max-width: 100%; }
input, button, textarea, select { font: inherit; color: inherit; }
button { background: none; border: 0; padding: 0; cursor: pointer; }
a { color: inherit; text-decoration: none; }
:where(h1,h2,h3,h4) { font-weight: 600; line-height: 1.25; }

/* ------------------------------------------------------------------ tokens */

:root {
  color-scheme: light;

  --c-slate:  215 16% 42%;
  --c-red:    0 72% 48%;
  --c-orange: 22 90% 40%;
  --c-amber:  36 92% 34%;
  --c-green:  148 62% 31%;
  --c-teal:   176 62% 31%;
  --c-cyan:   194 82% 36%;
  --c-blue:   217 84% 50%;
  --c-indigo: 243 62% 55%;
  --c-violet: 264 66% 54%;
  --c-pink:   330 70% 50%;

  --bg:            #f4f6f8;
  --bg-grad:       radial-gradient(1200px 600px at 70% -10%, #eef1f7 0%, transparent 60%);
  --panel:         #ffffff;
  --panel-2:       #f9fafb;
  --panel-3:       #f2f4f7;
  --border:        #e4e8ed;
  --border-strong: #cdd5df;
  --text:          #151b23;
  --text-dim:      #57636f;
  --text-mute:     #68717f;
  --accent:        hsl(243 62% 55%);
  --accent-soft:   hsl(243 62% 55% / .10);
  --accent-fg:     #ffffff;
  --danger:        hsl(0 72% 48%);

  --shadow-1: 0 1px 2px rgb(16 24 40 / .05), 0 1px 3px rgb(16 24 40 / .04);
  --shadow-2: 0 10px 30px -12px rgb(16 24 40 / .22), 0 2px 6px rgb(16 24 40 / .05);
  --ring: 0 0 0 3px hsl(243 62% 55% / .20);

  --r-sm: 5px;  --r-md: 8px;  --r-lg: 12px;  --r-xl: 16px;
  --sidebar-w: 244px;
  --topbar-h: 52px;

  /* Hue-coloured text sits on a 12% tint of its own hue, which lands at
     3.4–4.5:1 in light mode — under the bar for 12.5px. Only the letters take a
     darker ink; the tint, the dots and the accent bars keep the hue as it is. */
  --ink: color-mix(in srgb, hsl(var(--h, var(--c-slate))) 86%, #000);

  --sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
}

:root[data-theme="dark"], :root.dark { color-scheme: dark; }

@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) { color-scheme: dark; } }

:root[data-theme="dark"],
:root:not([data-theme="light"]) {
  --dark-tokens: 1;
}

/* Dark palette — applied for explicit dark and for system-dark. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --c-slate:  214 14% 62%;
    --c-red:    0 78% 66%;
    --c-orange: 24 92% 62%;
    --c-amber:  40 92% 58%;
    --c-green:  148 52% 52%;
    --c-teal:   174 52% 50%;
    --c-cyan:   192 76% 55%;
    --c-blue:   214 92% 68%;
    --c-indigo: 245 88% 74%;
    --c-violet: 266 82% 72%;
    --c-pink:   332 78% 68%;

    --bg:            #0d1117;
    --bg-grad:       radial-gradient(1100px 560px at 72% -12%, #16202e 0%, transparent 62%);
    --panel:         #151b24;
    --panel-2:       #1a212c;
    --panel-3:       #202836;
    --border:        #262f3c;
    --border-strong: #3a465a;
    --text:          #e7eef7;
    --text-dim:      #9dacc0;
    --text-mute:     #7b8ba1;
    --accent:        hsl(245 88% 74%);
    --accent-soft:   hsl(245 88% 74% / .10);
    --accent-fg:     #10131c;
    --danger:        hsl(0 78% 66%);

    --shadow-1: 0 1px 2px rgb(0 0 0 / .40);
    --shadow-2: 0 14px 34px -14px rgb(0 0 0 / .70), 0 2px 8px rgb(0 0 0 / .35);
    --ring: 0 0 0 3px hsl(245 88% 74% / .26);
    --ink: hsl(var(--h, var(--c-slate)));   /* dark tints clear AA unaided */
  }
}

:root[data-theme="dark"] {
  --c-slate:  214 14% 62%;
  --c-red:    0 78% 66%;
  --c-orange: 24 92% 62%;
  --c-amber:  40 92% 58%;
  --c-green:  148 52% 52%;
  --c-teal:   174 52% 50%;
  --c-cyan:   192 76% 55%;
  --c-blue:   214 92% 68%;
  --c-indigo: 245 88% 74%;
  --c-violet: 266 82% 72%;
  --c-pink:   332 78% 68%;

  --bg:            #0d1117;
  --bg-grad:       radial-gradient(1100px 560px at 72% -12%, #16202e 0%, transparent 62%);
  --panel:         #151b24;
  --panel-2:       #1a212c;
  --panel-3:       #202836;
  --border:        #262f3c;
  --border-strong: #3a465a;
  --text:          #e7eef7;
  --text-dim:      #9dacc0;
  --text-mute:     #7b8ba1;
  --accent:        hsl(245 88% 74%);
  --accent-soft:   hsl(245 88% 74% / .10);
  --accent-fg:     #10131c;
  --danger:        hsl(0 78% 66%);

  --shadow-1: 0 1px 2px rgb(0 0 0 / .40);
  --shadow-2: 0 14px 34px -14px rgb(0 0 0 / .70), 0 2px 8px rgb(0 0 0 / .35);
  --ring: 0 0 0 3px hsl(245 88% 74% / .26);
  --ink: hsl(var(--h, var(--c-slate)));   /* dark tints clear AA unaided */
}

body {
  font-family: var(--sans);
  background: var(--bg);
  background-image: var(--bg-grad);
  background-attachment: fixed;
  color: var(--text);
  font-size: 15px;
  line-height: 1.55;
}

::selection { background: var(--accent-soft); }

/* Scrollbars, tuned so they don't shout in dark mode. */
* { scrollbar-width: thin; scrollbar-color: var(--border-strong) transparent; }
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 99px; border: 3px solid transparent; background-clip: content-box; }
*::-webkit-scrollbar-track { background: transparent; }

.muted { color: var(--text-dim); }
.dim   { color: var(--text-mute); }
.mono  { font-family: var(--mono); }
.nowrap { white-space: nowrap; }
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.grow  { flex: 1 1 auto; min-width: 0; }
.row   { display: flex; align-items: center; gap: 8px; }
.spacer { flex: 1 1 auto; }
.sr {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ------------------------------------------------------------------ layout */

.app {
  display: grid;
  grid-template-columns: var(--sidebar-w) minmax(0, 1fr);
  grid-template-rows: var(--topbar-h) minmax(0, 1fr);
  grid-template-areas: "brand top" "side main";
  height: 100dvh;
}

.brandcell {
  grid-area: brand;
  display: flex; align-items: center; gap: 9px;
  padding: 0 14px;
  border-right: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  background: var(--panel);
}

.topbar {
  grid-area: top;
  display: flex; align-items: center; gap: 10px;
  padding: 0 14px;
  border-bottom: 1px solid var(--border);
  background: var(--panel);
  min-width: 0;
}

.sidebar {
  grid-area: side;
  border-right: 1px solid var(--border);
  background: var(--panel);
  /* `overflow-y: auto` alone computes `overflow-x` to `auto` as well, which is
     not "visible": the workspace switcher's popover is a child of this element
     and could not escape it. Opening it pushed `scrollWidth` past the column,
     raised a horizontal scrollbar under the nav, and clipped the panel's right
     edge. `clip` keeps the overflow contained without making a scroll container
     of the other axis. */
  overflow-y: auto;
  overflow-x: clip;
  padding: 12px 10px 32px;
}

.main {
  grid-area: main;
  overflow-y: auto;
  scroll-behavior: smooth;
}

.brand { display: flex; align-items: center; gap: 9px; font-weight: 650; letter-spacing: -.01em; }
.brandmark {
  width: 26px; height: 26px; border-radius: 8px;
  display: grid; place-items: center;
  background: linear-gradient(145deg, hsl(var(--c-indigo)), hsl(var(--c-violet)));
  color: #fff; font-size: 15px; box-shadow: var(--shadow-1);
}

/* ----------------------------------------------------------------- sidebar */

/* The switcher sits above everything it reframes. Full width, because the
   counts, the projects, the tags and the search box below it all mean
   something different depending on it. */
.wsmenu { display: block; margin: 0 0 14px; }
.wsmenu > summary { list-style: none; }
.wsmenu > summary::-webkit-details-marker { display: none; }
.wschip {
  display: flex; align-items: center; gap: 9px;
  padding: 7px 9px; border-radius: var(--r-md);
  border: 1px solid var(--border); background: var(--panel-2);
  font-size: 13.5px; font-weight: 600; cursor: pointer;
  transition: background .1s, border-color .1s;
}
.wschip:hover { background: var(--panel-3); }
.wsmenu[open] .wschip { border-color: var(--accent); }
.wsmark {
  width: 22px; height: 22px; border-radius: 6px; flex: none;
  display: inline-grid; place-items: center; color: #fff; vertical-align: -5px;
  background: linear-gradient(145deg, hsl(var(--c-indigo)), hsl(var(--c-blue)));
}
.wsmark[data-kind="personal"] {
  background: linear-gradient(145deg, hsl(var(--c-teal)), hsl(var(--c-green)));
}
/* `min-width: 0` overrides `.menupanel`'s 208px floor: the panel is as wide as
   the sidebar's content box and no wider, so it cannot push the column's
   scrollWidth past its own width. Without it a panel that would not fit was
   both clipped on its right edge and the cause of a horizontal scrollbar under
   the whole nav. */
.wsmenu .menupanel { width: 100%; min-width: 0; }
.wsitem { gap: 9px; }
.wsitem.sel { font-weight: 600; }
/* Its own class, not `:last-child` — the workspace's mark carries an icon too,
   and on every row but the current one that icon *is* the last one. */
.wshere { display: inline-flex; margin-left: auto; color: var(--accent); }

.navgroup { margin-bottom: 14px; }
.navlabel {
  display: flex; align-items: center; justify-content: space-between;
  padding: 6px 10px 4px;
  font-size: 12.5px; font-weight: 650; color: var(--text-mute);
}
.navlabel a { color: var(--text-mute); font-size: 16px; line-height: 1; padding: 0 2px; border-radius: 4px; }
.navlabel a:hover { color: var(--accent); background: var(--accent-soft); }

/* The label doubles as the group's switch: the whole word is the hit area, not
   just the chevron beside it. */
.navlabel-btn {
  display: flex; align-items: center; gap: 5px;
  margin: -2px -4px; padding: 2px 4px;
  border-radius: 5px; color: inherit; font: inherit; font-weight: 650;
}
.navlabel-btn:hover { color: var(--text); background: var(--panel-3); }
.navlabel-btn .chev { display: flex; opacity: .7; transition: transform .14s ease; }

/* Which groups are shut is written on <html> before the first paint, so a
   collapsed sidebar never unfolds and snaps back — and survives the htmx swap
   that replaces the sidebar, which carries no state of its own. */
:root[data-navclosed~="saved"]    .navgroup[data-group="saved"]    > .navlist,
:root[data-navclosed~="projects"] .navgroup[data-group="projects"] > .navlist,
:root[data-navclosed~="tags"]     .navgroup[data-group="tags"]     > .navlist { display: none; }

:root[data-navclosed~="saved"]    .navgroup[data-group="saved"]    .chev,
:root[data-navclosed~="projects"] .navgroup[data-group="projects"] .chev,
:root[data-navclosed~="tags"]     .navgroup[data-group="tags"]     .chev { transform: rotate(-90deg); }

.navitem {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 11px;
  border-radius: var(--r-md);
  color: var(--text-dim);
  font-weight: 500;
  line-height: 1.35;
}
.navitem:hover { background: var(--panel-3); color: var(--text); }
.navitem.active { background: var(--accent-soft); color: var(--accent); font-weight: 600; }
.navitem .ico { width: 16px; text-align: center; opacity: .85; flex: none; font-size: 14px; }
.navitem .count {
  margin-left: auto; font-size: 12px; font-variant-numeric: tabular-nums;
  color: var(--text-dim); background: var(--panel-3);
  padding: 1px 6px; border-radius: 99px; min-width: 20px; text-align: center;
}
.navitem.active .count { background: hsl(243 62% 55% / .16); color: var(--accent); }
.navitem .count.hot { --h: var(--c-red); color: var(--ink); background: hsl(var(--c-red) / .12); }
.navitem .swatch { width: 8px; height: 8px; border-radius: 3px; flex: none; background: hsl(var(--h, var(--c-slate))); }

/* ------------------------------------------------- form controls (base) */
/* Defined before the components so component rules always win the cascade. */

input[type="text"], input[type="date"], input[type="time"], input[type="number"],
input[type="search"], input[type="email"], input[type="url"], input[type="password"], select, textarea {
  width: 100%; padding: 7px 10px; min-height: 36px;
  background: var(--panel-2); border: 1px solid var(--border);
  border-radius: var(--r-sm); outline: none; color: var(--text);
}
input:focus, select:focus, textarea:focus { border-color: var(--accent); box-shadow: var(--ring); background: var(--panel); }
input::placeholder, textarea::placeholder { color: var(--text-mute); }
textarea { resize: vertical; min-height: 96px; padding: 10px 12px; font-family: inherit; line-height: 1.6; }
select { cursor: pointer; }

/* ------------------------------------------------------------------ topbar */

.searchbox { position: relative; flex: 1 1 460px; max-width: 560px; min-width: 0; }
.searchbox .mag { position: absolute; left: 10px; top: 50%; transform: translateY(-50%); color: var(--text-mute); pointer-events: none; }
.searchbox input {
  width: 100%; padding: 7px 30px 7px 31px;
  background: var(--panel-2); border: 1px solid var(--border);
  border-radius: var(--r-md); outline: none;
}
.searchbox input:focus { border-color: var(--accent); box-shadow: var(--ring); background: var(--panel); }
.searchbox kbd {
  position: absolute; right: 8px; top: 50%; transform: translateY(-50%);
  font-family: var(--mono); font-size: 11.5px; color: var(--text-mute);
  border: 1px solid var(--border); border-radius: 4px; padding: 1px 5px; background: var(--panel);
}
.searchbox input:focus + kbd, .searchbox input:not(:placeholder-shown) + kbd { display: none; }

.avatar {
  width: 26px; height: 26px; border-radius: 50%; flex: none;
  background: linear-gradient(145deg, hsl(var(--c-teal)), hsl(var(--c-blue)));
  color: #fff; display: grid; place-items: center; font-size: 12px; font-weight: 650;
  overflow: hidden;
}
.avatar img { width: 100%; height: 100%; object-fit: cover; }
.avatar.sm { width: 21px; height: 21px; font-size: 10.5px; }
/* Nobody. Said as an outline rather than left blank, so an empty cell reads as
   a question rather than as a rendering fault. */
.avatar.ghost {
  background: none; border: 1px dashed var(--border-strong);
  color: var(--text-dim);
}

.person { display: inline-flex; align-items: center; gap: 7px; min-width: 0; font-size: 13px; }
.person .avatar { width: 21px; height: 21px; font-size: 10.5px; }
.person.dim { color: var(--text-dim); }
.wl-who { display: flex; justify-content: center; }

/* Several people in the width of one, the way a shared thing is usually shown:
   overlapped, in a fixed order, with the names in the titles. Five names spelled
   out would push everything else off the row. */
.facepile { display: flex; align-items: center; padding-left: 3px; }
.facepile > * { margin-left: -6px; }
.facepile .avatar { box-shadow: 0 0 0 2px var(--panel); }
.facepile .avatar.more {
  background: var(--panel-3); color: var(--text-mute);
  font-size: 10px; font-weight: 600;
}

/* One team per row, like one project per row on the Projects page. */
.teamrow {
  display: grid; align-items: center; gap: 12px;
  grid-template-columns: auto minmax(0, 1fr) auto auto max-content;
  padding: 10px 16px;
}
.teamrow + .teamrow { border-top: 1px solid var(--border); }
.teamrow:hover { background: var(--panel-2); }
.tr-name { font-weight: 600; color: var(--text); }
.tr-name:hover { color: var(--accent); }

/* One person per row. A grid rather than a flex line, so the role control and
   the button sit in columns down the panel instead of wherever the name
   happens to end. */
.personrow {
  display: grid; align-items: center; gap: 12px;
  grid-template-columns: minmax(0, 1fr) 118px 96px;
  padding: 9px 16px; min-height: 52px;
}
/* Who this is: avatar, name, address — one group, read left to right. */
.pr-who { display: flex; align-items: center; gap: 9px; min-width: 0; }
.pr-who > .person { flex: 0 1 auto; }
.pr-you { font-size: 13px; color: var(--text-dim); flex: none; margin-left: -3px; }
.personrow + .personrow { border-top: 1px solid var(--border); }
.personrow:hover { background: var(--panel-2); }
.personrow .pr-mail { font-size: 13px; color: var(--text-mute); }
.personrow .pr-role select { width: 100%; }
.personrow .pr-act { justify-content: flex-end; }
.personrow .pr-role form { display: block; }
/* Nobody has accepted yet, so the row is quieter than the people above it. */
.personrow.pending .person { color: var(--text-dim); }
/* A heading *inside* a panel: the invitations belong with the people, but they
   are not people yet. */
.subhead {
  display: flex; align-items: center; gap: 7px;
  padding: 9px 16px; border-top: 1px solid var(--border);
  background: var(--panel-2);
  font-size: 12.5px; font-weight: 650; color: var(--text-mute);
}
.subhead .ico-svg { opacity: .8; }
.subhead .n { font-weight: 500; }

/* ----------------------------------------------------------------- buttons */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  padding: 8px 14px; border-radius: var(--r-md); min-height: 36px;
  border: 1px solid var(--border-strong);
  background: var(--panel); color: var(--text);
  font-weight: 550; font-size: 14px; white-space: nowrap;
  box-shadow: var(--shadow-1);
  transition: background .12s, border-color .12s, transform .06s;
}
.btn:hover { background: var(--panel-3); }
.btn:active { transform: translateY(.5px); }
.btn:focus-visible { outline: none; box-shadow: var(--ring); }
.btn.primary { background: var(--accent); border-color: var(--accent); color: var(--accent-fg); }
.btn.primary:hover { filter: brightness(1.07); }
.btn.ghost { background: transparent; border-color: transparent; box-shadow: none; color: var(--text-dim); }
.btn.ghost:hover { background: var(--panel-3); color: var(--text); }
.btn.danger { color: var(--danger); border-color: hsl(var(--c-red) / .35); background: hsl(var(--c-red) / .06); }
.btn.danger:hover { background: hsl(var(--c-red) / .13); }
.btn.sm { padding: 5px 11px; min-height: 30px; font-size: 13.5px; }
.btn.wide { width: 100%; }
.btn[disabled] { opacity: .5; pointer-events: none; }

.iconbtn {
  width: 34px; height: 34px; border-radius: var(--r-md);
  display: grid; place-items: center; color: var(--text-dim); flex: none;
}
.iconbtn:hover { background: var(--panel-3); color: var(--text); }
.iconbtn.on { color: hsl(var(--c-amber)); background: hsl(var(--c-amber) / .12); }

/* ------------------------------------------------------------------- chips */

.chip {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 10px; border-radius: 99px;
  font-size: 12.5px; font-weight: 600; line-height: 1.55;
  border: 1px solid transparent; white-space: nowrap;
  background: hsl(var(--h, var(--c-slate)) / .12);
  color: var(--ink);
  border-color: hsl(var(--h, var(--c-slate)) / .22);
}
.chip .dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex: none; }
.chip.sq { border-radius: var(--r-sm); }
.chip.plain { background: var(--panel-3); color: var(--text-dim); border-color: var(--border); }
a.chip:hover { filter: brightness(1.06); border-color: hsl(var(--h, var(--c-slate)) / .45); }

[data-color="slate"]  { --h: var(--c-slate); }
[data-color="red"]    { --h: var(--c-red); }
[data-color="orange"] { --h: var(--c-orange); }
[data-color="amber"]  { --h: var(--c-amber); }
[data-color="green"]  { --h: var(--c-green); }
[data-color="teal"]   { --h: var(--c-teal); }
[data-color="cyan"]   { --h: var(--c-cyan); }
[data-color="blue"]   { --h: var(--c-blue); }
[data-color="indigo"] { --h: var(--c-indigo); }
[data-color="violet"] { --h: var(--c-violet); }
[data-color="pink"]   { --h: var(--c-pink); }

[data-status="open"]        { --h: var(--c-blue); }
[data-status="in_progress"] { --h: var(--c-violet); }
[data-status="waiting"]     { --h: var(--c-amber); }
[data-status="scheduled"]   { --h: var(--c-teal); }
[data-status="closed"]      { --h: var(--c-green); }
[data-status="cancelled"]   { --h: var(--c-slate); }

[data-prio="urgent"] { --h: var(--c-red); }
[data-prio="high"]   { --h: var(--c-orange); }
[data-prio="normal"] { --h: var(--c-slate); }
[data-prio="low"]    { --h: var(--c-slate); }

.due { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; font-size: 13px; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.due.soon { color: hsl(var(--c-amber)); font-weight: 600; }
.due.over { color: hsl(var(--c-red)); font-weight: 650; }

/* --------------------------------------------------------------- work list */

.page { padding: 24px 28px 72px; max-width: 1500px; }
/* Settings-shaped pages: a column of panels reads better than a field of them. */
.page.narrow { max-width: 760px; }

/* Deleting a team takes everybody's work with it, so the control is folded
   away rather than sitting next to the ones that are reversible. */
.dangerzone > summary {
  display: inline-flex; align-items: center; gap: 6px;
  cursor: pointer; font-size: 13px; font-weight: 600; color: var(--danger);
  padding: 5px 0; list-style: none; user-select: none;
}
.dangerzone > summary::-webkit-details-marker { display: none; }
.dangerzone > summary .chev { display: inline-flex; transition: transform .12s; }
.dangerzone[open] > summary .chev { transform: rotate(90deg); }
.dz-body { margin-top: 8px; }

.pagehead { display: flex; align-items: flex-start; gap: 16px; margin-bottom: 18px; flex-wrap: wrap; }
.pagehead h1 { font-size: 21px; letter-spacing: -.015em; }
/* A heading that carries a mark is a row, not a word with a picture in it. */
.pagehead h1.withmark { display: flex; align-items: center; gap: 9px; }
.pagehead h1.withmark .wsmark { vertical-align: baseline; }
.pagehead .sub { color: var(--text-dim); font-size: 14px; margin-top: 4px; }

.filterbar {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 10px 12px; margin-bottom: 14px;
  background: var(--panel); border: 1px solid var(--border);
  border-radius: var(--r-lg);
}
.filterbar select, .filterbar input {
  width: auto; max-width: 210px;
  padding: 6px 10px; min-height: 34px; border-radius: var(--r-md);
  border: 1px solid var(--border); background: var(--panel-2); outline: none; font-size: 13.5px;
}
/* A control that is doing something looks like it: the default reading of this
   bar should be "nothing is filtered", at a glance. */
.filterbar select.set { border-color: hsl(var(--c-indigo) / .45); background: var(--accent-soft); color: var(--accent); font-weight: 600; }
.filterbar select:focus, .filterbar input:focus { border-color: var(--accent); box-shadow: var(--ring); }

.pcl { margin-bottom: 12px; }
.pcl > .ph .n { margin-left: 2px; }

.worklist {
  background: var(--panel); border: 1px solid var(--border);
  border-radius: var(--r-lg);
  /* Not `overflow: hidden` — that would clip the per-row status dropdown. */
}
.worklist > .wl-head { border-radius: var(--r-lg) var(--r-lg) 0 0; }
.worklist.is-empty > .wl-head { display: none; }
.worklist > .wl-row:last-child { border-radius: 0 0 var(--r-lg) var(--r-lg); }

.wl-head, .wl-row {
  display: grid;
  grid-template-columns: 28px 34px 56px minmax(220px, 1fr) auto auto 130px 122px 86px;
  align-items: center;
  gap: 12px;
  padding: 0 16px 0 0;
}
/* One more column in a team, immediately before the status: on a shared board
   "whose is this" is the question that follows "what is it", and a column can
   be read straight down. A personal desk never grows it, because there would
   only ever be one answer in it.
 *
 * It goes *after* the project and tag columns rather than before them because
 * those two are `auto`, and each row is its own grid — so anything to their
 * left is pushed about by whatever chips that row happens to carry, and a
 * labelled column that does not line up with its own heading is worse than no
 * heading at all. Everything from here to the right edge is fixed width. */
.worklist[data-team] > .wl-head,
.worklist[data-team] > .wl-row {
  grid-template-columns: 28px 34px 56px minmax(200px, 1fr) auto auto 34px 130px 122px 86px;
}
.wl-head {
  height: 36px; background: var(--panel-2); border-bottom: 1px solid var(--border);
  font-size: 12.5px; font-weight: 600; color: var(--text-mute);
}
.wl-head > * { padding: 0; }
.wl-head .h-id { padding-left: 0; }

.wl-row {
  position: relative;
  min-height: 56px;
  border-bottom: 1px solid var(--border);
  transition: background .1s;
}
.wl-row:last-child { border-bottom: 0; }
.wl-row:hover { background: var(--panel-2); }
.wl-row::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
  background: hsl(var(--h, var(--c-slate))); opacity: 0;
}
.wl-row[data-prio="urgent"]::before, .wl-row[data-prio="high"]::before { opacity: 1; }
.wl-row.done .wl-title { color: var(--text-mute); }
.wl-row.done .wl-title .t { text-decoration: line-through; text-decoration-color: var(--text-mute); }

/* The star is only interesting on the rows that have one, or the row you are
   pointing at. On every other row it is one more thing to look past. */
.wl-pin { display: grid; place-items: center; }
.wl-pin .iconbtn { width: 30px; height: 30px; opacity: 0; transition: opacity .12s; }
.wl-row:hover .wl-pin .iconbtn, .wl-pin .iconbtn.on, .wl-pin .iconbtn:focus-visible { opacity: 1; }
@media (hover: none) { .wl-pin .iconbtn { opacity: 1; } }
.wl-id { font-family: var(--mono); font-size: 12.5px; color: var(--text-mute); font-variant-numeric: tabular-nums; }
.wl-title { display: flex; flex-direction: column; gap: 3px; min-width: 0; padding: 9px 0; }
.wl-title .t { font-weight: 550; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wl-title .t:hover { color: var(--accent); }
.wl-meta { display: flex; align-items: center; gap: 11px; font-size: 13px; color: var(--text-mute); min-width: 0; }
.wl-meta .snip { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wl-badge { display: inline-flex; align-items: center; gap: 3px; flex: none; }
.wl-tags { display: flex; gap: 4px; flex-wrap: nowrap; overflow: hidden; }
.wl-updated { font-size: 12.5px; color: var(--text-mute); text-align: right; font-variant-numeric: tabular-nums; }

/* The row-wide link sits under the cells so their controls keep working, and the
   cells pass clicks through to it — otherwise everything but the twelve pixels
   between columns is a dead spot on a row that is asking to be clicked. */
.wl-row .rowlink { position: absolute; inset: 0; z-index: 0; }
.wl-row > * { position: relative; z-index: 1; pointer-events: none; }
/* `summary`, not `details`: the box is as wide as the cell while the chip inside
   it is not, and the difference would be another dead strip. */
.wl-row a, .wl-row button, .wl-row summary, .wl-row .menupanel, .wl-row .wl-badge, .wl-row .wl-pick { pointer-events: auto; }
.wl-row::before, .wl-row.sel::after { pointer-events: none; }
/* Each cell is its own stacking context, so a row with an open menu has to be
   lifted above the rows that come after it in the DOM. */
.wl-row:has(details.menu[open]) { z-index: 60; }
.wl-row > *:has(details.menu[open]) { z-index: 61; }

/* Ticking rows. The box is always there rather than shown on hover like the
   star: a control that exists only under the pointer is found by accident, and
   "can I do this to several at once" is a question people ask of a list the
   first day. Quiet at rest, so seventy of them do not shout; the row it is on
   tints, so a page of ticks can be read down the left edge. The whole cell is
   the label, which is a bigger target than a sixteen-pixel box. */
.wl-pick { display: grid; place-items: center; align-self: stretch; padding-left: 10px; cursor: pointer; }
.wl-pick input {
  width: 16px; height: 16px; margin: 0; cursor: pointer;
  accent-color: var(--accent); opacity: .55; transition: opacity .12s;
}
.wl-row:hover .wl-pick input, .wl-pick input:checked, .wl-pick input:focus-visible, .wl-head .wl-pick input { opacity: 1; }
.wl-row:has(.wl-pick input:checked) { background: var(--accent-soft); }

/* The bar of things to do with them. Hidden until something is ticked, by the
   stylesheet rather than a script, so it appears without one too; stuck to the
   bottom of the view rather than put above the list, where its appearing would
   have shoved the row under the pointer down by its own height — and where it
   would be off the screen from the fortieth row on. */
.bulkbar {
  position: sticky; bottom: 12px; z-index: 50;
  display: none; align-items: center; gap: 8px; flex-wrap: wrap;
  margin-top: 12px; padding: 8px 10px;
  background: var(--panel); border: 1px solid var(--border-strong);
  border-radius: var(--r-lg); box-shadow: var(--shadow-2);
}
#worklist:has(.wl-pick input:checked) .bulkbar { display: flex; }
/* A browser without `:has()` has nothing to reveal it with, so it is simply there. */
@supports not selector(:has(a)) { .bulkbar { display: flex; } }
.bulkbar .bulkn { font-weight: 600; font-size: 13.5px; white-space: nowrap; margin-right: 4px; }
.bulkbar select, .bulkbar input[type="text"] {
  width: auto; max-width: 170px; padding: 5px 9px; min-height: 32px;
  font-size: 13.5px; border-radius: var(--r-md);
}
.bulkbar input[type="text"] { width: 130px; }

.empty { padding: 54px 24px; text-align: center; color: var(--text-dim); }
.empty .big { display: flex; justify-content: center; margin-bottom: 10px; color: var(--text-mute); opacity: .55; }
.empty h3 { font-size: 16px; margin-bottom: 4px; color: var(--text); }

.pager { display: flex; align-items: center; justify-content: center; gap: 10px; padding: 14px; color: var(--text-dim); font-size: 13.5px; }

/* -------------------------------------------------------------- menus (details) */

.menu { position: relative; }
.menu > summary { list-style: none; cursor: pointer; display: inline-flex; }
.menu > summary::-webkit-details-marker { display: none; }
.menu > summary::marker { content: ""; }
.menupanel {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 60;
  min-width: 208px; padding: 5px;
  background: var(--panel); border: 1px solid var(--border);
  border-radius: var(--r-lg); box-shadow: var(--shadow-2);
  animation: pop .09s ease-out;
}
.menupanel.left { right: auto; left: 0; }
.menupanel.up { top: auto; bottom: calc(100% + 6px); }
@keyframes pop { from { opacity: 0; transform: translateY(-3px); } }
.menuitem {
  display: flex; align-items: center; gap: 9px; width: 100%;
  padding: 6px 9px; border-radius: var(--r-md);
  color: var(--text-dim); font-size: 14px; text-align: left;
}
.menuitem:hover { background: var(--panel-3); color: var(--text); }
.menuitem.sel { color: var(--accent); background: var(--accent-soft); font-weight: 600; }
.menuitem .hint { margin-left: auto; font-size: 12px; color: var(--text-mute); }
.menuhead { padding: 7px 10px 4px; font-size: 12.5px; font-weight: 650; color: var(--text-mute); }
.menuhead.plain { font-weight: 500; color: var(--text-dim); }
.menuhead.whoami { padding-bottom: 7px; }
.whoami-name { font-weight: 600; color: var(--text); }
.whoami-mail { font-weight: 500; color: var(--text-dim); }
.menuhead.whoami .whoami-mail { margin-top: 1px; }
.menusep { height: 1px; background: var(--border); margin: 5px 2px; }
.menufoot {
  padding: 6px 10px 2px; margin-top: 2px;
  font-size: 11.5px; color: var(--text-mute); font-variant-numeric: tabular-nums;
}

/* A setting that needs a control rather than a click. It reads like the items
   above it — same padding, same muted label — with the control on its own line,
   because a thirty-item select next to a label in a 208px panel is a sliver. */
.menurow { padding: 6px 9px 7px; }
.menurow-k {
  display: flex; align-items: center; gap: 9px;
  color: var(--text-dim); font-size: 14px; margin-bottom: 6px;
}
.menurow-k .qmark { margin-left: auto; }
.menurow select { min-height: 32px; padding: 5px 8px; font-size: 13.5px; }
/* The bubble hangs off the panel, and this panel is pinned to the right edge of
   the window — so it has to open leftwards or it opens straight off the screen. */
.menupanel .qmark .bubble { left: auto; right: 0; }

/* ---------------------------------------------------------- ticket detail */

.tdetail { display: grid; grid-template-columns: minmax(0, 1fr) 352px; gap: 18px; align-items: start; }

.thead { margin-bottom: 14px; }
.tcrumb { display: flex; align-items: center; gap: 7px; font-size: 13px; color: var(--text-mute); margin-bottom: 7px; flex-wrap: wrap; }
.tcrumb a:hover { color: var(--accent); }
.ttitle-input {
  font-size: 24px; font-weight: 600; letter-spacing: -.02em; width: 100%;
  border: 1px solid var(--border); background: var(--panel); border-radius: var(--r-md);
  padding: 5px 9px; outline: none;
}
.ttitle-input:focus { border-color: var(--accent); box-shadow: var(--ring); }
textarea.ttitle-input {
  min-height: 0; resize: none; overflow: hidden;
  line-height: 1.28; padding: 5px 9px;
}
.ttitle-input.flat { border-color: transparent; background: transparent; }
.ttitle-input.flat:hover { background: var(--panel-3); }
.ttitle-input.flat:focus { background: var(--panel); border-color: var(--accent); }

.statusbar {
  display: flex; align-items: center; gap: 5px; flex-wrap: wrap;
  padding: 8px; margin-bottom: 18px;
  background: var(--panel); border: 1px solid var(--border);
  border-radius: var(--r-lg);
}
.stbtn {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 11px; border-radius: var(--r-md);
  font-size: 13.5px; font-weight: 600; color: var(--text-dim);
  border: 1px solid transparent;
}
.stbtn:hover { background: var(--panel-3); color: var(--text); }
.stbtn.on {
  background: hsl(var(--h) / .13); color: var(--ink); border-color: hsl(var(--h) / .3);
}
.stbtn .dot { width: 7px; height: 7px; border-radius: 50%; background: hsl(var(--h)); opacity: .55; }
.stbtn.on .dot { opacity: 1; }

.panel {
  background: var(--panel); border: 1px solid var(--border);
  border-radius: var(--r-lg);
  margin-bottom: 18px;
}
.panel > .ph {
  display: flex; align-items: center; gap: 9px;
  padding: 12px 16px; border-bottom: 1px solid var(--border);
  font-size: 14px; font-weight: 650; color: var(--text);
}
.panel > .ph .ico-svg { color: var(--text-mute); }
.panel > .ph .n { color: var(--text-mute); font-weight: 500; font-size: 13px; }
.panel > .pb { padding: 16px; }
.panel.flush > .pb { padding: 0; }

/* Right-hand property rail */
.prop { display: grid; grid-template-columns: 104px minmax(0, 1fr); gap: 8px; align-items: center; padding: 7px 13px; }
.prop + .prop { border-top: 1px solid var(--border); }
.prop > .k {
  font-size: 12.5px; color: var(--text-mute); font-weight: 600;
  /* Room for a `?` beside the word, and something for its bubble to hang off.
     The keys are two words at most, and a key broken across two lines grows the
     whole row for nothing. */
  display: flex; align-items: center; gap: 5px; position: relative;
  white-space: nowrap;
}
.prop > .v { min-width: 0; font-size: 14px; }
.prop .stack { display: flex; flex-wrap: wrap; gap: 5px; align-items: center; }

.fl {
  display: flex; align-items: center; gap: 6px; margin-bottom: 6px;
  font-size: 13.5px; color: var(--text-dim); font-weight: 600;
}
.fieldgrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(178px, 1fr)); gap: 0 14px; }
.fieldgrid .span2 { grid-column: span 2; }
/* Positioned for the same reason `.dfield` is: a `?` beside a field's label
   hangs its bubble off the whole field, so the explanation opens below what it
   explains rather than across it. */
.field { margin-bottom: 11px; position: relative; }
/* Controls in a row share the space instead of each claiming 100% of it. */
.hstack { display: flex; gap: 7px; align-items: center; flex-wrap: wrap; }
.hstack > input, .hstack > select, .hstack > textarea { flex: 1 1 auto; width: auto; min-width: 0; }
.hstack > button, .hstack > .btn, .hstack > label { flex: none; }
input[type="date"] { min-width: 124px; }
.hstack > input[type="date"] { flex: 1 1 124px; }
.hstack > input[type="time"] { flex: 0 0 96px; }
.hstack > .colorpick { flex: none; }
.hstack > * { min-width: 0; }

/* ------------------------------------------------------------- markdown */

.md { line-height: 1.7; color: var(--text); overflow-wrap: break-word; }
.md > * + * { margin-top: .85em; }
.md h1 { font-size: 18px; } .md h2 { font-size: 16.5px; } .md h3 { font-size: 15px; }
.md h1, .md h2 { padding-bottom: .3em; border-bottom: 1px solid var(--border); }
.md a { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; text-decoration-thickness: 1px; }
.md ul, .md ol { padding-left: 1.35em; }
.md li + li { margin-top: .28em; }
.md li::marker { color: var(--text-mute); }
.md code {
  font-family: var(--mono); font-size: .875em;
  background: var(--panel-3); border: 1px solid var(--border);
  padding: .08em .38em; border-radius: 4px;
}
.md pre {
  background: var(--panel-3); border: 1px solid var(--border);
  padding: 11px 13px; border-radius: var(--r-md); overflow-x: auto;
}
.md pre code { background: none; border: 0; padding: 0; font-size: 13.5px; }
.md blockquote {
  border-left: 3px solid var(--border-strong); padding-left: 12px; color: var(--text-dim);
}
/* The grid is for a markdown table, which has no look of its own. A table
   in a rich-text note is either somebody's layout — an email signature's
   columns, which must not sprout borders — or one made here with the table
   tool, which carries `border="1"` and is drawn as the same flat grid. */
.md:not(.rich) table { border-collapse: collapse; width: 100%; display: block; overflow-x: auto; }
.md:not(.rich) th, .md:not(.rich) td { border: 1px solid var(--border); padding: 8px 12px; text-align: left; }
.md:not(.rich) th { background: var(--panel-2); font-weight: 650; }
.md.rich table { max-width: 100%; }
.md.rich table[border]:not([border="0"]) { border-collapse: collapse; }
.md.rich table[border]:not([border="0"]) :is(th, td) { border: 1px solid var(--border); padding: 6px 10px; }
.md.rich table[border]:not([border="0"]) th { background: var(--panel-2); font-weight: 650; text-align: left; }
.md hr { border: 0; border-top: 1px solid var(--border); }
/* An image in a note is usually a screenshot, and a screenshot is usually the
   point of the note — so it gets the full width of the thread. The height cap
   is what stops a tall phone screenshot pushing everything under it off the
   page; with both maxima set and no width or height of its own, the browser
   scales it to fit whichever it meets first and the proportions keep
   themselves. Clicking opens the file, where the browser's own zoom and save
   already are — `markdown::render` makes every image a link to itself, so that
   works with the script off too. The anchor must not draw a link's underline
   under the picture. */
.md img {
  border-radius: var(--r-md); border: 1px solid var(--border);
  max-height: 60vh; cursor: zoom-in;
  /* `height: auto` on purpose: a picture pasted with both its dimensions, or
     one dragged narrower in the box, keeps its proportions rather than being
     squashed to whatever height it arrived with. */
  height: auto;
}
.md a:has(> img) { display: inline-block; text-decoration: none; }
.md input[type="checkbox"] { width: auto; margin-right: .4em; }
.empty-body { color: var(--text-mute); font-style: italic; }

/* ------------------------------------------------------------- checklist */

.cl-item { display: flex; align-items: flex-start; gap: 9px; padding: 6px 13px; border-bottom: 1px solid var(--border); }
.cl-item:last-of-type { border-bottom: 0; }
.cl-item:hover { background: var(--panel-2); }
.cl-item .tick {
  width: 17px; height: 17px; border-radius: 5px; flex: none; margin-top: 2px;
  border: 1.5px solid var(--border-strong); display: grid; place-items: center;
  color: transparent; font-size: 12px; transition: all .12s;
}
.cl-item .tick:hover { border-color: var(--accent); }
.cl-item.done .tick { background: hsl(var(--c-green)); border-color: hsl(var(--c-green)); color: #fff; }
.cl-item .tick svg { width: 12px; height: 12px; stroke-width: 3; }
.cl-item.done .txt { color: var(--text-mute); text-decoration: line-through; }
.cl-item .txt { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
.cl-item .x { opacity: 0; color: var(--text-mute); font-size: 16px; line-height: 1; padding: 0 4px; }
.cl-item:hover .x { opacity: 1; }
.cl-item .x:hover { color: var(--danger); }

/* The checklist's add row keeps the card's own padding; the divider is dropped
   when it follows the header directly (an empty checklist) to avoid a 2px rule. */
.cl-add { padding: 10px 13px; border-top: 1px solid var(--border); }
.panel > .ph + .cl-add { border-top: 0; padding-top: 13px; }

.progressbar { height: 4px; border-radius: 99px; background: var(--panel-3); overflow: hidden; flex: 1 1 60px; max-width: 110px; }
.progressbar > i { display: block; height: 100%; background: hsl(var(--c-green)); border-radius: 99px; transition: width .25s; }

/* --------------------------------------------------- project / tag admin */

.adminrow {
  display: grid; align-items: center; gap: 10px;
  grid-template-columns: minmax(150px, 320px) auto auto auto max-content;
  justify-content: start;
  padding: 8px 13px;
}
.adminrow + .adminrow { border-top: 1px solid var(--border); }
.adminrow:hover { background: var(--panel-2); }
.adminrow .count { font-size: 13px; color: var(--text-mute); white-space: nowrap; min-width: 52px; }
.adminrow .arch { display: flex; align-items: center; gap: 5px; font-size: 13px; color: var(--text-dim); white-space: nowrap; }
.adminrow .arch input { width: auto; }

.colorpick { position: relative; display: inline-flex; }
.colorpick .sw {
  position: absolute; left: 9px; top: 50%; transform: translateY(-50%);
  width: 10px; height: 10px; border-radius: 3px; pointer-events: none;
  background: hsl(var(--h, var(--c-slate)));
}
.colorpick select { padding-left: 26px; min-width: 128px; }

/* ---------------------------------------------------------- conversation */
/* The middle of the ticket is a thread: the description opens it, notes follow,
   and the box you type in is the last thing in the card. */

.convo { margin-bottom: 0; }
.thread { padding: 2px 0 4px; }

.msg { display: flex; gap: 12px; padding: 12px 16px; }
.msg + .msg { border-top: 1px solid var(--border); }
.msg-avatar {
  width: 30px; height: 30px; border-radius: 50%; flex: none; margin-top: 1px;
  display: grid; place-items: center; font-size: 13px; font-weight: 650;
  background: linear-gradient(145deg, hsl(var(--c-teal)), hsl(var(--c-blue))); color: #fff;
  /* The circle is on the wrapper, so the picture has to be clipped to it —
     without this a square photograph sits inside a round frame. */
  overflow: hidden;
}
.msg-avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
.msg-avatar.op { background: linear-gradient(145deg, hsl(var(--c-indigo)), hsl(var(--c-violet))); }
.msg-main { flex: 1 1 auto; min-width: 0; }
.msg-head { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; min-height: 26px; }
.msg-head .who { font-weight: 650; }
.msg-actions { display: flex; gap: 2px; opacity: 0; transition: opacity .12s; }
.msg-actions .iconbtn { width: 26px; height: 26px; }
.msg:hover .msg-actions, .msg:focus-within .msg-actions { opacity: 1; }
/* Nothing hovers on a phone, so the actions can't hide there. */
@media (hover: none) { .msg-actions { opacity: 1; } }

/* No bubble: a note is just its text, set a shade larger than the interface
   around it because it is the thing you came to read. */
.msg .md { font-size: 15.5px; line-height: 1.72; }

/* The box you type in leads the thread, because the thread runs newest first. */
.composer {
  padding: 12px 16px; border-bottom: 1px solid var(--border);
  background: var(--panel-2);
}

/* ----------------------------------------------------------------- dates */
/* Four dates that are easy to confuse, so each gets room for a line of plain
   English and a couple of one-tap answers. */

/* The bubble hangs off the whole field rather than off its label row, so it
   opens *below* the date box and the Today / Tomorrow / Next week chips instead
   of on top of the very things it is describing. The `?` itself is far too
   small to anchor to: a bubble hung off an 18px mark opens leftwards into the
   edge of the panel. */
.dfield { position: relative; }
.dates .dfield + .dfield { margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--border); }

.chiprow { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.chipbtn {
  padding: 5px 11px; border-radius: 999px;
  border: 1px solid var(--border); background: var(--panel-2);
  color: var(--text-dim); font-size: 12.5px; font-weight: 600; white-space: nowrap;
}
.chipbtn:hover { border-color: var(--accent); color: var(--accent); background: var(--accent-soft); }

.switchrow { display: flex; align-items: flex-start; gap: 7px; position: relative; }
.switchrow > .qmark { margin-top: 1px; }
.switch {
  display: flex; align-items: flex-start; gap: 9px; text-align: left;
  font-size: 13.5px; line-height: 1.45; color: var(--text-dim);
}
.switch .box {
  width: 19px; height: 19px; border-radius: 5px; flex: none; margin-top: 0;
  border: 1.5px solid var(--border-strong); display: grid; place-items: center;
  color: transparent; transition: all .12s;
}
.switch:hover { color: var(--text); }
.switch:hover .box { border-color: var(--accent); }
.switch.on { color: var(--text); }
.switch.on .box, .switch input:checked + .box { background: hsl(var(--c-green)); border-color: hsl(var(--c-green)); color: #fff; }
.switch:has(input:checked) { color: var(--text); }
.switch input:focus-visible + .box { box-shadow: var(--ring); border-color: var(--accent); }
label.switch { cursor: pointer; }
.switch .box svg { width: 12px; height: 12px; stroke-width: 3; }

/* ------------------------------------------------------------- help bubble */
/* An explanation you have already read is clutter. Each one hides behind a
   question mark and comes back on hover or keyboard focus. */

.qmark {
  width: 18px; height: 18px; flex: none; border-radius: 50%;
  display: inline-grid; place-items: center;
  border: 1px solid var(--border-strong); background: var(--panel-2);
  color: var(--text-mute); font-size: 11.5px; font-weight: 700; line-height: 1;
  cursor: help; vertical-align: middle;
}
.qmark:hover, .qmark:focus-visible { border-color: var(--accent); color: var(--accent); background: var(--accent-soft); }
.qmark:focus-visible { outline: none; box-shadow: var(--ring); }

/* Anchored to the field rather than to the 18px question mark: a bubble hung off
   the mark itself opens leftwards into the edge of the panel, and `overflow:
   hidden` there cut four of the five down to an unreadable sliver. */
.qmark .bubble {
  position: absolute; z-index: 70; left: 0; top: calc(100% + 8px);
  width: max-content; max-width: 250px; padding: 9px 11px;
  background: var(--panel); border: 1px solid var(--border-strong);
  border-radius: var(--r-md); box-shadow: var(--shadow-2);
  color: var(--text-dim); font-size: 12.5px; font-weight: 400; line-height: 1.5;
  text-align: left; white-space: normal;
  opacity: 0; visibility: hidden; transform: translateY(-3px); transition: opacity .12s, transform .12s;
}
.qmark .bubble b { color: var(--text); font-weight: 650; }
.qmark:hover .bubble, .qmark:focus-visible .bubble, .qmark:focus-within .bubble {
  opacity: 1; visibility: visible; transform: none;
}

/* ------------------------------------------------------------- rail tabs */

.trail { position: relative; }
.railtabs {
  display: flex; gap: 4px; padding: 4px; margin-bottom: 14px;
  background: var(--panel); border: 1px solid var(--border);
  border-radius: var(--r-lg);
}
.railtabs label {
  flex: 1 1 0; min-width: 0; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding: 6px 8px; border-radius: var(--r-md);
  font-size: 13.5px; font-weight: 600; color: var(--text-dim); white-space: nowrap;
}
.railtabs label:hover { background: var(--panel-3); color: var(--text); }
.railtabs label .n {
  font-size: 12px; font-variant-numeric: tabular-nums; color: var(--text-dim);
  background: var(--panel-3); padding: 0 5px; border-radius: 99px;
}

/* One tab, one region. Six bordered cards stacked inside another bordered
   column was a box in a box in a box; the sections now share a single card and
   are told apart by their headings and a hairline. */
.tabpane { display: none; }
.tabpane {
  background: var(--panel); border: 1px solid var(--border);
  border-radius: var(--r-lg); overflow: hidden;
}
.tabpane > .panel { border: 0; border-radius: 0; margin: 0; background: none; }
.tabpane > .panel + .panel { border-top: 1px solid var(--border); }
.tabpane > .panel > .ph { border-bottom: 0; padding-bottom: 4px; }
.tabpane > .panel.flush > .ph { padding-bottom: 12px; border-bottom: 1px solid var(--border); }

#rt-info:checked ~ .tabpane[data-pane="info"],
#rt-files:checked ~ .tabpane[data-pane="files"],
#rt-activity:checked ~ .tabpane[data-pane="activity"] { display: block; }

#rt-info:checked ~ .railtabs label[for="rt-info"],
#rt-files:checked ~ .railtabs label[for="rt-files"],
#rt-activity:checked ~ .railtabs label[for="rt-activity"] {
  background: var(--accent-soft); color: var(--accent);
}
#rt-info:checked ~ .railtabs label[for="rt-info"] .n,
#rt-files:checked ~ .railtabs label[for="rt-files"] .n,
#rt-activity:checked ~ .railtabs label[for="rt-activity"] .n { color: var(--accent); }

#rt-info:focus-visible ~ .railtabs label[for="rt-info"],
#rt-files:focus-visible ~ .railtabs label[for="rt-files"],
#rt-activity:focus-visible ~ .railtabs label[for="rt-activity"] { box-shadow: var(--ring); }

/* --------------------------------------------------------- activity log */

.tl { padding: 4px 0; }
.tl-item { display: flex; gap: 11px; padding: 9px 13px; }
.tl-item .rail { display: flex; flex-direction: column; align-items: center; flex: none; }
.tl-item .bead {
  width: 22px; height: 22px; border-radius: 50%; flex: none;
  display: grid; place-items: center; font-size: 11.5px;
  background: var(--panel-3); color: var(--text-mute); border: 1px solid var(--border);
}
.tl-item .line { width: 1px; flex: 1 1 auto; background: var(--border); margin-top: 3px; min-height: 4px; }
.tl-item:last-child .line { display: none; }
.tl-body { flex: 1 1 auto; min-width: 0; padding-bottom: 4px; }
.tl-when { font-size: 12.5px; color: var(--text-mute); white-space: nowrap; }
.tl-event .tl-body { font-size: 13.5px; color: var(--text-dim); padding-top: 3px; }

/* ---- live sync: shared drafts, held-back refreshes, lost connection ---- */
.draftnote { display: flex; align-items: center; gap: 5px; margin: 6px 0 0;
             font-size: 12.5px; color: var(--text-mute); }
.draftnote[hidden] { display: none; }
textarea.locked { background: var(--panel-3); color: var(--text-dim); cursor: not-allowed; }

/* Shown in place of swapping a region the caret is sitting in. */
.updatedpill { position: sticky; bottom: 8px; display: block; margin: 8px auto 0;
               padding: 4px 11px; border: 1px solid var(--border-strong);
               border-radius: 999px; background: var(--panel); color: var(--text-dim);
               font: inherit; font-size: 12.5px; cursor: pointer; box-shadow: var(--shadow-1); }
.updatedpill:hover { color: var(--text); border-color: var(--accent); }

.connchip { display: inline-flex; align-items: center; gap: 5px; padding: 3px 9px;
            border: 1px solid var(--border); border-radius: 999px;
            background: var(--panel-2); color: hsl(var(--c-amber));
            font-size: 12.5px; white-space: nowrap; }
.connchip[hidden] { display: none; }
.composer textarea { background: var(--panel); min-height: 84px; font-size: 15.5px; }
/* `position` so the help bubble hanging off the row's question mark is placed
   against the row rather than against the page. */
.composer .actions { display: flex; align-items: center; gap: 8px; margin-top: 8px; position: relative; }

/* ------------------------------------------------------------ attachments */

.att-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(128px, 1fr)); gap: 9px; padding: 13px 13px 0; }
.att {
  border: 1px solid var(--border); border-radius: var(--r-md);
  overflow: hidden; background: var(--panel-2); position: relative;
}
.att:hover { border-color: var(--border-strong); }
.att .thumb { height: 82px; display: grid; place-items: center; background: var(--panel-3); font-size: 24px; color: var(--text-mute); overflow: hidden; }
.att .thumb img { width: 100%; height: 100%; object-fit: cover; }
.att .meta { padding: 6px 8px; font-size: 12.5px; }
.att .meta .fn { font-weight: 550; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.att .del { position: absolute; top: 5px; right: 5px; opacity: 0; background: var(--panel); border-radius: 50%; width: 22px; height: 22px; display: grid; place-items: center; box-shadow: var(--shadow-1); font-size: 14px; color: var(--text-dim); }
.att:hover .del { opacity: 1; }
.att .del:hover { color: var(--danger); }

.dropzone {
  display: block;
  margin: 13px; padding: 14px; text-align: center;
  border: 1.5px dashed var(--border-strong); border-radius: var(--r-md);
  color: var(--text-mute); font-size: 13.5px; cursor: pointer; transition: all .12s;
}
.dropzone:hover, .dropzone.over { border-color: var(--accent); color: var(--accent); background: var(--accent-soft); }
.dropzone input { display: none; }

/* ------------------------------------------------------------ dialogs */

dialog {
  margin: auto;
  border: 1px solid var(--border); border-radius: var(--r-xl);
  background: var(--panel); color: var(--text);
  box-shadow: var(--shadow-2); padding: 0; max-width: min(620px, calc(100vw - 32px)); width: 100%;
}
dialog::backdrop { background: rgb(10 14 20 / .48); backdrop-filter: blur(2px); }
dialog .dh { display: flex; align-items: center; gap: 10px; padding: 13px 16px; border-bottom: 1px solid var(--border); }
dialog .dh h2 { font-size: 15.5px; }
dialog .db { padding: 16px; }
dialog .df { display: flex; align-items: center; gap: 8px; padding: 12px 16px; border-top: 1px solid var(--border); background: var(--panel-2); border-radius: 0 0 var(--r-xl) var(--r-xl); }

.qa-input {
  width: 100%; font-size: 16px; padding: 9px 11px;
  border: 1px solid var(--border); border-radius: var(--r-md); background: var(--panel-2);
}
.qa-hint { margin-top: 9px; font-size: 13px; color: var(--text-mute); line-height: 1.75; }
.qa-hint code { font-family: var(--mono); background: var(--panel-3); border: 1px solid var(--border); padding: .5px 5px; border-radius: 4px; font-size: 12.5px; color: var(--text-dim); }

.kbdgrid { display: grid; grid-template-columns: auto 1fr; gap: 7px 14px; align-items: center; font-size: 14px; }
.kbdgrid kbd {
  font-family: var(--mono); font-size: 12px; border: 1px solid var(--border-strong);
  border-bottom-width: 2px; border-radius: 5px; padding: 2px 6px; background: var(--panel-2); white-space: nowrap;
}

/* ---------------------------------------------------------------- toast */

#toast {
  position: fixed; bottom: 18px; left: 50%; transform: translateX(-50%) translateY(12px);
  z-index: 200; padding: 9px 15px; border-radius: 99px;
  background: var(--text); color: var(--bg); font-size: 14px; font-weight: 550;
  box-shadow: var(--shadow-2); opacity: 0; pointer-events: none;
  transition: opacity .18s, transform .18s;
}
#toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }


/* ------------------------------------------------------------ login page */

.loginpage { display: grid; place-items: center; min-height: 100dvh; padding: 24px; }
.logincard {
  width: 100%; max-width: 380px; text-align: center;
  background: var(--panel); border: 1px solid var(--border);
  border-radius: var(--r-xl); box-shadow: var(--shadow-2); padding: 34px 30px;
}
.loginmark {
  width: 46px; height: 46px; border-radius: 14px; margin: 0 auto 16px;
  display: grid; place-items: center; font-size: 24px; color: #fff;
  background: linear-gradient(145deg, hsl(var(--c-indigo)), hsl(var(--c-violet)));
  box-shadow: var(--shadow-1);
}
.logincard h1 { font-size: 24px; margin-bottom: 7px; letter-spacing: -.02em; }
.logincard .muted { font-size: 14px; margin-bottom: 22px; }
.btn.google { width: 100%; padding: 9px; background: var(--panel); }
.or { display: flex; align-items: center; gap: 10px; margin: 14px 0; color: var(--text-mute); font-size: 12.5px; }
.or::before, .or::after { content: ""; flex: 1; height: 1px; background: var(--border); }
.fineprint { margin-top: 16px; font-size: 12.5px; color: var(--text-mute); line-height: 1.6; }
.fineprint code { font-family: var(--mono); background: var(--panel-3); padding: 1px 4px; border-radius: 4px; }

/* ---------------------------------------------------------- consent page */
/* Letting an app in: the sign-in card's shape, one decision on it. The head
   stays centred like the sign-in page; the choices read left to right. */

.logincard.consent { max-width: 420px; }
.consent form { text-align: left; }
.cs-block { padding: 14px 0; border-top: 1px solid var(--border); }
.cs-head {
  display: flex; align-items: center; gap: 6px; position: relative;
  font-size: 12.5px; font-weight: 650; color: var(--text-mute); margin-bottom: 8px;
}
.cs-spaces { border: 0; padding: 0; margin: 0; min-width: 0; display: grid; gap: 7px; }
.cs-opt { display: flex; align-items: flex-start; gap: 9px; font-size: 14px; cursor: pointer; }
.cs-opt input { margin-top: 3px; accent-color: var(--accent); flex: none; }
.cs-hint { display: block; font-size: 12.5px; color: var(--text-mute); }
/* "Only some" opens the list; with "All" chosen it is not there to fiddle with
   to no effect. */
.cs-only { display: none; gap: 7px; padding: 2px 0 0 25px; }
.cs-spaces:has(input[value="some"]:checked) .cs-only { display: grid; }
.cs-warn {
  display: flex; gap: 8px; align-items: flex-start; margin: 2px 0 14px;
  padding: 9px 11px; border-radius: var(--r-md); font-size: 13px; line-height: 1.45;
  background: hsl(var(--c-amber) / .10); border: 1px solid hsl(var(--c-amber) / .30); color: var(--text);
}
.cs-warn .ico-svg { color: hsl(var(--c-amber)); flex: none; margin-top: 2px; }
.cs-back { margin: 2px 0 14px; font-size: 13px; color: var(--text-dim); }
.cs-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }

/* ------------------------------------------------------- connections page */

#mcp-url { font-size: 13px; }
.howto { margin-top: 12px; }
.howto > summary {
  display: inline-flex; align-items: center; gap: 6px; cursor: pointer;
  font-size: 13.5px; font-weight: 600; color: var(--text-dim); list-style: none; user-select: none;
}
.howto > summary::-webkit-details-marker { display: none; }
.howto > summary .ico-svg { transition: transform .12s; }
.howto[open] > summary .ico-svg { transform: rotate(90deg); }
.howto > summary:hover { color: var(--text); }
.howto ol { margin: 8px 0 0; padding-left: 38px; font-size: 13.5px; line-height: 1.6; color: var(--text-dim); }
.howto ol b, .howto .fineprint b { color: var(--text); font-weight: 600; }
.howto .fineprint { margin-top: 6px; padding-left: 20px; }
pre.cmd {
  margin: 8px 0 0 20px; padding: 9px 11px; overflow-x: auto;
  background: var(--panel-3); border: 1px solid var(--border); border-radius: var(--r-sm);
  font-family: var(--mono); font-size: 12.5px; white-space: pre;
}
.grantrow {
  display: grid; align-items: center; gap: 12px;
  grid-template-columns: minmax(0, 1fr) auto; padding: 11px 16px;
}
.grantrow + .grantrow { border-top: 1px solid var(--border); }
.gr-name { font-weight: 600; display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.gr-host { font-weight: 400; font-size: 12.5px; color: var(--text-mute); }
.gr-meta {
  display: flex; align-items: center; flex-wrap: wrap; gap: 4px 10px;
  margin-top: 3px; font-size: 12.5px; color: var(--text-mute);
}

/* ------------------------------------------------------------ error page */

.errpage { display: grid; place-items: center; min-height: 100dvh; padding: 24px; }
.errbox { text-align: center; max-width: 400px; }
.errcode { font-size: 54px; font-weight: 700; color: var(--border-strong); line-height: 1; letter-spacing: -.03em; }
.errbox h1 { font-size: 21px; margin: 8px 0 6px; }
.errbox .muted { margin-bottom: 18px; }

/* Someone who has asked for less movement gets the layout, not the animation. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
  .main { scroll-behavior: auto; }
  html { scroll-behavior: auto; }
}

/* ------------------------------------------------------------ responsive */

@media (max-width: 1180px) {
  .tdetail { grid-template-columns: minmax(0, 1fr); }
  .convo { margin-bottom: 16px; }
}

@media (max-width: 900px) {
  .app { grid-template-columns: minmax(0, 1fr); grid-template-areas: "brand" "top" "main"; grid-template-rows: var(--topbar-h) var(--topbar-h) minmax(0, 1fr); }
  .brandcell { border-right: 0; justify-content: space-between; }
  .sidebar {
    position: fixed; inset: var(--topbar-h) auto 0 0; width: 262px; z-index: 90;
    transform: translateX(-100%); transition: transform .18s; box-shadow: var(--shadow-2);
  }
  body.nav-open .sidebar { transform: none; }
  body.nav-open::after { content: ""; position: fixed; inset: 0; background: rgb(10 14 20 / .4); z-index: 80; }
  .page { padding: 14px 13px 60px; }
  .ttitle-input { font-size: 18px; }
  .fieldgrid .span2 { grid-column: auto; }

  /* Every pixel of card width counts on a phone. */
  .msg { padding: 11px 12px; gap: 9px; }
  .msg-avatar { width: 26px; height: 26px; }
  .composer { padding: 11px 12px; }

  .wl-head { display: none; }
  /* The number keeps a column of its own rather than leaving with the other
     dropped ones. It is how a person says out loud which ticket they mean, and
     on a phone the only way to read it was to open the ticket. `auto` is as
     wide as `#4` or `#412` needs and no wider; the title keeps the rest. */
  /* The tick box keeps a narrow column of its own. Tucking it into the empty
     cell under the star cost nothing in width but made every row a line
     taller, and seventy rows of that is a great deal more thumb than the
     twenty-odd pixels this takes off a title. */
  .wl-row {
    grid-template-columns: 20px 26px auto minmax(0, 1fr) auto;
    grid-template-areas: "pick pin id title status" ".  .  .  meta  meta";
    row-gap: 3px; padding: 9px 12px 9px 0;
    column-gap: 8px;
  }
  .wl-pin { grid-area: pin; }
  .wl-pick { grid-area: pick; padding-left: 4px; }
  .wl-id { grid-area: id; font-size: 12px; }
  .wl-project, .wl-tags, .wl-updated { display: none; }
  /* The assignee keeps the company it kept on a wide screen — beside the
     status — rather than dropping into the meta line, where it would sit on
     top of the due date and leave an empty row on the tickets that have none. */
  .worklist[data-team] > .wl-row {
    grid-template-columns: 20px 26px auto minmax(0, 1fr) auto auto;
    grid-template-areas: "pick pin id title who status" ".  .  .  meta  meta meta";
  }
  .bulkbar { bottom: 8px; padding: 8px; }
  .bulkbar .spacer { display: none; }
  .worklist[data-team] > .wl-row .wl-who { grid-area: who; }
  .wl-title { grid-area: title; }
  .wl-status { grid-area: status; }
  .wl-due { grid-area: meta; justify-self: start; }

  /* The flexible gap only makes sense when the bar fits on one line. */
  .filterbar .spacer { display: none; }

  /* The bell's panel is pinned to the right of a very narrow window, so it is
     capped by the viewport rather than by its own content. */
  .menupanel.notifs { width: calc(100vw - 20px); }
  .nf-when { display: none; }

  /* Five fixed columns don't fit a phone; let the row wrap instead of clipping
     the Save and Delete buttons off the edge. */
  .adminrow { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 10px; }
  .adminrow > input[type="text"] { flex: 1 1 100%; max-width: none; }
  .adminrow .row { margin-left: auto; }

  /* Four fixed columns do not fit a phone either. The name leads, the rest
     wraps under it rather than being clipped off the edge. */
  .teamrow, .personrow {
    display: flex; flex-wrap: wrap; align-items: center; gap: 8px 10px;
  }
  .tr-name { flex: 1 1 auto; }
  .personrow > .pr-who { flex: 1 1 100%; flex-wrap: wrap; }
  .personrow .pr-mail { flex: 1 1 100%; margin-top: -4px; }
  .personrow .pr-role { min-width: 118px; }
  .personrow .pr-act, .teamrow .row { margin-left: auto; }
}

@media (min-width: 901px) { .navtoggle { display: none; } }

/* keyboard selection in the work list */
.wl-row.sel { background: var(--accent-soft); }
.wl-row.sel::after { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 2px; background: var(--accent); }

/* saved views: a row that reveals its remove control on hover */
.navrow { display: flex; align-items: center; }
.navrow .navitem { flex: 1 1 auto; min-width: 0; }
.navrow .delx { opacity: 0; color: var(--text-mute); padding: 0 7px; font-size: 16px; line-height: 1; border-radius: 4px; }
.navrow:hover .delx { opacity: 1; }
.navrow .delx:hover { color: var(--danger); background: hsl(var(--c-red) / .1); }
.ico-svg { display: inline-block; vertical-align: -0.15em; flex: none; }

/* ------------------------------------------------------- people, picked */
/* A `<select>` cannot hold a face, and on a shared board the answer to "whose
   is this" is a person. The control is therefore the same `<details>` menu the
   status and priority pickers use, dressed to read as a form field. */

.peoplepick { display: block; }
.peoplepick > summary { display: block; }
.peoplepick > .menupanel { width: 250px; min-width: 0; }
.peoplepick .menurow input { min-width: 0; }
.picked {
  display: flex; align-items: center; gap: 8px; width: 100%;
  min-height: 34px; padding: 4px 8px 4px 5px;
  border: 1px solid var(--border-strong); border-radius: var(--r-md);
  background: var(--panel); color: var(--text); font-size: 14px;
  cursor: pointer; transition: border-color .12s, background .12s;
}
.picked:hover { border-color: var(--accent); background: var(--panel-2); }
/* The control's own chevron, not the ghost avatar's icon inside it, which
   the descendant form of this rule pushed off-centre. */
.picked > .ico-svg:last-child { margin-left: auto; color: var(--text-mute); flex: none; }
.picked .truncate { min-width: 0; }
.picked.empty { color: var(--text-mute); }
.peoplepick > summary:focus-visible .picked {
  outline: none; border-color: var(--accent); box-shadow: var(--ring);
}
.menuitem.person-item { gap: 8px; padding: 5px 8px; }
.menuitem.person-item .hint { color: var(--text-mute); }
/* An outline where the face goes, so "nobody" reads as an answer rather than
   as a picture that failed to load. */
.avatar.ghost.sm { width: 21px; height: 21px; }

/* The badge that says who a waiting ticket is with. It carries a face when
   that somebody is a colleague, so the row is legible without reading it. */
.wl-badge.who { padding-left: 3px; gap: 5px; }
.wl-badge.who .avatar { width: 17px; height: 17px; font-size: 9.5px; }

/* --------------------------------------------------------------- mentions */
/* Somebody's name inside a note. A chip rather than a plain link: it is a
   person, not a destination, and it has to be spottable while skimming. */

/* The same chip in both places it appears — in a posted note, and in the box
   the note is being written in. A mention that changed shape between the two
   would make the box a worse promise about what is being sent. */
.md .mention, .editor .mention {
  display: inline-block; padding: 0 5px; border-radius: 5px;
  background: var(--accent-soft); color: var(--accent);
  font-weight: 600; font-size: .93em; line-height: 1.5;
  text-decoration: none;
}
.md .mention:hover { background: var(--accent); color: var(--accent-fg); }

/* ---------------------------------------------------------------- the editor */
/* The box a note is written in is the note: it carries the same `.md.rich`
   typography the posted note is drawn with, so what it shows is what is
   posted. It stands in for the textarea the server rendered — which is still
   in the form and still what gets posted — so it has to look like one: same
   border, same padding, same focus ring. */

.editor {
  position: relative;
  width: 100%; padding: 10px 12px; min-height: 96px;
  background: var(--panel-2); border: 1px solid var(--border);
  border-radius: var(--r-sm); outline: none; color: var(--text);
  overflow-wrap: break-word;
}
.editor:focus { border-color: var(--accent); box-shadow: var(--ring); background: var(--panel); }
.editor.over { border-color: var(--accent); box-shadow: var(--ring); }
/* A blank box holds one blank paragraph for the caret, so `:empty` never
   matches; the script says when there is nothing in it. `blank` rather than
   `empty`, which is the empty-state panel's class: on the box it centred the
   caret and dimmed the text. */
.editor.blank::before {
  content: attr(data-placeholder); position: absolute; left: 12px; right: 12px; top: 10px;
  color: var(--text-mute); pointer-events: none;
}
.editor.locked { background: var(--panel-3); color: var(--text-dim); cursor: not-allowed; }
.composer .editor { background: var(--panel); min-height: 84px; font-size: 15.5px; line-height: 1.72; }
.composer .editor:focus { border-color: var(--accent); }

/* A picture in the box is clicked rather than opened. */
.editor img { cursor: default; }
.editor img.ed-selected { outline: 2px solid var(--accent); outline-offset: -1px; }
.editor img[data-pending] { opacity: .6; }
.editor .mention { cursor: default; }
.editor a { cursor: text; }

/* The row of tools: a bar along the bottom of the box, where every editor
   anyone has used keeps it, and where it never has to fight the buttons for
   room. Twenty-eight pixels a side — large enough to hit, small enough that
   eleven of them read as one quiet strip rather than a ribbon. */
.edrow { flex-wrap: wrap; }
.edtools {
  display: flex; flex-wrap: wrap; align-items: center; gap: 1px;
  padding: 3px 6px; margin-top: -1px;
  background: var(--panel-2); border: 1px solid var(--border);
  border-radius: 0 0 var(--r-sm) var(--r-sm);
}
.mentionwrap:has(.edtools) .editor { border-bottom-left-radius: 0; border-bottom-right-radius: 0; }
.editor.locked ~ .edtools { opacity: .5; pointer-events: none; }
.edtool {
  width: 28px; height: 28px; border-radius: 6px;
  display: grid; place-items: center; color: var(--text-dim);
}
.edtool:hover { background: var(--panel-3); color: var(--text); }
.edtool[aria-pressed="true"] { background: var(--accent-soft); color: var(--accent); }
.edtool:focus-visible { outline: none; box-shadow: var(--ring); }
.edsep { width: 1px; height: 16px; background: var(--border); margin: 0 4px; flex: none; }

/* The link tool's row: it opens inside the bar, under the tools. */
.edlink { flex: 1 1 100%; display: flex; gap: 6px; align-items: center; padding: 4px 2px 3px; }
.edlink input { flex: 1 1 auto; min-width: 0; min-height: 32px; padding: 5px 9px; font-size: 13.5px; }

/* The corners a clicked picture grows. The frame takes no pointer events, so
   the picture under it can still be clicked; only the handles do. */
.edimg {
  position: absolute; z-index: 5; pointer-events: none;
  border: 1.5px solid var(--accent); border-radius: var(--r-md);
}
.edimg .h {
  position: absolute; width: 11px; height: 11px; pointer-events: auto; touch-action: none;
  background: var(--panel); border: 1.5px solid var(--accent); border-radius: 3px;
}
.edimg .h.nw { left: -6px; top: -6px; cursor: nwse-resize; }
.edimg .h.ne { right: -6px; top: -6px; cursor: nesw-resize; }
.edimg .h.sw { left: -6px; bottom: -6px; cursor: nesw-resize; }
.edimg .h.se { right: -6px; bottom: -6px; cursor: nwse-resize; }
.edimg .size {
  position: absolute; right: 6px; bottom: 6px; padding: 1px 7px; border-radius: 99px;
  background: var(--text); color: var(--bg); font-size: 11px; font-variant-numeric: tabular-nums;
  opacity: 0; transition: opacity .12s;
}
.edimg.resizing .size { opacity: 1; }

/* The list that opens under a composer once you type `@`. Anchored to the box
   rather than to the caret: a caret-tracked popup is a lot of arithmetic for a
   list that is never more than a handful of names long. */
.mentionwrap { position: relative; }
.mentionlist {
  position: absolute; z-index: 70; left: 0; right: 0; top: 100%;
  margin-top: 4px; padding: 4px; max-height: 232px; overflow-y: auto;
  background: var(--panel); border: 1px solid var(--border-strong);
  border-radius: var(--r-lg); box-shadow: var(--shadow-2);
  animation: pop .09s ease-out;
}
.mentionlist[hidden] { display: none; }
.mentionlist button {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 5px 8px; border-radius: var(--r-md);
  font-size: 14px; color: var(--text-dim); text-align: left;
}
.mentionlist button .handle { color: var(--text-mute); font-size: 12.5px; }
.mentionlist button.on, .mentionlist button:hover { background: var(--accent-soft); color: var(--accent); }

/* ---------------------------------------------------------------- the bell */
/* What other people did that you are part of. It reads across every workspace,
   because otherwise you would have to go and stand in a team to discover you
   had been tagged in it. */

#notifbell { flex: none; }
.topbar .iconbtn.has { color: var(--text); }
.ndot {
  position: absolute; top: -3px; right: -4px; min-width: 16px; height: 16px;
  padding: 0 4px; border-radius: 99px;
  background: var(--danger); color: #fff;
  font-size: 10.5px; font-weight: 700; line-height: 16px; text-align: center;
  box-shadow: 0 0 0 2px var(--panel);
}
#notifbell .iconbtn { position: relative; overflow: visible; }

.menupanel.notifs { width: 366px; max-width: calc(100vw - 24px); padding: 5px; }
.nf-head { display: flex; align-items: center; gap: 8px; }
.linky {
  font-size: 12.5px; font-weight: 600; color: var(--accent);
  padding: 2px 4px; border-radius: 5px;
}
.linky:hover { background: var(--accent-soft); }
.nf-none {
  margin: 0; padding: 10px 10px 14px;
  font-size: 13px; color: var(--text-mute); line-height: 1.55;
}

.notif {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 9px;
  align-items: start; padding: 8px; border-radius: var(--r-md);
  color: var(--text-dim);
}
.notif:hover { background: var(--panel-3); }
/* Unread carries the accent on its left edge rather than a wash across the
   row: the rows are the same shape either way, so the eye finds the new ones
   by a single vertical line instead of re-reading all of them. */
.notif.unread { background: var(--accent-soft); box-shadow: inset 2px 0 0 var(--accent); }
.notif.unread .nf-line { color: var(--text); font-weight: 600; }

.nf-face { position: relative; flex: none; }
.nf-kind {
  position: absolute; right: -3px; bottom: -3px;
  width: 15px; height: 15px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--panel-3); color: var(--text-dim);
  box-shadow: 0 0 0 1.5px var(--panel);
}
.notif.unread .nf-kind { background: var(--accent); color: var(--accent-fg); box-shadow: 0 0 0 1.5px var(--accent-soft); }
.nf-main { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.nf-line { font-size: 13.5px; line-height: 1.4; }
.nf-sub {
  display: flex; align-items: center; gap: 5px; min-width: 0;
  font-size: 12.5px; color: var(--text-mute);
}
.nf-sub .mono { flex: none; }
.nf-where {
  flex: none; padding: 0 6px; border-radius: 99px;
  background: var(--panel-3); font-size: 11px; font-weight: 600;
}
.nf-when { font-size: 12px; color: var(--text-mute); white-space: nowrap; padding-top: 1px; }

/* The full list is the same row with room around it — and a hairline, because
   forty of them stacked with nothing between is a wall of text. */
/* The bell's one setting — whether it is also sent by email — at the head of
   its page. A sentence stating what happens now, and a link to the other. */
.mailpref { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin-top: 10px; font-size: 13.5px; color: var(--text-dim); }
.mailpref > .ico-svg { color: var(--text-mute); }
.mailpref.on > .ico-svg { color: hsl(var(--c-green)); }
.mailpref b { font-weight: 600; color: var(--text); }
.mailpref form { display: contents; }

/* A team's mailbox on the People page. Set once and then left alone, so the
   form folds away behind what it produced: the one line saying where the
   mail comes from. */
.mailnow { display: flex; align-items: center; gap: 7px; font-size: 14px; color: var(--text); }
.mailnow .ico-svg { color: hsl(var(--c-green)); flex: none; }
.fold > summary {
  display: flex; align-items: center; gap: 6px; cursor: pointer; list-style: none;
  font-size: 13.5px; font-weight: 600; color: var(--text-dim);
}
.fold > summary::-webkit-details-marker { display: none; }
.fold > summary .chev { display: inline-flex; transition: transform .12s; }
.fold[open] > summary .chev { transform: rotate(90deg); }
.fold > .fold-body { margin-top: 10px; }
.notiflist { padding: 4px; }
.notiflist .notif { border-radius: var(--r-md); padding: 12px 11px; }
.notiflist .notif + .notif { border-top: 1px solid var(--border); border-radius: 0; }
.notiflist .notif:hover { border-radius: var(--r-md); }

/* --------------------------------------------------------- without script */
/* The scripted control and its plain-HTML twin are both in the markup; each
   hides the other, so neither state ever shows two of the same button. */
noscript .btn { display: inline-flex; }
html.js noscript { display: none; }
html:not(.js) .js-only { display: none !important; }

/* Read aloud, never drawn. For the things a page has to *say* that it already
   shows some other way — a heading over a title that is an editable box, the
   link that skips the fourteen sidebar entries. */
.offscreen {
  position: absolute; width: 1px; height: 1px; margin: -1px;
  padding: 0; border: 0; overflow: hidden; white-space: nowrap;
  clip: rect(0 0 0 0); clip-path: inset(50%);
}
/* ...except when it has the caret, so the skip link is visible to the person
   tabbing through and to nobody else. */
.skiplink:focus {
  position: fixed; top: 8px; left: 8px; z-index: 200;
  width: auto; height: auto; margin: 0; overflow: visible;
  clip: auto; clip-path: none;
  padding: 8px 13px; border-radius: var(--r-md);
  background: var(--panel); border: 1px solid var(--accent);
  box-shadow: var(--shadow-2); color: var(--text); text-decoration: none;
}

/* A field the ticket's own status is asking to have filled in. Quiet — an
   amber edge and a line of explanation, not an error: nothing is wrong, there
   is just one more thing worth saying while the thought is fresh. */
.prop.wants { box-shadow: inset 3px 0 0 hsl(var(--c-amber)); }
.prop.wants > .k { color: var(--text-dim); }
.wantsnote { margin-top: 4px; color: var(--text-mute); }

/* A date in words, under the chips that can only offer three of them. Quieter
   than the picker above it: it is the way round for the answer that is not on
   a chip, not the primary control. */
.whenbox { display: flex; gap: 6px; margin-top: 7px; }
.whenbox input { flex: 1 1 auto; min-width: 0; font-size: 12.5px; padding: 5px 9px; }
.whenbox button { flex: none; }

/* A toast you can act on. The button reads as part of the message rather than
   as a second control beside it — it is the one thing this particular sentence
   is for. */
#toast:has(.toast-act) { padding: 7px 8px 7px 15px; display: inline-flex; align-items: center; gap: 10px; }
#toast .toast-act {
  pointer-events: auto;
  padding: 5px 12px; border-radius: 99px;
  border: 1px solid color-mix(in srgb, var(--bg) 35%, transparent);
  background: color-mix(in srgb, var(--bg) 14%, transparent);
  color: inherit; font: inherit; font-weight: 650; cursor: pointer;
}
#toast .toast-act:hover { background: color-mix(in srgb, var(--bg) 26%, transparent); }
#toast .toast-act:focus-visible { outline: 2px solid var(--bg); outline-offset: 1px; }

/* ---------------------------------------------------------------- Claude
   The panel above a ticket's conversation, while Claude works on it. Quiet
   by default — a line saying where things stand — and the buttons only for
   whoever may press them. */
.agentav { width: 16px; height: 16px; border-radius: 4px; flex: none; }
.agentp .ph { gap: 7px; }
.agentp .ap-state { color: var(--text-dim); font-weight: 500; }
.agentp .ap-state::before { content: "·"; margin-right: 7px; color: var(--text-mute); }
.agentp[data-state="review"] .ap-state, .agentp[data-state="plan"] .ap-state { color: var(--accent); }
.agentp[data-state="failed"] .ap-state { color: var(--danger); }
.agentp .pb { display: grid; gap: 10px; }
.agentp .pb:empty { display: none; }
.ap-note { margin: 0; color: var(--text-dim); font-size: 14px; }
.ap-steps {
  margin: 0; padding: 8px 12px; list-style: none; display: grid; gap: 3px;
  background: var(--panel-2); border: 1px solid var(--border); border-radius: var(--r-md);
  font-family: var(--mono); font-size: 12.5px; color: var(--text-dim);
}
.ap-steps li { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ap-steps li:last-child { color: var(--text); }
.ap-row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.ap-act { display: inline; margin: 0; }
.ap-links { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; font-size: 13.5px; }
.ap-links a { display: inline-flex; align-items: center; gap: 5px; }
.ap-ok { color: hsl(var(--c-green)); font-size: 13.5px; }
.ap-bad { color: var(--danger); font-size: 13.5px; }
.ap-plan summary { cursor: pointer; display: inline-flex; align-items: center; gap: 5px; color: var(--text-dim); }
.ap-plan[open] summary svg { transform: rotate(90deg); }
.ap-plantext { white-space: pre-wrap; font-size: 14px; margin-top: 8px; padding: 10px 12px; border-left: 3px solid var(--accent-soft); }
.ap-off { display: inline-block; }
.ap-off > summary { list-style: none; }
.ap-off > summary::-webkit-details-marker { display: none; }
.ap-off[open] { display: block; flex-basis: 100%; }
.ap-offform { display: grid; gap: 8px; margin-top: 8px; }
.ap-offform textarea { width: 100%; }
.ap-foot { padding: 0 16px 12px; font-size: 12.5px; }
.ap-foot code, .ap-links code, .ap-note code { font-size: 12px; }
.ap-model { display: inline; }
.ap-idle { font-size: 12.5px; margin: 0 0 12px; }
.ap-model > summary { display: inline; cursor: pointer; list-style: none; text-decoration: underline dotted; text-underline-offset: 3px; }
.ap-model > summary::-webkit-details-marker { display: none; }
.ap-modelform { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 190px), 1fr)); gap: 8px 12px; align-items: end; margin-top: 8px; }
.ap-modelform label { display: grid; gap: 4px; min-width: 0; }
.ap-modelform label span { font-size: 12px; color: var(--text-dim); }
.ap-modelform select { width: 100%; min-width: 0; }
.ap-modelform .btn { justify-self: start; }
.ap-modelform p { grid-column: 1 / -1; margin: 0; font-size: 12px; }

/* Above the composer, only while it is true. */
.askedme {
  display: flex; align-items: center; gap: 8px; margin: 0 0 8px;
  padding: 7px 10px; border-radius: var(--r-md);
  background: var(--accent-soft); color: var(--text); font-size: 13.5px;
}

/* On a list row. */
.claudechip { padding: 0 6px 0 3px; border-radius: 999px; border: 1px solid var(--border); }
.claudechip .agentav { width: 11px; height: 11px; border-radius: 3px; }
.claudechip[data-tone="you"] { border-color: var(--accent); color: var(--accent); }
.claudechip[data-tone="bad"] { border-color: var(--danger); color: var(--danger); }
.claudechip[data-tone="work"] { color: var(--text); }

/* A project's Claude settings. */
.cfgform { display: grid; grid-template-columns: minmax(0, 1fr); gap: 12px; }
.cfgform > label:not(.switch), .cfgpair > label { display: grid; gap: 4px; font-size: 13.5px; color: var(--text-dim); }
.cfgform input[type="text"], .cfgform input[type="number"], .cfgform input[type="url"], .cfgform input[type="password"],
.cfgform textarea, .cfgform select { width: 100%; max-width: 420px; }
.cfgset { border: 0; padding: 0; margin: 0; display: grid; gap: 6px; min-width: 0; }
.cfgset > legend { font-size: 13.5px; color: var(--text-dim); margin-bottom: 4px; display: flex; align-items: center; gap: 6px; }
.cfgpair { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 12px; align-items: end; max-width: 640px; }
.setupchecks { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; font-size: 14px; }
.setupchecks li { display: flex; gap: 8px; align-items: baseline; }
.setupchecks .sc-mark { width: 16px; flex: none; text-align: center; font-weight: 700; }
.setupchecks li[data-level="ok"] .sc-mark { color: hsl(var(--c-green)); }
.setupchecks li[data-level="warn"] .sc-mark { color: hsl(var(--c-amber)); }
.setupchecks li[data-level="fail"] .sc-mark { color: var(--danger); }
.setupchecks .sc-fix { display: block; margin-top: 2px; color: var(--text-dim); }
.setupchecks .sc-fix b { color: var(--text); font-weight: 600; }
.projclaude { gap: 5px; max-width: 220px; overflow: hidden; }
.projclaude .mono { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12.5px; }
.agentteam .pb.row { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; font-size: 14px; }

/* A plan's steps: who has said yes, and who still has to. */
.ap-gates { list-style: none; margin: 0; padding: 0; display: grid; gap: 4px; font-size: 13.5px; }
.ap-gates li { display: flex; gap: 7px; align-items: baseline; color: var(--text-dim); }
.ap-gates li[data-done="yes"] { color: var(--text); }
.ap-gates li[data-done="yes"] .sc-mark { color: hsl(var(--c-green)); }
.ap-gates .sc-mark { width: 14px; text-align: center; font-weight: 700; flex: none; }
.ap-check { margin: 0; font-size: 13.5px; color: var(--text-dim); }

/* Claude's settings: four tabs, each a page. */
.cl-tabs {
  display: flex; gap: 4px; padding: 4px; margin-bottom: 16px; overflow-x: auto;
  background: var(--panel); border: 1px solid var(--border); border-radius: var(--r-lg);
}
.cl-tabs a {
  flex: 1 1 0; min-width: max-content; text-align: center; padding: 6px 12px; border-radius: var(--r-md);
  font-size: 13.5px; font-weight: 600; color: var(--text-dim); white-space: nowrap; text-decoration: none;
}
.cl-tabs a:hover { background: var(--panel-3); color: var(--text); }
.cl-tabs a[aria-current="page"] { background: var(--accent-soft); color: var(--text); }
.cl-notice { margin: 0 0 12px; padding: 8px 12px; border-radius: var(--r-md); background: var(--accent-soft); font-size: 14px; }
.cl-error { margin: 0 0 12px; }
.cl-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; }
.cl-stats b { font-size: 22px; font-variant-numeric: tabular-nums; letter-spacing: -.01em; }
.cl-stats .dim { font-size: 13px; }
.cl-setup { margin: 0; padding-left: 18px; display: grid; gap: 4px; font-size: 14px; }
.cl-remove { margin-top: 4px; }
.cl-skill { display: grid; gap: 4px; padding: 10px 0; border-bottom: 1px solid var(--border); }
.cl-skill:first-child { padding-top: 0; }
.cl-skillhead { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.cl-skillhead form { display: inline; margin: 0; }
.cl-skillsrc { margin: 0; font-size: 12.5px; }
.cl-skillsrc code { font-size: 12px; }
.cl-addskill { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 12px; }
.cl-addskill input[type="url"] { flex: 1 1 300px; width: auto; min-width: 0; }
.cl-addskill select { flex: none; width: auto; }
.cl-person, .cl-source { border-top: 1px solid var(--border); }
.cl-person > summary, .cl-source > summary {
  list-style: none; cursor: pointer; display: flex; align-items: center; gap: 9px; padding: 10px 16px; min-width: 0;
}
.cl-person > summary::-webkit-details-marker, .cl-source > summary::-webkit-details-marker { display: none; }
.cl-person > summary:hover, .cl-source > summary:hover { background: var(--panel-2); }
.cl-person > summary > .ico-svg, .cl-source > summary > .ico-svg { color: var(--text-mute); transition: transform .12s; flex: none; }
.cl-person[open] > summary > .ico-svg:last-child, .cl-source[open] > summary > .ico-svg:last-child { transform: rotate(90deg); }
.cl-source > form { padding: 4px 16px 16px; }
.cl-source .cfgpair { align-items: start; }
.panel.flush > .pb.cl-pad { padding: 12px 16px; }
.cl-srccheck[data-state="ok"] { color: var(--text); }
.cl-okmark { color: hsl(var(--c-green)); font-weight: 700; }
.cl-sppair { align-items: start; }
.cl-steps { margin: 6px 0 8px; padding-left: 20px; display: grid; gap: 4px; font-size: 13.5px; color: var(--text-dim); }
.cl-source > summary .mono { font-size: 12.5px; min-width: 0; }
.cl-source .chip[data-state="ok"] { border-color: var(--accent); color: var(--accent); }
.cl-source .chip[data-state="err"], .cl-srccheck[data-state="err"] { color: var(--danger); }
.cl-source .chip[data-state="err"] { border-color: currentColor; }
.cl-srccheck { margin: 0; }
.cl-tools .cl-tool { align-items: flex-start; }
.cl-tools .cl-tool code { font-size: 12.5px; }
.cl-tools .cl-tool .cs-hint { display: block; }
.cl-writes { font-size: 11px; padding: 0 6px; }
.cl-person .chip[data-level="none"] { color: var(--text-mute); }
.cl-person .chip[data-level="developer"] { border-color: var(--accent); color: var(--accent); }
.cl-personfacts { font-size: 13px; min-width: 0; }
.cl-person > form, .cl-person > .pb { padding: 4px 16px 16px; }
.cl-project {
  display: flex; align-items: center; gap: 10px; padding: 10px 16px; border-top: 1px solid var(--border);
  color: var(--text); text-decoration: none; min-width: 0; flex-wrap: wrap;
}
.cl-project:hover { background: var(--panel-2); }
.cl-project .mono { font-size: 12.5px; min-width: 0; }
.cl-project > .ico-svg { color: var(--text-mute); flex: none; }
.cl-back { align-items: center; gap: 10px; margin-bottom: 12px; }
.cl-back h2 { font-size: 17px; margin: 0; }
.cl-save { margin: 4px 0 24px; }
.cl-switchhint { margin: 3px 0 0 28px; }
@media (max-width: 640px) {
  .cl-tabs { display: grid; grid-template-columns: 1fr 1fr; }
  .cl-person > summary, .cl-source > summary { flex-wrap: wrap; }
  .cl-personfacts { flex-basis: 100%; order: 3; }
}
.md .linkhost { color: var(--text-mute); font-size: .92em; }
