/* ============================================================
   Docket — design system  (no framework)
   RULES LIVE IN /DESIGN.md — read it before touching this file.
   The short version: readable beats refined (body 15px, labels
   12.5px, nothing under 12px); mono is for identifiers only;
   color means pipeline stage or danger, plus ONE cool accent
   (--nav) for wayfinding (active nav, links, version chip).
   Fonts: IBM Plex Sans / Mono.
   ============================================================ */
:root[data-theme="dark"]{
	/* Follow the app theme for UA-drawn form controls — the <meta color-scheme>
	   is "dark light", so without this an unstyled input paints DARK on the
	   light theme (the theme toggle only flips tokens, never the meta). */
	color-scheme:dark;
	--ink:#0D1014; --surface:#141920; --raised:#1A2029; --sunken:#0A0D11;
	/* Lifted one step (from #242C37 / #1A212A) so cards and section rules
	   separate at a glance instead of blending into the surface. */
	--line:#36414F; --line-soft:#2B3441;
	/* --fg-3 is tertiary text (micro labels, meta, status chips). Lifted from
	   #5E6978 (~3.1:1 on --surface — fails AA for the 11px mono it's used on) to
	   ~5.6:1 so the small print is actually legible. */
	--fg:#EAEDF1; --fg-2:#9BA6B4; --fg-3:#8A93A1;
	--bone:#F0EAE0; --on-bone:#12161B;
	/* Wayfinding accent (active nav, links, version chip) — see DESIGN.md. */
	--nav:#7CA0FF;
	/* Dedicated code-editor surface (feels like a real editor, distinct from the warm UI). */
	--code-bg:#0D1117; --code-fg:#DCE3EA; --code-gutter:#6E7681; --code-line:#222A34; --code-head:#161B22;
	/* Syntax tokens (code surfaces are the one sanctioned color exception). */
	--cv-k:#F47067; --cv-s:#8DDB8C; --cv-n:#6CB6FF; --cv-v:#F69D50; --cv-f:#DCBDFB; --cv-t:#96D0FF; --cv-a:#6CB6FF;
	--shadow:0 1px 0 rgba(255,255,255,.03) inset, 0 8px 24px -12px rgba(0,0,0,.7);
}
:root[data-theme="light"]{
	color-scheme:light;
	--ink:#F6F4F0; --surface:#FFFFFF; --raised:#FBFAF8; --sunken:#EFEDE8;
	/* Lifted one step (from #DFDBD3 / #EAE7E1) — same reason as the dark theme. */
	--line:#C8C1B4; --line-soft:#DAD5CB;
	/* Same lift in light mode: #8E97A4 was ~2.9:1 on white; #6B7280 is ~4.6:1. */
	--fg:#15191F; --fg-2:#565F6C; --fg-3:#6B7280;
	--bone:#15191F; --on-bone:#F5F3EF;
	--nav:#3B63D8;
	--code-bg:#FFFFFF; --code-fg:#1F2328; --code-gutter:#8C959F; --code-line:#E4E2DC; --code-head:#F7F6F3;
	--cv-k:#CF222E; --cv-s:#116329; --cv-n:#0550AE; --cv-v:#953800; --cv-f:#8250DF; --cv-t:#0A6E8A; --cv-a:#0550AE;
	--shadow:0 1px 2px rgba(20,24,30,.04), 0 8px 24px -16px rgba(20,24,30,.18);
}
:root{
	/* stage colors — the ONLY chroma in the product */
	--s-assigned:#8A94A6; --s-autotest:#E3A83C; --s-qa:#A98BE8;
	--s-testing:#4FBBD6;  --s-review:#6B8DF7;   --s-merge:#52B788;
	--s-open:#8A94A6; --s-holding:#6E7A8A; --s-closed:#5E6978;
	--danger:#E0685F;
	--r:7px; --r-lg:11px;
	--mono:"IBM Plex Mono",ui-monospace,SFMono-Regular,Menlo,monospace;
	--sans:"IBM Plex Sans",system-ui,-apple-system,sans-serif;
	--cond:"IBM Plex Sans Condensed","IBM Plex Sans",sans-serif;
	/* Type scale (DESIGN.md — hard values, 12px floor everywhere):
	   display 27 · title 23 · lead 16 · body 15 · ui 14 · label 12.5 · meta 13 */
	--fs-display:27px; --fs-title:23px; --fs-lead:16px; --fs-body:15px;
	--fs-ui:14px; --fs-label:12.5px; --fs-meta:13px;
}
*{box-sizing:border-box}
/* Pin text-size-adjust: without it iOS Safari "font boosting" inflates individual
   lines inside wide non-wrapping blocks (diff rows render at mixed sizes on phones). */
html,body{margin:0;padding:0;-webkit-text-size-adjust:100%;text-size-adjust:100%}
body{background:var(--ink);color:var(--fg);font-family:var(--sans);font-size:var(--fs-body);line-height:1.5;-webkit-font-smoothing:antialiased}
a{color:var(--fg);text-decoration:none}
a:hover{text-decoration:underline}
:focus-visible{outline:2px solid var(--fg-2);outline-offset:2px;border-radius:4px}
[hidden]{display:none !important}
.muted{color:var(--fg-2)}
.spacer{flex:1}

/* Type scale — see DESIGN.md. Section labels are SANS (mono is for
   identifiers only), 600 weight, and nothing renders below 12px. */
.t-display{font-size:var(--fs-title);font-weight:650;letter-spacing:-.02em;line-height:1.25}
.t-section{font-family:var(--sans);font-size:var(--fs-label);font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--fg-3)}
.t-body{font-size:var(--fs-body)}
.t-meta{font-family:var(--mono);font-size:var(--fs-meta);color:var(--fg-2)}
.t-micro{font-family:var(--mono);font-size:12.5px;letter-spacing:.02em;color:var(--fg-3)}
.mono{font-family:var(--mono)}

/* ===== TOPBAR ===== */
.topbar{display:flex;align-items:center;gap:16px;height:60px;padding:0 24px;border-bottom:1px solid var(--line);background:var(--surface);position:sticky;top:0;z-index:40}
.wordmark{font-weight:700;letter-spacing:-.03em;font-size:19px;white-space:nowrap;color:var(--fg)}
.wordmark:hover{text-decoration:none}
.wordmark .dim{color:var(--fg-3);font-weight:450}
.org{font-family:var(--mono);font-size:12.5px;color:var(--fg-2);border:1px solid var(--line);border-radius:var(--r);padding:5px 9px}
.topsearch{position:relative;flex:1;max-width:560px}
.topsearch>span.ic{position:absolute;left:11px;top:50%;transform:translateY(-50%);color:var(--fg-3);font-size:14px;pointer-events:none}
.topsearch input{width:100%;background:var(--sunken);border:1px solid var(--line);border-radius:var(--r);padding:9px 12px 9px 32px;color:var(--fg);font-family:var(--sans);font-size:14px;outline:none}
.topsearch input::placeholder{color:var(--fg-3)}
.topsearch input:focus{border-color:var(--fg-3)}
/* The native search "×" renders near-invisible; replace it with an SVG mask so
   its color follows the theme (muted gray, darkening to full-contrast on hover). */
.topsearch input::-webkit-search-cancel-button{-webkit-appearance:none;appearance:none;width:14px;height:14px;cursor:pointer;background-color:var(--fg-2);-webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M6 6 18 18M18 6 6 18' stroke='black' stroke-width='2.6' stroke-linecap='round'/%3E%3C/svg%3E") center/contain no-repeat;mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M6 6 18 18M18 6 6 18' stroke='black' stroke-width='2.6' stroke-linecap='round'/%3E%3C/svg%3E") center/contain no-repeat}
.topsearch input::-webkit-search-cancel-button:hover{background-color:var(--fg)}
/* The dropdown floats wider than the input (the topbar squeezes the field on busy screens).
   clamp: never narrower than the input, never past the viewport's right edge (420px ≈ the
   chrome left of the search plus the topbar padding), 640px when there's room. */
.hdr-results{position:absolute;top:calc(100% + 6px);left:0;width:clamp(100%, calc(100vw - 420px), 640px);z-index:50;background:var(--surface);border:1px solid var(--line);border-radius:var(--r-lg);box-shadow:var(--shadow);overflow:hidden;max-height:60vh;overflow-y:auto;padding:5px}
.hr-item{display:flex;align-items:center;gap:10px;padding:8px 9px;border-radius:var(--r);color:var(--fg)}
.hr-item:hover{background:var(--raised);text-decoration:none}
/* Keyboard-selected result: the highlight is the only cue (no cursor), so it
   reads stronger than hover — sunken fill + a nav rail, like .notif-item.unread. */
.hr-item.active{background:var(--sunken);box-shadow:inset 2px 0 0 var(--nav);text-decoration:none}
.hr-key{font-family:var(--mono);font-size:12.5px;color:var(--fg-2);border:1px solid var(--line);border-radius:4px;padding:3px 7px;flex:none}
.hr-body{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.hr-title{font-size:var(--fs-ui);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.hr-snip{font-size:var(--fs-meta);color:var(--fg-2);line-height:1.4;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.hr-hit{font-weight:600;color:var(--fg)}
.hr-empty{padding:12px;color:var(--fg-2);font-size:var(--fs-ui)}
.hr-more{display:block;padding:12px;margin-top:4px;border-top:1px solid var(--line);font-size:var(--fs-ui);font-weight:500;color:var(--nav);border-radius:var(--r);position:sticky;bottom:-5px;background:var(--surface);z-index:1}
.hr-more:hover{background:var(--raised);text-decoration:none;color:var(--nav)}
.topnav{display:flex;gap:4px;margin-left:auto;align-items:center}
.topnav a{color:var(--fg-2);padding:8px 12px;border-radius:var(--r);font-size:15px;font-weight:450}
.topnav a:hover{color:var(--fg);text-decoration:none}
/* "Needs you" hand-off count — same pill as the bell badge, inline in the link. */
.topnav .nav-count{display:inline-block;min-width:16px;height:16px;padding:0 4px;margin-left:6px;border-radius:9px;background:var(--nav);color:#fff;font-family:var(--sans);font-size:10.5px;font-weight:700;line-height:16px;text-align:center;vertical-align:1px}
/* Active nav = a quiet filled pill (the underline hugged the link's rounded
   corners and read as a stray floating border). */
.topnav a[aria-current]{color:var(--fg);font-weight:600;background:var(--raised);box-shadow:inset 0 0 0 1px var(--line-soft)}
/* "More" overflow trigger — dressed as a topnav link, not a button. When the
   current page lives inside the menu, the trigger carries its name + the same
   active pill as a real tab (ui_head.php sets aria-current on it). */
.topnav-more>button{display:inline-flex;align-items:center;gap:5px;background:none;border:0;cursor:pointer;font:inherit;color:var(--fg-2);padding:8px 12px;border-radius:var(--r);font-size:15px;font-weight:450;line-height:normal;user-select:none}
.topnav-more>button:hover{color:var(--fg)}
.topnav-more>button[aria-current]{color:var(--fg);font-weight:600;background:var(--raised);box-shadow:inset 0 0 0 1px var(--line-soft)}
.topnav-more>button svg{opacity:.55;margin-top:1px;flex:none}
.topnav-more .menu{min-width:250px}
.topnav-more .menu-item span{white-space:nowrap}
.topnav-more .menu-item{text-decoration:none}
.topnav-more .menu-item:hover{text-decoration:none}
.topnav-more .menu-item[aria-current]{background:var(--raised);font-weight:600}
.iconbtn{background:none;border:1px solid var(--line);color:var(--fg-2);border-radius:var(--r);width:34px;height:34px;cursor:pointer;font-size:15px;line-height:1;display:grid;place-items:center}
.iconbtn:hover{color:var(--fg);border-color:var(--fg-3)}
.av{width:30px;height:30px;border-radius:50%;display:grid;place-items:center;font-family:var(--mono);font-size:11px;font-weight:600;line-height:1;background:var(--raised);border:1px solid var(--line);color:var(--fg-2);flex:none;text-decoration:none}
.av:hover{text-decoration:none}
/* The topbar avatar is an <a> inside .topnav, whose link rule (15px font,
   8/12px padding) outspecifies .av and shoved the initials off-center. */
.topnav a.av{font-size:11px;font-weight:600;padding:0;line-height:1}

/* Header notifications bell + dropdown. */
.notif-wrap{position:relative;display:inline-flex}
.notif-badge{position:absolute;top:-4px;right:-5px;min-width:16px;height:16px;padding:0 4px;border-radius:9px;background:var(--nav);color:#fff;font-family:var(--sans);font-size:10.5px;font-weight:700;line-height:16px;text-align:center}
.notif-panel{position:absolute;right:0;top:calc(100% + 8px);width:344px;max-width:86vw;background:var(--raised);border:1px solid var(--line);border-radius:var(--r-lg);box-shadow:0 16px 40px rgba(0,0,0,.34);z-index:200;overflow:hidden}
.notif-hd{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:12px 14px;border-bottom:1px solid var(--line-soft)}
.notif-hd-actions{display:flex;align-items:center;gap:12px;flex:none}
.notif-showread{all:unset;cursor:pointer;color:var(--fg-2);font-size:12.5px;font-weight:600}
.notif-showread:hover{color:var(--fg);text-decoration:underline}
.notif-showread[aria-pressed="true"]{color:var(--nav)}
.notif-readall{all:unset;cursor:pointer;color:var(--nav);font-size:12.5px}
.notif-readall:hover{text-decoration:underline}
.notif-empty .notif-readall{display:inline-block;margin-top:10px}
.notif-list{max-height:60vh;overflow-y:auto}
.notif-empty{padding:18px 14px;color:var(--fg-3);font-size:13.5px}
.notif-item{display:flex;align-items:flex-start;gap:10px;padding:11px 14px;border-bottom:1px solid var(--line-soft);color:var(--fg);border-left:2px solid transparent}
.notif-item:last-child{border-bottom:0}
.notif-item:hover{background:var(--sunken)}
.notif-item.unread{background:var(--sunken);border-left-color:var(--nav)}
.notif-item-link{flex:1;min-width:0;color:inherit;text-decoration:none}
.notif-item-link:hover{text-decoration:none}
.notif-item-hd{font-size:13.5px}
.notif-item-hd b{font-weight:600}
.notif-verb{color:var(--fg-2)}
.notif-item-body{margin-top:3px;color:var(--fg-2);font-size:12.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.notif-readone{all:unset;cursor:pointer;color:var(--nav);font-size:12.5px;flex:none;align-self:center}
.notif-readone:hover{text-decoration:underline}

/* ===== SHELL ===== */
.shell{max-width:1560px;margin:0 auto;padding:0 20px 64px}
.wrap{max-width:1100px;margin:0 auto;padding:0 20px 64px}
/* Wide variant (admin) — the 12-tab row overflowed the 1100px wrap; the page
   matches the tab row's width instead. */
.wrap-wide{max-width:1560px}
/* Reading pages (release notes): between wrap and wrap-wide — wide enough to
   use a big monitor, narrow enough that 16px prose fills the card without
   needing its own cap. */
.wrap-notes{max-width:1300px}

/* ===== BUTTONS ===== */
/* Buttons clear the 36px height floor (10px vertical padding). */
.btn{font-family:var(--sans);font-size:var(--fs-ui);font-weight:500;border-radius:var(--r);padding:10px 16px;cursor:pointer;border:1px solid var(--line);background:var(--surface);color:var(--fg);display:inline-flex;align-items:center;gap:8px;text-decoration:none;line-height:1}
.btn:hover{border-color:var(--fg-3);text-decoration:none}
.btn:disabled{opacity:.5;cursor:default}
.btn-primary{background:var(--bone);color:var(--on-bone);border-color:transparent;font-weight:600}
.btn-primary:hover{filter:brightness(.94);border-color:transparent}
.btn-quiet{background:none;border-color:transparent;color:var(--fg-2)}
.btn-quiet:hover{color:var(--fg);background:var(--raised)}
.btn-danger{background:none;border-color:transparent;color:var(--danger)}
.btn-danger:hover{background:color-mix(in srgb,var(--danger) 12%,transparent)}
.btn-sm{padding:7px 12px;font-size:13.5px}

/* ===== TICKET HEADER ===== */
.thead{display:flex;align-items:flex-start;gap:14px;padding:26px 0 8px}
.back{border:1px solid var(--line);background:var(--surface);color:var(--fg-2);border-radius:var(--r);width:38px;height:38px;display:grid;place-items:center;cursor:pointer;flex:none;font-size:16px;text-decoration:none}
.back:hover{color:var(--fg);border-color:var(--fg-3);text-decoration:none}
.key{font-family:var(--mono);font-size:14px;font-weight:500;color:var(--fg-2);border:1px solid var(--line);border-radius:var(--r);padding:7px 11px;flex:none}
.key-copy{display:inline-flex;align-items:center;gap:6px;cursor:pointer;min-height:36px;background:var(--surface);line-height:1.2}
.key-copy:hover{color:var(--fg);border-color:var(--fg-3)}
.key-copy:focus-visible{outline:2px solid var(--fg-3);outline-offset:2px}
.key-copy-mark{font-size:15px;color:var(--fg-3);line-height:1}
.key-copy:hover .key-copy-mark{color:var(--nav)}
.key-copy.is-copied{color:var(--s-merge);border-color:var(--s-merge)}
.key-copy.is-copied .key-copy-mark{color:var(--s-merge)}
.thead h1{margin:0;flex:1;min-width:0;max-width:760px}
.thead-actions{margin-left:auto;display:flex;gap:10px;align-items:center;flex:none}
.watch-btn{width:36px;height:36px;flex:none}
.watch-btn svg{width:18px;height:18px}
.watch-btn.watching{color:var(--fg);border-color:var(--fg-3)}
.watch-btn.watching .watch-eye{fill:currentColor}
.watch-btn.watching circle{fill:var(--surface)}
.editable-title{cursor:text;border-radius:var(--r);padding:1px 5px;margin:0 -5px}
.editable-title:hover{background:var(--raised)}
.title-input{width:100%;font-family:var(--sans);font-size:var(--fs-title);font-weight:650;letter-spacing:-.02em;background:var(--sunken);border:1px solid var(--fg-3);border-radius:var(--r);color:var(--fg);padding:1px 6px;outline:none}
/* Ticket title rename: keep the control in the heading's display box so a
   long name does not collapse to a single clipped native-input line. */
#tk-title:has(.title-input){flex:1 1 auto;min-width:0}
#tk-title .title-input{display:block;width:100%;min-width:0;max-width:100%;margin:0;padding:0;border:0;outline:1px solid var(--fg-3);outline-offset:0;font:inherit;letter-spacing:inherit;line-height:inherit;resize:none;overflow:hidden;background:var(--sunken)}

/* ===== PIPELINE SPINE (replaces stepper + status pill) ===== */
.spine{border:1px solid var(--line);border-radius:var(--r-lg);background:var(--surface);padding:18px 20px 16px;box-shadow:var(--shadow)}
.spine-track{display:grid;gap:4px}
/* Scoped to .spine-track so the thin 4px bar does NOT leak onto the .seg
   segmented control (view-toggle) further down — same class name, different widget. */
.spine-track .seg{height:5px;border-radius:3px;background:var(--line-soft)}
.spine-track .seg.done{background:var(--fg-3)}
.spine-track .seg.active{background:var(--stage);position:relative;overflow:hidden}
/* The sweeping sheen means "work is actively happening" — show it ONLY while the
   issue is in automated testing, else a static pipeline looks like it's moving. */
.spine-track .seg.active::after{content:"";position:absolute;inset:0;background:linear-gradient(90deg,transparent,color-mix(in srgb,#fff 70%,transparent),transparent);opacity:0}
.spine.is-testing .spine-track .seg.active::after,.spine.is-merging .spine-track .seg.active::after,.spine.is-unmerging .spine-track .seg.active::after{opacity:1;animation:sweep 2.4s ease-in-out infinite}
@keyframes sweep{0%{transform:translateX(-100%)}60%,100%{transform:translateX(100%)}}
.spine-labels{display:grid;gap:4px;margin-top:12px}
.spine-labels span{font-family:var(--sans);font-size:var(--fs-label);font-weight:600;letter-spacing:.04em;text-transform:uppercase;color:var(--fg-3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.spine-labels span.done{color:var(--fg-2)}
.spine-labels span.active{color:var(--stage)}
.spine-foot{display:flex;align-items:center;gap:12px;margin-top:16px;padding-top:15px;border-top:1px solid var(--line-soft);flex-wrap:wrap}
.stage-now{display:flex;align-items:center;gap:9px;font-size:15px;font-weight:500;color:var(--fg)}
.pulse{width:8px;height:8px;border-radius:50%;background:var(--stage);box-shadow:0 0 0 4px color-mix(in srgb,var(--stage) 22%,transparent);flex:none}
.spine-foot .t-micro{margin-left:auto}
/* Why the issue sits in Assigned — reads as a sub-clause of the stage sentence, not a second line. */
.stage-why{font-weight:400;color:var(--fg-2)}
.stage-why-link{font-size:12px;font-weight:500;color:var(--fg-3);border-bottom:1px dashed var(--line);margin-left:4px;white-space:nowrap}
.spine.is-closed .spine-track .seg.active,.spine.is-closed .spine-track .seg.done{background:var(--fg-3)}

/* Move-stage menu */
.menu-wrap{position:relative}
.menu{position:absolute;right:0;top:calc(100% + 6px);z-index:50;min-width:240px;background:var(--surface);border:1px solid var(--line);border-radius:var(--r-lg);box-shadow:var(--shadow);padding:5px}
.menu-hd{font-family:var(--sans);font-size:var(--fs-label);font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--fg-3);padding:8px 10px 6px}
.menu-item{display:flex;align-items:center;justify-content:space-between;gap:12px;width:100%;text-align:left;background:none;border:0;padding:10px 10px;border-radius:var(--r);cursor:pointer;font-family:var(--sans);font-size:14px;color:var(--fg)}
.menu-item:hover{background:var(--raised)}
.menu-item .to{font-family:var(--mono);font-size:12.5px;color:var(--fg-3)}
/* Disabled by the trunk-conflict gate: not clickable, dimmed, not-allowed cursor. */
.menu-item.is-blocked{opacity:.45;cursor:not-allowed}
/* Drop-UP variant for menus anchored to the composer at the bottom of the view. */
.menu-up{top:auto;bottom:calc(100% + 6px)}
/* Selected-row checkmark inside chip menus (model/effort). */
.menu-item .mi-on{font-weight:600}
/* Long menus scroll instead of running off-screen. */
.menu{max-height:min(70vh, 560px);overflow-y:auto}
/* Start-a-session actions: real buttons (the menu above them is a form, so
   plain rows stopped reading as "this starts it"). Label left, hint right —
   the hint inherits the button's color so it works on the bone primary too. */
.menu-actions{display:flex;flex-direction:column;gap:8px;padding:10px 12px 12px}
.menu-actions .btn{width:100%;justify-content:space-between;white-space:nowrap}
.menu-actions .btn-sub{font-family:var(--mono);font-size:12.5px;color:inherit;opacity:.65;font-weight:400}
/* The start-a-session menus carry a form + action buttons — give them room so
   the button label and its hint sit on one line. Never wider than the viewport. */
#new-menu,#ws-new-menu{min-width:320px}
.menu{max-width:calc(100vw - 24px)}
/* The rail's + New sits near the LEFT page edge — a right-anchored 320px menu
   would run off-screen, so this one opens toward the chat column instead. */
#ws-new-menu{right:auto;left:0}
/* Cards clip children for their rounded corners — but an OPEN dropdown (the
   ticket page's + New session menu) must escape, or it renders cut off. */
.card:has(.menu:not([hidden])){overflow:visible}
.menu-item.is-blocked:hover{background:none}
.menu-empty{padding:10px;font-size:13.5px;color:var(--fg-2)}

/* ===== COLUMNS ===== */
.cols{display:grid;grid-template-columns:300px minmax(0,1fr) 320px;gap:16px;margin-top:16px;align-items:start}
@media (max-width:1240px){.cols{grid-template-columns:300px minmax(0,1fr)}.col-sessions{grid-column:1/-1}}
/* minmax(0,…) so a wide child (e.g. the Activity filter pills) can't stretch
   the track past the viewport. */
@media (max-width:880px){.cols{grid-template-columns:minmax(0,1fr)}}

.card{border:1px solid var(--line);border-radius:var(--r-lg);background:var(--surface);box-shadow:inset 3px 0 0 var(--card-spine,transparent),var(--shadow);overflow:hidden}
.card + .card{margin-top:18px}
/* Ticket main-column spines: each section carries the stage color it serves
   (testing steps → testing, QA notes → QA), prose sections stay slate. The
   hues are the pipeline stage tokens, so this stays inside DESIGN.md's
   "color = state" rule — don't add spines from outside that palette. */
.col-main > .card{--card-spine:var(--s-assigned)}
#card-steps{--card-spine:var(--s-testing)}
#card-qa{--card-spine:var(--s-qa)}
/* Grid gaps handle spacing — the stacked-card margin above would push every
   card after the first down and misalign the column tops. */
.field-grid > .card + .card{margin-top:0}
.metrics-grid > .card + .card{margin-top:0}
.card-hd{display:flex;align-items:center;gap:12px;padding:14px 16px;border-bottom:1px solid var(--line-soft)}
/* Collapsible field cards (ticket page): grid-rows 1fr→0fr collapses without
   measuring content. No height transition — some engines never finish
   interpolating fr tracks (the row would stay open forever); the rotating
   chevron carries the state change instead. */
.fold .fold-wrap{display:grid;grid-template-rows:1fr}
.fold.folded .fold-wrap{grid-template-rows:0fr}
.fold .fold-inner{overflow:hidden;min-height:0}
.fold.folded .card-hd{border-bottom-color:transparent}
.fold-btn{all:unset;cursor:pointer;display:inline-flex;align-items:center;color:var(--fg-3);padding:2px;margin:-2px 0 -2px -2px;border-radius:4px}
.fold-btn:hover{color:var(--fg)}
.fold-btn svg{width:14px;height:14px;transition:transform .18s ease}
.fold.folded .fold-btn svg{transform:rotate(-90deg)}
.fold-title{cursor:pointer;user-select:none}
.card-hd .t-section{flex:1}
.card-hd a{color:var(--nav)}
/* Automated-tests header: title + the action cluster share a line when the
   rail allows it. The cluster (All runs / Cancel / Run / ⋯ / bell) must stay
   on one line — wrapping inside it stacked the bell on its own row after the
   pipeline ding landed. In the 320px rail the whole cluster wraps BELOW the
   title as a unit (flex:0 0 auto), right-aligned, instead of clipping. */
.ci-card .card-hd{flex-wrap:wrap;row-gap:8px;column-gap:8px}
/* Keep the title on one line: when the row is tight the actions wrap below it
   as a group, rather than the title breaking into "AUTOMATED / TESTS". */
.ci-card .card-hd .t-section{white-space:nowrap;flex:1 1 auto}
.ci-hd-actions{display:flex;align-items:center;gap:4px;flex-wrap:nowrap;justify-content:flex-end;margin-left:auto;flex:0 0 auto}
/* "All runs ›" is a wayfinding link, not an identifier — sans, not mono. */
.ci-hd-actions a.t-micro{font-family:var(--sans);font-weight:600;letter-spacing:.02em;white-space:nowrap}
.ci-hd-actions .btn-sm{padding-left:8px;padding-right:8px}
/* ⋯ overflow trigger — 36px floor, same box as the bell, so the two icons
   read as a pair and the extra horizontal padding doesn't blow the row. */
.ci-more{font-size:18px;line-height:1;letter-spacing:1px;width:36px;height:36px;padding:0;justify-content:center}
/* Pipeline-complete bell — same 36px floor + latched .ding-btn.on as the
   session composer. Sits after the ⋯ so the overflow menu stays put. */
.ci-hd-actions .ding-btn{width:36px;height:36px;padding:0;border-radius:var(--r);border:1px solid var(--line);background:var(--surface);color:var(--fg-2);display:grid;place-items:center;cursor:pointer;flex:none}
.ci-hd-actions .ding-btn:hover{color:var(--fg);border-color:var(--fg-3)}
.ci-hd-actions .ding-btn svg{display:block}
.card-bd{padding:16px}

/* ===== META RAIL ===== */
.meta{padding:8px 0;margin:0}
.meta-row{display:grid;grid-template-columns:80px 1fr;gap:10px;align-items:baseline;padding:9px 16px}
.meta-row dt{font-family:var(--sans);font-size:var(--fs-label);font-weight:600;letter-spacing:.04em;text-transform:uppercase;color:var(--fg-3)}
.meta-row dd{margin:0;font-size:15px;min-width:0;overflow-wrap:break-word}
.meta-row dd.mono{font-family:var(--mono);font-size:14px;color:var(--fg-2)}
.who{display:flex;align-items:center;gap:9px;min-width:0}
.who .meta-set-val{min-width:0;overflow-wrap:break-word}
.divider{height:1px;background:var(--line-soft);margin:10px 0}
.meta-set-val{cursor:pointer;border-radius:4px;padding:0 3px;margin:0 -3px}
.meta-set-val:hover{background:var(--raised)}
.unset{display:flex;flex-wrap:wrap;gap:8px;padding:4px 16px 16px}
.unset button{font-family:var(--mono);font-size:13px;color:var(--fg-3);background:none;border:1px dashed var(--line);border-radius:var(--r);padding:6px 11px;cursor:pointer}
.unset button:hover{color:var(--fg);border-color:var(--fg-3);border-style:solid}
.inline-pick{background:var(--sunken);border:1px solid var(--fg-3);border-radius:var(--r);color:var(--fg);font-family:var(--sans);font-size:14px;padding:5px 8px;outline:none}
/* Styled field picker (replaces the native inline <select>) */
.field-picker{position:fixed;z-index:200;width:264px;max-width:calc(100vw - 16px);background:var(--surface);border:1px solid var(--line);border-radius:var(--r-lg);box-shadow:0 18px 50px -18px rgba(0,0,0,.55),0 2px 6px rgba(0,0,0,.28);overflow:hidden;display:flex;flex-direction:column;animation:ui-modal-pop .1s ease}
.field-picker-search{border:0;border-bottom:1px solid var(--line-soft);background:var(--sunken);color:var(--fg);font-family:var(--sans);font-size:14px;padding:11px 13px;outline:none}
.field-picker-search::placeholder{color:var(--fg-3)}
.field-picker-list{max-height:300px;overflow:auto;padding:5px}
.fp-opt{display:block;width:100%;text-align:left;background:none;border:0;color:var(--fg);font-family:var(--sans);font-size:13.5px;padding:9px 10px;border-radius:var(--r);cursor:pointer;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.fp-opt:hover{background:var(--raised)}
.fp-opt.on{background:var(--raised);font-weight:600}
/* Keyboard-highlighted option (↑/↓ nav) — a clear inset marker so it reads as
   "Enter picks this", distinct from hover. */
.fp-opt.fp-hi{background:var(--raised);box-shadow:inset 2px 0 0 var(--nav)}
.fp-opt.on::after{content:"✓";float:right;color:var(--fg-2);margin-left:8px}
/* Multi-select rows carry a real, large checkbox — not a tiny ☐ glyph. */
.fp-opt.fp-multi{display:flex;align-items:center;gap:11px}
.fp-opt.fp-multi.on::after{content:none}
.fp-box{flex:none;width:20px;height:20px;border:2px solid var(--fg-3);border-radius:5px;background:var(--surface);position:relative}
.fp-opt:hover .fp-box{border-color:var(--fg-2)}
.fp-opt.on .fp-box{background:var(--fg);border-color:var(--fg)}
.fp-opt.on .fp-box::after{content:"";position:absolute;left:6px;top:2px;width:5px;height:10px;border:solid var(--surface);border-width:0 2.5px 2.5px 0;transform:rotate(45deg)}
.fp-lab{min-width:0;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Done = a real action bar, not another list row: solid, centered, pinned. */
.fp-done{margin:4px -5px -5px;width:calc(100% + 10px);border-top:1px solid var(--line);border-radius:0;font-weight:700;text-align:center;padding:11px 10px;position:sticky;bottom:-5px;background:var(--fg);color:var(--surface)}
.fp-done:hover{background:color-mix(in srgb,var(--fg) 88%,var(--surface))}
.fp-scrim{position:fixed;inset:0;z-index:199;background:transparent}
.field-picker .fp-foot{flex:none}
.field-picker .fp-foot .fp-done{margin:0;width:100%;position:static}
/* District / Sites picker: a touch wider (names run long), slug = mono id pushed right */
.field-picker.fp-districts{width:320px}
.field-picker.fp-sites{width:360px}
/* Components picker: hierarchical names ("Human Resources -> Employee…")
   need real width — 264px clips every row at the same prefix. What's
   still cut after 480px gets .fp-overflow-tip on hover. */
.field-picker.fp-components{width:480px}
/* Hover tooltip for truncated picker rows. Lives on <body> so it isn't
   clipped by .field-picker's overflow:hidden. 14px — DESIGN.md UI floor. */
.fp-overflow-tip{position:fixed;z-index:300;max-width:min(420px,calc(100vw - 16px));padding:8px 12px;background:var(--surface);color:var(--fg);border:1px solid var(--line);border-radius:var(--r);box-shadow:0 18px 50px -18px rgba(0,0,0,.55),0 2px 6px rgba(0,0,0,.28);font-family:var(--sans);font-size:var(--fs-ui);font-weight:450;line-height:1.5;pointer-events:none;white-space:normal}
.fp-opt.fp-parent{font-family:var(--sans);font-size:12.5px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;color:var(--fg-2);padding:8px 10px 6px;margin-top:4px}
.fp-opt.fp-parent .fp-lab{text-transform:uppercase}
.fp-opt.fp-child{padding-left:28px}
.fp-opt.fp-some .fp-box{background:var(--fg-3);border-color:var(--fg-3)}
.fp-opt.fp-some .fp-box::after{content:"";position:absolute;left:3px;top:6px;width:8px;height:2px;background:var(--surface);border:0;transform:none}
.fp-slug{margin-left:auto;padding-left:12px;font-family:var(--mono);font-size:12px;color:var(--fg-3);flex:none}
.fp-empty{padding:14px 12px;font-family:var(--sans);font-size:13.5px;color:var(--fg-2);line-height:1.5}
/* "site · when" stamp on a district chip: last time the branch hit that site */
.tag .tag-when{font-family:var(--mono);font-size:12px;font-weight:400;letter-spacing:.02em;opacity:.62;white-space:nowrap}

/* Components — tags are sans (they're names, not identifiers) */
.tags{display:flex;flex-wrap:wrap;gap:8px;padding:4px 16px 16px}
.tag{font-family:var(--sans);font-size:13.5px;padding:7px 13px;border-radius:var(--r);border:1px solid var(--line);color:var(--fg-2);cursor:pointer;background:none}
.tag[aria-pressed="true"],.tag.on{background:var(--fg);color:var(--ink);border-color:var(--fg);font-weight:500}
.tag:hover{color:var(--fg)}
.tag[aria-pressed="true"]:hover,.tag.on:hover{color:var(--ink)}
/* Selected-component chips are display-only (editing is via the Add/Edit picker). */
.tag.on{cursor:default}
.tags-empty{font-size:14px;color:var(--fg-2);padding:0 2px 2px}

/* ===== RELEASE NOTES ===== */
/* Area bands stick just below the (sticky, 60px) topbar while their section
   scrolls, so the reader always sees which team's notes they're in. Each band
   lives in its own .rn-area wrapper, so the next section pushes it out. The
   padding-top (not margin) keeps the gap above the label painted over
   scrolled-under content; the notes card must run overflow:visible for
   sticky to engage (release_notes.php sets it inline). */
.rn-area-hd{display:flex;align-items:baseline;gap:10px;padding:28px 0 8px;border-bottom:2px solid var(--line);position:sticky;top:60px;z-index:5;background:var(--surface)}
/* Highlights already has a section label, so the first area band sits closer. */
.rn-highlights .rn-area:first-child .rn-area-hd{padding-top:12px}
@media (max-width:720px){
	/* The phone topbar is position:relative (it scrolls away), so bands stick
	   to the very top there. */
	.rn-area-hd{top:0}
}

/* ===== RELEASE READINESS REPORT ===== */
/* The AI report is markdown rendered into #rr-body — dress it in the
   release-notes design language: section headings as uppercase bands,
   issue keys as quiet mono chips instead of bare accent-colored links. */
#rr-body .md-h{font-family:var(--sans);font-size:var(--fs-label);font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--fg);margin:26px 0 12px;padding-bottom:8px;border-bottom:2px solid var(--line)}
#rr-body .md-h:first-child{margin-top:4px}
#rr-body a[href^="ticket.php"]{font-family:var(--mono);font-size:13px;font-weight:500;color:var(--fg-2);text-decoration:none;border:1px solid var(--line);border-radius:5px;padding:1px 7px;white-space:nowrap}
#rr-body a[href^="ticket.php"]:hover{color:var(--fg);border-color:var(--fg-3)}

/* ===== PROSE / EMPTY ===== */
.prose{font-size:var(--fs-lead);line-height:1.65;color:var(--fg)}
.prose p{margin:0 0 10px}
.prose p:last-child{margin-bottom:0}
.prose code{font-family:var(--mono);font-size:14px;background:var(--sunken);border:1px solid var(--line);border-radius:5px;padding:2px 6px}
/* Rendered markdown on full pages (.prose.md — the release report, ticket
   description/QA fields). The .bubble.md rules are comment-bubble-scoped, so
   page prose gets its own heading/list/link treatment; links use the nav
   accent so issue keys actually read as clickable. */
.prose.md .md-h{font-weight:700;font-size:16px;margin:18px 0 6px}
.prose.md .md-h:first-child{margin-top:0}
.prose.md .md-list{margin:6px 0 10px 22px;padding:0}
.prose.md .md-list li{margin:4px 0}
.prose.md .md-list .md-list{margin:2px 0 4px 22px}
.prose.md .md-line + .md-line{margin-top:3px}
.prose.md .md-gap{height:8px}
.prose.md a{color:var(--nav)}
.prose.md pre.md-pre{font-family:var(--mono);font-size:13px;line-height:1.5;background:var(--sunken);border:1px solid var(--line-soft);border-radius:var(--r);padding:10px 12px;overflow-x:auto;white-space:pre;margin:8px 0}
.prose.md .md-table-wrap{overflow-x:auto;margin:8px 0}
.prose.md table.md-table{border-collapse:collapse;font-size:14px}
.prose.md table.md-table th,.prose.md table.md-table td{border:1px solid var(--line-soft);padding:5px 9px;text-align:left}
.prose.md table.md-table th{background:var(--sunken);font-weight:600}
.empty{border:1px dashed var(--line);border-radius:var(--r);padding:24px;text-align:center}
.empty p{margin:0 0 14px;color:var(--fg-2);font-size:15px;line-height:1.6;max-width:560px;margin-inline:auto}
.edit-area{width:100%;min-height:130px;background:var(--sunken);border:1px solid var(--fg-3);border-radius:var(--r);color:var(--fg);font-family:var(--sans);font-size:var(--fs-lead);line-height:1.6;padding:12px 14px;outline:none;resize:vertical}
/* Issue-page long-text editors (description, testing steps, QA notes,
   release notes, custom body textareas such as QA concerns). View mode
   already sizes to the markdown; edit used to stay at the 130px (~1.5")
   default. JS growFieldEdit matches height to content; this floor/cap
   keeps an empty box comfortable and a huge one from taking the page. */
.edit-area.field-edit{min-height:220px;max-height:70vh;overflow-y:auto}
.edit-actions{display:flex;gap:8px;margin-top:10px}

/* ===== ACTIVITY FEED ===== */
.composer{position:relative;display:flex;flex-direction:column;gap:10px;align-items:stretch;margin-bottom:18px}
.composer textarea{width:100%;background:var(--sunken);border:1px solid var(--line);border-radius:var(--r);color:var(--fg);font-family:var(--sans);font-size:15px;padding:12px 14px;resize:vertical;min-height:124px;outline:none}
.composer textarea::placeholder{color:var(--fg-3)}
.composer textarea:focus{border-color:var(--fg-3)}
.composer .comment-preview{margin-top:0;min-height:80px}
.composer-foot{display:flex;align-items:center;gap:8px}
.composer-hint{color:var(--fg-3)}
.composer-hint b{color:var(--fg-2)}
.composer-foot #comment-preview-btn{margin-left:auto}
.composer-overlay{display:flex;align-items:center;gap:10px;flex-wrap:wrap;padding:2px 0 4px}
.composer-overlay .t-section{flex:none}
.composer-overlay-chips{display:flex;flex-wrap:wrap;gap:6px;align-items:center;flex:1;min-width:0}
.composer-overlay-chips .tag{cursor:pointer;border:0}
.composer-overlay-chips .tag:not(.on){background:var(--sunken);color:var(--fg-2)}
/* @mention autocomplete popover, anchored under the textarea. */
.mention-pop{position:absolute;z-index:60;left:0;top:78px;min-width:240px;max-width:340px;background:var(--raised);border:1px solid var(--line);border-radius:var(--r);box-shadow:0 10px 28px rgba(0,0,0,.30);padding:4px}
.mention-opt{display:flex;align-items:baseline;gap:8px;width:100%;text-align:left;background:none;border:0;border-radius:6px;padding:8px 10px;cursor:pointer;color:var(--fg)}
.mention-opt.on,.mention-opt:hover{background:var(--sunken)}
.mention-h{font-family:var(--mono);font-size:13px;color:var(--nav);font-weight:600}
.mention-n{font-size:13px;color:var(--fg-2)}
/* Rendered markdown inside comment bubbles / preview. */
.bubble.md{white-space:normal}
.bubble.md .md-line + .md-line{margin-top:2px}
.bubble.md .md-gap{height:8px}
.bubble.md .md-h{font-weight:700;font-size:15px;margin:8px 0 2px}
.bubble.md .md-list{margin:4px 0 4px 20px;padding:0}
.bubble.md .md-list li{margin:1px 0}
.bubble.md .md-list .md-list{margin:1px 0 2px 20px}
.bubble.md code{font-family:var(--mono);font-size:13px;background:var(--sunken);border:1px solid var(--line-soft);border-radius:5px;padding:1px 5px}
.bubble.md pre.md-pre{font-family:var(--mono);font-size:13px;line-height:1.5;background:var(--sunken);border:1px solid var(--line-soft);border-radius:var(--r);padding:10px 12px;overflow-x:auto;white-space:pre;margin:6px 0}
.md-pre-wrap{position:relative;margin:6px 0}
.prose.md .md-pre-wrap{margin:8px 0}
.bubble.md .md-pre-wrap{margin:6px 0}
.prose.md .md-pre-wrap > pre.md-pre,
.bubble.md .md-pre-wrap > pre.md-pre{margin:0;padding-right:48px;white-space:pre-wrap;overflow-wrap:anywhere;overflow-x:visible}
.md-copy{position:absolute;top:6px;right:6px;appearance:none;-webkit-appearance:none;margin:0;padding:0;border:none;background:var(--bg,var(--surface));width:36px;height:36px;border-radius:var(--r);color:var(--fg);font-family:var(--sans);font-size:19px;line-height:1;cursor:pointer;display:grid;place-items:center;box-shadow:0 0 0 1px var(--line-soft);z-index:1}
.md-copy:hover,.md-copy:focus-visible{color:var(--nav);background:var(--sunken)}
.md-copy:focus-visible{outline:2px solid var(--fg-3);outline-offset:1px}
.md-copy.is-copied,.md-copy.is-copied:hover{color:var(--s-merge);box-shadow:0 0 0 1px var(--s-merge)}
.bubble.md a{color:var(--nav)}
.bubble.md .md-table-wrap{overflow-x:auto;margin:6px 0}
.bubble.md table.md-table{border-collapse:collapse;font-size:14px}
.bubble.md table.md-table th,.bubble.md table.md-table td{border:1px solid var(--line-soft);padding:5px 9px;text-align:left}
.bubble.md table.md-table th{background:var(--sunken);font-weight:600}
.md-mention{color:var(--nav);font-weight:600}
/* Metrics page: two-column cards + horizontal stage bars. */
.metrics-grid{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-top:16px}
@media (max-width:820px){.metrics-grid{grid-template-columns:1fr}}
.mstage{padding:9px 0}
.mstage + .mstage{border-top:1px solid var(--line-soft)}
.mstage-hd{display:flex;align-items:baseline;justify-content:space-between;gap:12px;margin-bottom:7px}
.mstage-name{font-size:14px;color:var(--fg)}
.mstage-val{font-size:13px;color:var(--fg-2)}
.mstage-val b{color:var(--fg);font-weight:600}
.mbar{height:8px;border-radius:5px;background:var(--sunken);overflow:hidden}
.mbar > span{display:block;height:100%;border-radius:5px;background:var(--nav)}
.mbar.alt > span{background:var(--fg-3)}
/* Programmer report (reports.php): people table grouped by team. */
.wrap.rpt-wrap{max-width:1320px}
.rpt-kinds{margin:16px 0 0}
.rpt-toolbar{display:flex;flex-wrap:wrap;align-items:flex-end;gap:16px;margin:18px 0 8px}
.rpt-date{display:flex;flex-direction:column;gap:4px;font-family:var(--sans);font-size:var(--fs-label);font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--fg-3)}
.rpt-date .fld{width:auto;min-width:160px;min-height:36px;font-size:14px}
.rpt-toolbar .btn{min-height:36px}
.rpt-toolbar .seg{margin-bottom:1px}
.rpt-empty-page{margin:0;font-size:var(--fs-lead);line-height:1.65;color:var(--fg)}
.rpt-table td{padding:12px 16px;vertical-align:top}
.rpt-table th.rpt-num,.rpt-table td.rpt-num{text-align:right;font-family:var(--mono);font-size:15px;font-weight:600;font-variant-numeric:tabular-nums;white-space:nowrap}
.rpt-who{font-size:15px;font-weight:550;color:var(--fg)}
.rpt-email{font-size:13px;color:var(--fg-2);margin-top:4px}
.rpt-empty{color:var(--fg-3)}
.rpt-keys{display:flex;flex-wrap:wrap;gap:8px;align-items:center}
.rpt-key{font-family:var(--mono);font-size:13px;color:var(--fg);background:var(--sunken);border:1px solid var(--line);border-radius:var(--r);padding:6px 10px;text-decoration:none}
.rpt-key:hover{border-color:var(--fg-3);text-decoration:none}
.rpt-key.is-pass{border-color:color-mix(in srgb,var(--s-merge) 50%,var(--line))}
.rpt-key.is-fail{border-color:color-mix(in srgb,var(--danger) 50%,var(--line))}
.rpt-more{display:inline-flex;flex-wrap:wrap;gap:8px;align-items:center}
.rpt-more summary{list-style:none;cursor:pointer;font-family:var(--sans);font-size:13px;font-weight:600;color:var(--nav);padding:6px 10px;min-height:36px;display:inline-flex;align-items:center}
.rpt-more summary::-webkit-details-marker{display:none}
.rpt-more[open] summary{color:var(--fg-2)}
.rpt-wrap .statband .stat{cursor:default}
.rpt-wrap .statband .stat:hover{border-color:var(--line)}
@media (max-width:720px){
	.rpt-date .fld{min-width:0;width:100%}
	.rpt-toolbar .btn{flex:1;justify-content:center}
}
/* Dashboard: count charts that double as filters. Bars are neutral (color
   is state: only the Status chart tints by stage via --bar); the selected bar
   takes the --nav wayfinding accent. Each row is a 36px link target. */
.wrap.dash-wrap{max-width:1560px}
.dash-filters{display:flex;flex-wrap:wrap;align-items:center;gap:8px 10px;min-height:44px;margin:0 0 18px}
.dash-filters-hint{font-size:var(--fs-body);color:var(--fg-2)}
.dash-filters-lbl{font-family:var(--sans);font-size:var(--fs-label);font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--fg-3);margin-right:2px}
.dash-chip{display:inline-flex;align-items:center;gap:6px;min-height:36px;padding:6px 12px;border:1px solid color-mix(in srgb,var(--nav) 45%,var(--line));background:color-mix(in srgb,var(--nav) 10%,var(--surface));border-radius:var(--r);font-size:var(--fs-ui);font-weight:500;color:var(--fg);text-decoration:none}
.dash-chip:hover{border-color:var(--nav);text-decoration:none}
.dash-chip-dim{color:var(--fg-2)}
.dash-chip-x{font-size:16px;line-height:1;color:var(--fg-3);margin-left:2px}
.dash-chip:hover .dash-chip-x{color:var(--danger)}
.dash-clear,.dash-open{display:inline-flex;align-items:center;min-height:36px;padding:6px 10px;font-size:var(--fs-ui);font-weight:500;color:var(--nav);border-radius:var(--r)}
.dash-open{margin-left:auto}
.dash-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:18px;align-items:start;margin:0 0 32px}
.dash-grid > .card{margin:0}
.dash-chart .card-hd .t-micro{margin-left:auto}
.dash-bars{padding:8px 12px 10px}
.dash-row{display:grid;grid-template-columns:minmax(0,1fr) 36px;align-items:center;gap:2px}
.dash-row.is-folded{display:none}
.dash-bar{display:grid;grid-template-columns:minmax(0,44%) 1fr auto;align-items:center;gap:12px;min-height:36px;padding:0 6px;border-radius:var(--r);color:var(--fg);text-decoration:none;--bar:color-mix(in srgb,var(--fg) 22%,transparent)}
.dash-bar:hover{background:var(--sunken);text-decoration:none}
.dash-bar-open{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;border-radius:var(--r);font-size:15px;color:var(--fg-3);text-decoration:none}
.dash-bar-open:hover{background:var(--sunken);color:var(--nav);text-decoration:none}
.dash-row:hover .dash-bar-open{color:var(--fg-2)}
.dash-row:hover .dash-bar-open:hover{color:var(--nav)}
.dash-bar-lbl{font-size:14px;font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dash-bar-track{height:12px;border-radius:6px;background:var(--sunken);overflow:hidden}
.dash-bar-fill{display:block;height:100%;border-radius:6px;background:var(--bar);transition:width .18s ease}
.dash-bar:hover .dash-bar-fill{filter:brightness(1.15)}
.dash-bar-n{font-family:var(--mono);font-size:13px;font-weight:600;font-variant-numeric:tabular-nums;min-width:2.5ch;text-align:right}
.dash-bar.is-active{background:color-mix(in srgb,var(--nav) 10%,transparent)}
.dash-bar.is-active .dash-bar-lbl{font-weight:650}
.dash-bar.is-active .dash-bar-fill{background:var(--nav)}
.dash-chart.has-active .dash-bar:not(.is-active) .dash-bar-lbl{color:var(--fg-2)}
.dash-more{all:unset;display:flex;align-items:center;min-height:36px;padding:0 6px;font-family:var(--sans);font-size:13px;font-weight:600;color:var(--nav);cursor:pointer}
.dash-more:hover{text-decoration:underline}
.dash-empty{margin:0;padding:10px 6px 12px;font-size:var(--fs-body);line-height:1.6;color:var(--fg-2)}
.dash-note{padding:10px 18px 14px;border-top:1px solid var(--line-soft);font-size:13px;line-height:1.5;color:var(--fg-2)}
#dash-body.is-loading{opacity:.6;transition:opacity .12s ease}
@media (max-width:1200px){
	.dash-grid{grid-template-columns:repeat(2,minmax(0,1fr))}
}
@media (max-width:760px){
	.dash-grid{grid-template-columns:1fr}
	.dash-open{margin-left:0}
}
/* Dashboard issue list (dashboard_issues.php): the rows behind a slice. */
.dash-list-head{display:flex;flex-wrap:wrap;align-items:center;gap:8px 10px;margin:0 0 18px}
.dash-list-head .dash-chip{cursor:default}
.dash-list-head .dash-chip:hover{border-color:color-mix(in srgb,var(--nav) 45%,var(--line))}
.dash-list-actions{display:flex;flex-wrap:wrap;gap:10px;margin-left:auto}
.dash-list-scroll{overflow-x:auto}
.dash-list-table{min-width:900px}
.dash-list-table td{padding:12px 16px;vertical-align:top;font-size:15px}
.dash-list-table td:nth-child(2){min-width:260px}
.dash-list-table .dash-key{font-family:var(--mono);font-size:13px;color:var(--nav);white-space:nowrap}
.dash-list-table .dash-title{color:var(--fg);text-decoration:none}
.dash-list-table .dash-title:hover{text-decoration:underline}
.dash-list-table .dash-st{display:inline-flex;align-items:center;gap:8px;white-space:nowrap}
.dash-list-table .dash-st::before{content:'';width:9px;height:9px;border-radius:50%;background:var(--st,var(--fg-3))}
.dash-list-table .dash-num{text-align:right;font-family:var(--mono);font-size:15px;font-weight:600;font-variant-numeric:tabular-nums}
.dash-list-table .dash-dim{color:var(--fg-2)}
/* Runs page: cross-ticket CI batches, each with its job pills. */
.runs-list{display:flex;flex-direction:column;gap:12px;margin-top:16px}
.run-batch{background:var(--surface);border:1px solid var(--line);border-radius:var(--r-lg);padding:14px 16px}
.run-batch-hd{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap}
.run-batch-hd .dot{align-self:center}
.run-tk{color:var(--fg);text-decoration:none;font-size:15px;font-weight:550;display:inline-flex;gap:8px;align-items:baseline;min-width:0}
.run-tk:hover{text-decoration:none;color:var(--nav)}
.run-tk .mono{color:var(--nav);font-size:13px}
.run-tk-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:52ch}
.run-summary{color:var(--fg-2);font-size:13px}
.run-when{margin-left:auto;font-family:var(--mono);font-size:12.5px;color:var(--fg-3)}
.run-jobs{display:flex;flex-wrap:wrap;gap:7px;margin-top:11px}
.run-job{display:inline-flex;align-items:center;gap:7px;background:var(--sunken);border:1px solid var(--line-soft);border-radius:999px;padding:5px 11px;font-size:13px;color:var(--fg);text-decoration:none}
a.run-job:hover{border-color:var(--fg-3);color:var(--fg)}
.run-job-name{font-family:var(--mono);font-size:12.5px}
/* Pipeline live board — branches in a CI batch or a merge right now. */
.pipe-live{margin:8px 0 32px}
.pipe-live-bar{display:flex;flex-wrap:wrap;gap:10px;align-items:center;margin:0 0 16px}
.pipe-chip{display:inline-flex;align-items:baseline;gap:8px;border:1px solid var(--line);background:var(--surface);border-radius:999px;padding:8px 14px;min-height:36px;font-size:15px;color:var(--fg);text-decoration:none;cursor:pointer}
.pipe-chip:hover{border-color:var(--fg-3);text-decoration:none}
.pipe-chip[aria-current="true"]{border-color:var(--fg-2);box-shadow:inset 0 0 0 1px var(--fg-2)}
.pipe-chip b{font-weight:700;letter-spacing:-.02em}
.pipe-chip .pipe-chip-lbl{font-family:var(--sans);font-size:var(--fs-label);font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--fg-3)}
.pipe-branches{display:flex;flex-direction:column;gap:12px}
.pipe-branch{background:var(--surface);border:1px solid var(--line);border-radius:var(--r-lg);padding:18px;box-shadow:var(--shadow)}
.pipe-branch-hd{display:flex;align-items:center;gap:12px;flex-wrap:nowrap;min-width:0}
.pipe-branch-hd .run-tk{flex:1 1 auto;min-width:0}
.pipe-branch-hd .run-tk-title{flex:1;min-width:0;max-width:none}
.pipe-who{display:inline-flex;align-items:center;gap:8px;min-width:0;flex:none}
.pipe-who .av{font-size:12px}
.pipe-who-name{font-size:15px;font-weight:550;color:var(--fg);max-width:18ch;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pipe-branch-now{font-size:15px;font-weight:550;color:var(--fg);white-space:nowrap;flex:none}
.pipe-foot{display:flex;align-items:center;gap:12px;margin-top:11px;flex-wrap:nowrap}
.pipe-foot .run-jobs{margin-top:0;flex:1;min-width:0}
.pipe-branch-age{margin-left:auto;font-size:13.5px;color:var(--fg-2);white-space:nowrap;flex:none}
.run-job.is-now{border-color:color-mix(in srgb,var(--s-autotest) 55%,var(--line));background:color-mix(in srgb,var(--s-autotest) 12%,var(--sunken))}
.run-job.is-now[data-kind="merge"],.run-job.is-now[data-kind="unmerge"]{border-color:color-mix(in srgb,var(--s-merge) 55%,var(--line));background:color-mix(in srgb,var(--s-merge) 12%,var(--sunken))}
/* "Explain this failure" output on the job page. */
.explain-out{margin:12px 14px 0}
/* Small inline edit affordance (e.g. the Branch row on the ticket Details card). */
.meta-edit{all:unset;cursor:pointer;color:var(--fg-3);font-size:12.5px;border-bottom:1px dashed var(--line)}
.meta-edit:hover{color:var(--nav)}
/* Icon-only rail buttons (✎ ⧉): comfortably bigger than the 12.5px text ones. */
.meta-ico{all:unset;cursor:pointer;color:var(--fg-2);font-size:19px;line-height:1;padding:2px 4px;vertical-align:-3px}
.meta-ico:hover{color:var(--nav)}
/* Branch row: name + action icons stay on ONE line (chips wrap beneath). */
.meta-row dd.mono .branch-line{display:flex;align-items:center;gap:2px;flex-wrap:nowrap;min-width:0}
.meta-row dd.mono .branch-line > a{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Conflict warning reads as a problem, not a hint. */
.mc-conflict{color:var(--danger,#f87171)}
/* Rebase-conflict session: one clear instruction above the submit bar. */
.rebase-bar{display:block;padding:8px 14px;font-size:13px;background:color-mix(in srgb,var(--danger) 12%,var(--surface));border-top:1px solid color-mix(in srgb,var(--danger) 35%,transparent);color:var(--fg)}
.rebase-bar code{font-family:var(--mono);font-size:12px}
/* Collapsible in-progress bar (ZD 354311): the Conflicts panel slides away so
   the chat stays usable. The heading stays as a residual indicator. */
.rb-head{display:flex;align-items:flex-start;gap:8px;min-height:36px}
.rb-fold-btn{flex:none;margin-top:0;padding:8px;min-width:36px;min-height:36px;justify-content:center;box-sizing:border-box}
.rb-head-copy{flex:1;min-width:0;cursor:pointer;padding-top:8px;line-height:1.5}
.rb-head-sum{display:none}
.rebase-bar.folded{padding-top:4px;padding-bottom:4px}
.rebase-bar.folded .rb-head{align-items:center}
.rebase-bar.folded .rb-head-copy{padding-top:0;overflow:hidden;white-space:nowrap}
.rebase-bar.folded .rb-head-full{display:none}
.rebase-bar.folded .rb-head-sum{display:inline;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rebase-bar.folded .rb-fold-btn svg{transform:rotate(-90deg)}
.rb-head-count{font-weight:600;color:var(--danger)}
.rebase-bar.rb-ready .rb-head-count{color:var(--s-merge)}
.rebase-bar.folded .rb-conflicts,.rebase-bar.folded .rb-steps{max-height:0;margin-top:0;opacity:0;overflow:hidden;pointer-events:none;border:0;padding:0}
/* Conflicts panel inside the rebase bar (session.php). Sizes follow DESIGN.md:
   state lines are body-tier (14–15px), controls are ui-tier (14px), and
   nothing drops below the 12px floor. */
.rb-conflicts{margin-top:9px;display:flex;flex-direction:column;gap:6px;max-height:360px;overflow-y:auto;transition:max-height .2s ease,margin .2s ease,opacity .15s ease}
.rb-state{display:flex;align-items:flex-start;gap:10px;font-size:14.5px;line-height:1.55}
.rb-state .rb-glyph{flex:none;font-size:16px;line-height:1.4}
.rb-state.rb-working{color:var(--fg)}
.rb-state.rb-working .spinner{margin-top:3px}
.rb-state.rb-need{color:var(--danger)}
.rb-state.rb-need b{color:var(--danger)}
.rb-state.rb-ok{color:var(--s-merge)}
.rb-state.rb-ok code{font-family:var(--mono);font-size:13px}
.rb-row{display:flex;align-items:center;gap:12px;padding:7px 10px;background:color-mix(in srgb,var(--ink) 55%,transparent);border:1px solid color-mix(in srgb,var(--danger) 22%,transparent);border-radius:var(--r)}
.rb-row-dim{opacity:.6}
.rb-path{overflow-wrap:anywhere;font-family:var(--mono);font-size:13px}
.rb-mark{color:var(--danger);font-size:12.5px;font-weight:600;white-space:nowrap}
.rb-acts{display:flex;gap:8px;margin-left:auto;flex:none}
.rb-btn{font-family:var(--sans);font-size:13.5px;font-weight:600;padding:7px 14px;border:1px solid var(--line);background:var(--raised);border-radius:var(--r);cursor:pointer;color:var(--fg);white-space:nowrap}
.rb-btn:hover{border-color:var(--fg-2);background:var(--surface)}
.rb-btn:disabled{opacity:.5;cursor:default}
.rb-btn.rb-agent{border-style:dashed}
.rb-ask{margin-top:2px;display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.rb-hint{font-size:13px}
/* Conflict rows: the path is a button (click = open/expand); tree conflicts
   carry svn's reason and unfold into a per-file listing. */
.rb-row{flex-wrap:wrap}
.rb-main{display:flex;align-items:center;gap:10px;flex-wrap:wrap;min-width:0;flex:1 1 auto}
.rb-path-btn{cursor:pointer;text-align:left;color:var(--fg)}
.rb-path-btn:hover{text-decoration:underline;color:var(--accent)}
.rb-reason{font-size:12.5px;line-height:1.4;flex-basis:100%}
.rb-btn.rb-primary{border-color:color-mix(in srgb,var(--accent) 60%,transparent);background:color-mix(in srgb,var(--accent) 14%,var(--raised))}
.rb-btn.rb-danger{color:var(--danger);border-color:color-mix(in srgb,var(--danger) 45%,transparent)}
.rb-btn.rb-danger:hover{background:color-mix(in srgb,var(--danger) 12%,var(--raised))}
.rb-tree{display:flex;flex-direction:column;gap:4px;margin:-2px 0 4px 18px;padding:8px 10px;border-left:2px solid color-mix(in srgb,var(--danger) 35%,transparent);background:color-mix(in srgb,var(--ink) 35%,transparent);border-radius:0 var(--r) var(--r) 0}
.rb-tree-row{display:flex;align-items:center;gap:10px;padding:4px 2px;flex-wrap:wrap}
.rb-tree-row .rb-path{font-size:12.5px}
.rb-tree-gone .rb-path{text-decoration:line-through;opacity:.55}
.rb-tree-tag{font-size:12px;color:var(--fg-3);white-space:nowrap}
.rb-tree-tag.rb-tree-drop{color:var(--danger);font-weight:600}
.rb-tree-note{font-size:12.5px;padding:2px 2px 4px}
.rb-tree-foot{display:flex;gap:8px;flex-wrap:wrap;padding-top:6px;margin-top:2px;border-top:1px solid var(--line-soft)}
.rb-residue-head{font-size:13.5px;line-height:1.45;padding:6px 2px 0}
.rb-row-residue{border-color:color-mix(in srgb,var(--s-autotest) 45%,transparent)}
.rb-row-residue .rb-mark{color:var(--s-autotest)}
.diff-section.needs-resolving .diff-sec-head{box-shadow:inset 3px 0 0 var(--danger)}
.rb-in-changes{margin:8px 12px 10px;max-height:none}
.rebase-bar.rb-done{background:color-mix(in srgb,var(--s-merge) 10%,var(--surface));border-top-color:color-mix(in srgb,var(--s-merge) 35%,transparent)}
.rebase-bar.rb-dead{background:var(--surface);border-top-color:var(--line);color:var(--fg-2)}
.rb-done-acts{margin-top:10px}
/* Finishing stage: commit → swap, narrated as steps inside the bar. */
.rb-steps{margin-top:9px;display:flex;flex-direction:column;gap:7px}
.rb-step{display:flex;align-items:center;gap:10px;font-size:14px;line-height:1.5}
.rb-step .rb-step-glyph{flex:none;width:16px;text-align:center;font-weight:700}
.rb-step .spinner{flex:none}
.rb-step-done{color:var(--s-merge)}
.rb-step-active{color:var(--fg)}
.rb-step-todo{color:var(--fg-3)}
.rb-step code{font-family:var(--mono);font-size:12.5px}
/* Raw commit log stays behind a disclosure in rebase mode — the bar narrates. */
.rb-log-row{padding:4px 14px;background:var(--surface);border-top:1px solid var(--line)}
.rb-log-toggle{all:unset;cursor:pointer;font-size:12.5px;color:var(--fg-3)}
.rb-log-toggle:hover{color:var(--fg-2)}
/* Background rebase pill (ticket page): the rebase keeps running while the
   person keeps working; the pill carries live progress and the end state. */
.rb-pill{position:fixed;left:18px;bottom:18px;z-index:120;display:flex;align-items:center;gap:10px;max-width:min(440px,calc(100vw - 36px));padding:10px 16px;font-family:var(--sans);font-size:13.5px;font-weight:500;color:var(--fg);background:var(--raised);border:1px solid var(--line);border-radius:999px;box-shadow:0 8px 28px rgba(0,0,0,.4);cursor:pointer;animation:rb-pill-in .28s cubic-bezier(.2,.9,.3,1.2)}
.rb-pill .rb-pill-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rb-pill .rb-pill-glyph{flex:none}
.rb-pill:hover{border-color:var(--fg-2)}
.rb-pill-conflicts{border-color:color-mix(in srgb,var(--danger) 55%,transparent);background:color-mix(in srgb,var(--danger) 14%,var(--raised))}
.rb-pill-done{border-color:color-mix(in srgb,var(--s-merge) 55%,transparent);background:color-mix(in srgb,var(--s-merge) 12%,var(--raised))}
.rb-pill-error{border-color:color-mix(in srgb,var(--danger) 55%,transparent)}
.rb-pill .rb-pill-x{flex:none;margin-left:2px;padding:0 4px;color:var(--fg-3);font-size:16px;line-height:1;border-radius:50%}
.rb-pill .rb-pill-x:hover{color:var(--fg)}
@keyframes rb-pill-in{from{transform:translateY(14px);opacity:0}to{transform:translateY(0);opacity:1}}
/* Hand-edit modal for one conflicted file (CodeView editor inside) */
.resolve-overlay{position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:90;display:flex;align-items:center;justify-content:center}
.resolve-panel{width:min(1200px,94vw);height:min(84vh,940px);display:flex;flex-direction:column;background:var(--surface);border:1px solid var(--line);border-radius:var(--r-lg);padding:14px;gap:10px}
.resolve-head{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;font-size:14px}
.resolve-legend{margin-left:auto;font-family:var(--mono);font-size:12px}
.resolve-mount{flex:1;min-height:0;display:flex;flex-direction:column;border:1px solid var(--code-line);border-radius:var(--r);overflow:hidden;background:var(--code-bg)}
/* CodeView.editor paints a highlight <pre> absolutely over a transparent
   textarea. A flex column + flex:1 on that <pre> sized the overlay as
   flex-basis:0% (Zendesk 354647) so the Edit-file modal showed plain text.
   Once CodeView owns the mount, treat it as a positioned box — same geometry
   as the code-browser editor (#cb-editor-mount). The no-CodeView fallback
   textarea still flex-grows via the rule below. */
.resolve-mount.cv-editwrap{position:relative;display:block;height:100%;min-height:0}
.resolve-mount.cv-editwrap .cv-ta,.resolve-mount.cv-editwrap .cv-hl,.resolve-mount.cv-editwrap .cv-gutter{flex:none}
.resolve-mount .cv-ta,.resolve-mount .cv-hl{flex:1;min-height:0}
.resolve-foot{display:flex;align-items:center;gap:10px;font-size:13px}
/* SVG variant: emoji-presentation glyphs (⤴ etc.) render huge and break the
   row, so icon buttons that need a symbol use an inline svg sized to the text. */
.meta-ico .mi-svg{width:15px;height:15px;display:block}
.meta-ico:has(.mi-svg){padding:2px 4px;vertical-align:-2px;display:inline-block}
.feed{position:relative;padding-left:22px}
.feed::before{content:"";position:absolute;left:5px;top:6px;bottom:6px;width:1px;background:var(--line-soft)}
.ev{position:relative;padding:11px 0}
.ev::before{content:"";position:absolute;left:-20px;top:17px;width:8px;height:8px;border-radius:50%;background:var(--line);border:1px solid var(--surface)}
.ev.is-comment::before{background:var(--fg-3)}
.ev-line{display:flex;align-items:baseline;gap:9px;flex-wrap:wrap;font-size:14px;color:var(--fg-2)}
.ev-line b{color:var(--fg);font-weight:600;font-size:15px}
.ev-line .chg{color:var(--fg-2)}
.ev-line a{color:var(--nav)}
.ev-line time{font-family:var(--mono);font-size:12.5px;color:var(--fg-3);margin-left:auto}
.bubble{margin-top:8px;background:var(--raised);border:1px solid var(--line-soft);border-radius:var(--r);padding:12px 14px;font-size:15px;line-height:1.6;white-space:pre-wrap}
.feed-empty{color:var(--fg-2);font-size:14px;padding:6px 0}
/* Before/after diff of a long-text field edit (activity "Changes" events). */
.fh-diff{font-family:var(--mono);font-size:13px;line-height:1.7;padding:8px 10px;overflow-x:auto}
.fh-line{white-space:pre-wrap;padding:0 4px;border-radius:3px}
.fh-line.t-add{color:var(--s-merge);background:color-mix(in srgb,var(--s-merge) 11%,transparent)}
.fh-line.t-del{color:var(--danger);background:color-mix(in srgb,var(--danger) 10%,transparent)}
.fh-line.t-gap{color:var(--fg-3)}
/* Comment replies: one level of nesting under the parent comment. */
.ev-replies{margin:10px 0 0 18px;padding-left:14px;border-left:2px solid var(--line-soft);display:flex;flex-direction:column;gap:10px}
.ev-reply .bubble{margin-top:6px;padding:10px 12px;font-size:14.5px}
.ev-comment-acts{display:inline-flex;align-items:baseline;gap:2px;flex:none}
.ev-reply-btn{border:0;background:none;color:var(--fg-3);cursor:pointer;font-size:12.5px;padding:1px 5px;border-radius:4px;flex:none;opacity:.65}
.ev:hover .ev-reply-btn,.ev-reply-btn:focus-visible{opacity:1}
.ev-reply-btn:hover{color:var(--fg);background:var(--raised)}
.ev-reply-btn.danger:hover{color:var(--danger)}
a.ev-fix-link{text-decoration:none;opacity:1;color:var(--fg-2)}
a.ev-fix-link:hover{color:var(--fg)}
.ev-edited{font-size:12.5px;color:var(--fg-3);font-style:italic}
.ev-edit{position:relative;margin-top:8px}
.ev-edit .edit-area{min-height:100px}
.ev-edit .mention-pop{top:auto}
/* "Replying to …" chip on the composer (reply mode). */
.reply-chip{display:flex;align-items:center;gap:6px;font-size:13px;color:var(--fg-2);background:var(--raised);border:1px solid var(--line-soft);border-radius:var(--r);padding:6px 10px}
.reply-chip b{color:var(--fg)}
.reply-chip .opt-x{margin-left:auto}

/* ===== SESSION LANES ===== */
.lane{display:block;width:100%;text-align:left;border:none;background:none;padding:14px 16px;border-bottom:1px solid var(--line-soft);cursor:pointer;color:inherit;text-decoration:none}
.lane:last-of-type{border-bottom:none}
.lane:hover{background:var(--raised);text-decoration:none}
.lane[aria-current="true"]{background:var(--raised);box-shadow:inset 3px 0 0 var(--fg)}
.lane-top{display:flex;align-items:center;gap:10px}
.dot{width:8px;height:8px;border-radius:50%;flex:none}
.dot.run{background:var(--s-autotest);box-shadow:0 0 0 3px color-mix(in srgb,var(--s-autotest) 20%,transparent)}
.dot.ok{background:var(--s-merge)}
.dot.idle{background:var(--fg-3)}
.dot.err{background:var(--danger)}
.dot.rev{background:var(--s-qa);box-shadow:0 0 0 3px color-mix(in srgb,var(--s-qa) 20%,transparent)}
.dot.ex{background:var(--s-autotest)}
.lane-name{font-size:15px;font-weight:550;flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--fg)}
.lane-rename{opacity:.55;border:0;background:none;color:var(--fg-3);cursor:pointer;font-size:15px;padding:1px 4px;line-height:1;flex:none;border-radius:4px}
.lane:hover .lane-rename,.lane:focus-within .lane-rename{opacity:1}
.lane-rename:hover{color:var(--fg);background:var(--surface)}
/* Always faintly visible (not hover-gated like rename) — the delete affordance
   needs to be discoverable, per pilot feedback. Brightens on lane hover. */
.lane-discard-x{font-size:19px;opacity:.5}
.lane:hover .lane-discard-x,.lane:focus-within .lane-discard-x{opacity:1}
.lane-discard-x:hover{color:var(--danger);background:var(--surface);opacity:1}
.lane-rename-input{width:100%;background:var(--surface);border:1px solid var(--fg-3);border-radius:4px;color:var(--fg);font:inherit;font-weight:500;padding:1px 5px;outline:none}
.title-edit{opacity:.55;border:0;background:none;color:var(--fg-3);cursor:pointer;font-size:12px;padding:0 4px;line-height:1;flex:none;border-radius:4px}
.title-edit:hover{opacity:1;color:var(--fg);background:var(--raised)}
.lane-sub{font-family:var(--mono);font-size:13px;color:var(--fg-3);margin-top:6px;display:flex;gap:12px;align-items:center;flex-wrap:wrap}
.lane-when{margin-left:auto;color:var(--fg-3);white-space:nowrap}
.add{color:var(--s-merge)}.del{color:var(--danger)}
.lane-last{font-size:13.5px;color:var(--fg-2);margin-top:7px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* Dictation mic: pulses red while listening. */
.mic-btn.listening{color:var(--danger)}
.mic-btn.listening svg{animation:mic-pulse 1.15s ease-in-out infinite}
@keyframes mic-pulse{0%,100%{opacity:1}50%{opacity:.35}}

/* CI-card override: accept a failed run as a false positive without leaving. */
.lane-ovr{flex:none;border:1px solid color-mix(in srgb,var(--s-autotest) 45%,transparent);background:color-mix(in srgb,var(--s-autotest) 12%,transparent);color:var(--fg);font:inherit;font-size:12px;font-weight:600;padding:2px 8px;border-radius:20px;cursor:pointer;white-space:nowrap;line-height:1.4}
.lane-ovr:hover{background:color-mix(in srgb,var(--s-autotest) 24%,transparent)}
.ovr-mark{flex:none;color:var(--s-autotest);font-weight:600;font-size:12.5px}
/* Fold toggle: latest CI run / latest sessions up front, older items hidden. */
.ci-prev-toggle{display:block;width:100%;text-align:center;padding:9px 16px;border:none;border-top:1px solid var(--line-soft);background:none;color:var(--fg-2);font-family:var(--sans);font-size:var(--fs-label);font-weight:600;cursor:pointer}
.ci-prev-toggle:hover{background:var(--raised);color:var(--fg)}
.ci-prev .lane-group-hd{padding:12px 16px 8px}

/* ===== TICKET LIST (index) ===== */
.page-head{padding:30px 0 8px}
.page-head h1{margin:0 0 8px;font-size:var(--fs-display);font-weight:700;letter-spacing:-.02em}
.page-head-row{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin:0 0 8px}
.page-head-row h1{margin:0;flex:1;min-width:0}
.page-head-row .btn{flex:none;margin-left:auto}
.page-head .sub{color:var(--fg-2);font-size:var(--fs-lead)}
.statband{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;margin:22px 0}
.statband.cols-5{grid-template-columns:repeat(5,1fr)}
.stat{text-align:left;border:1px solid var(--line);background:var(--surface);border-radius:var(--r-lg);padding:18px 20px;cursor:pointer;box-shadow:var(--shadow)}
.stat:hover{border-color:var(--fg-3)}
.stat[aria-current="true"]{border-color:var(--fg-2);box-shadow:inset 0 0 0 1px var(--fg-2)}
.stat .lbl{font-family:var(--sans);font-size:var(--fs-label);font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--fg-3);display:block}
.stat .n{font-size:30px;font-weight:700;margin-top:8px;display:block;letter-spacing:-.02em;line-height:1}
.lane-group{margin-top:30px}
.lane-group-hd{display:flex;align-items:center;gap:10px;padding:0 2px 10px}
.lane-group-hd .t-section{color:var(--fg-2)}
.lane-group-hd .rule{flex:1;height:1px;background:var(--line-soft)}
/* Ticket rows are the main content — they breathe (20px pad) and the title
   leads at 17px/550. Meta is sans (sentences), identifiers stay mono via .mono. */
.trow{display:flex;align-items:center;gap:18px;border:1px solid var(--line);border-radius:var(--r-lg);background:var(--surface);padding:18px 18px;margin-bottom:10px;box-shadow:var(--shadow);color:inherit}
.trow:hover{border-color:var(--fg-3);text-decoration:none}
.trow .rail{width:3px;align-self:stretch;border-radius:2px;background:var(--stage,transparent);flex:none;margin:-2px 0}
.trow .tkey{font-family:var(--mono);font-size:13px;color:var(--fg-2);background:var(--sunken);border:1px solid var(--line);border-radius:var(--r);padding:6px 10px;flex:none}
.trow .tmain{flex:1;min-width:0}
.trow .ttitle{font-size:17px;font-weight:550;letter-spacing:-.01em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.trow .tmeta{font-family:var(--sans);font-size:13.5px;color:var(--fg-3);margin-top:6px;display:flex;gap:9px;flex-wrap:wrap;align-items:center}
.trow .lf{display:none}
.lf-wrap[data-show~="priority"] .lf-priority,
.lf-wrap[data-show~="version"] .lf-version,
.lf-wrap[data-show~="tester"] .lf-tester,
.lf-wrap[data-show~="reviewer"] .lf-reviewer,
.lf-wrap[data-show~="component"] .lf-component,
.lf-wrap[data-show~="label"] .lf-label,
.lf-wrap[data-show~="qa"] .lf-qa,
.lf-wrap[data-show~="type"] .lf-type,
.lf-wrap[data-show~="sessions"] .lf-sessions,
.lf-wrap[data-show~="zd"] .lf-zd,
.lf-wrap[data-show~="branch"] .lf-branch,
.lf-wrap[data-show~="jira"] .lf-jira,
.lf-wrap[data-show~="created"] .lf-created,
.lf-wrap[data-show~="updated"] .lf-updated{display:inline}
.trow .lf-version,.trow .lf-jira{font-family:var(--mono);font-size:13px;color:var(--fg-2)}
.trow .lf-more{color:var(--fg-2)}
.show-row{display:flex;flex-wrap:wrap;gap:8px;margin-top:12px;align-items:center}
.show-toggle{font-family:var(--sans);font-size:var(--fs-ui);font-weight:500;color:var(--fg-2);background:var(--raised);border:1px solid var(--line);border-radius:var(--r);padding:8px 12px;cursor:pointer;min-height:36px;display:inline-flex;align-items:center;gap:8px;flex:none;line-height:1;transition:border-color .12s,color .12s,background .12s}
.show-toggle:hover{border-color:var(--fg-3);color:var(--fg)}
.show-toggle[aria-expanded="true"]{border-color:var(--fg-3);background:var(--surface);color:var(--fg)}
.show-toggle svg{flex:none;display:block}
.show-f{font-family:var(--sans);font-size:13px;font-weight:500;color:var(--fg-2);background:var(--raised);border:1px solid var(--line);border-radius:var(--r);padding:6px 11px;cursor:pointer;min-height:36px;transition:border-color .12s,color .12s,background .12s}
.show-f:hover{border-color:var(--fg-3);color:var(--fg)}
.show-f.on{border-color:var(--fg-3);background:var(--surface);color:var(--fg)}
.trow .row-who{display:inline-flex;align-items:center;gap:8px;flex:none;min-width:0}
.trow .who-name{font-size:13px;color:var(--fg-2);max-width:130px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.stage-tag{display:inline-flex;align-items:center;gap:7px;font-family:var(--sans);font-size:var(--fs-label);font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--stage);flex:none}
.stage-tag .d{width:7px;height:7px;border-radius:50%;background:var(--stage)}

/* priority badges — fixed 1–5 scale, 5 = most urgent */
.pri{font-family:var(--mono);font-size:12.5px;font-weight:600;border-radius:var(--r);padding:2px 7px;white-space:nowrap}
.pri.p5{color:#f0564f;background:rgba(240,86,79,.12)}
.pri.p4{color:#e8923f;background:rgba(232,146,63,.12)}
.pri.p3{color:#4f9cf0;background:rgba(79,156,240,.10)}
.pri.p2,.pri.p1{color:var(--fg-3);background:rgba(128,140,155,.12)}

/* dashboard: needs-you strip, release progress, live pipeline, row warnings */
.needs-you,.rel-progress{display:flex;align-items:center;gap:14px;padding:14px 18px;margin-top:16px;flex-wrap:wrap}
.rel-progress{text-decoration:none;color:inherit}
.needs-group{display:inline-flex;align-items:center;gap:8px;flex-wrap:wrap}
.needs-lbl{font-family:var(--sans);font-size:var(--fs-label);font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--fg-3)}
.needs-chip{font-family:var(--mono);font-size:13px;text-decoration:none;color:var(--fg-2);background:var(--sunken);border:1px solid var(--line);border-radius:var(--r);padding:6px 11px}
.needs-chip:hover{color:var(--fg);border-color:var(--fg-3)}
.trow .chat-run{color:var(--s-autotest)}
.trow .chat-rev{color:var(--s-qa)}
.your-chats{margin-top:16px;padding:0}
.your-chats .yc-hd{display:flex;align-items:baseline;gap:10px;padding:15px 18px 0}
.your-chats .yc-hd .t-section{flex:none}
.yc-rows{display:flex;flex-direction:column;padding:8px 0 10px}
.yc-row{display:flex;align-items:center;gap:12px;padding:10px 18px;min-height:36px;text-decoration:none;color:inherit}
.yc-row:hover{background:var(--raised);text-decoration:none}
.yc-key{font-family:var(--mono);font-size:13px;color:var(--fg-2);flex:none}
.yc-state{font-family:var(--sans);font-size:15px;font-weight:550;color:var(--fg);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1}
.yc-when{font-size:13px;color:var(--fg-2);flex:none}
.rel-bar{display:flex;flex:1;min-width:120px;height:6px;border-radius:3px;overflow:hidden;background:var(--sunken)}
.rel-bar .rb{height:100%}
.rel-bar .rb.merged{background:#3f8f5f}
.rel-bar .rb.active{background:#e8923f}
.rel-bar .rb.open{background:var(--line)}
.pipeline-now{margin-top:16px;padding:0}
.pipeline-now .card-hd{padding:0}
.pipeline-now .card-hd .t-section{flex:none}
.pipeline-now .pn-toggle{display:flex;align-items:center;gap:12px;width:100%;padding:14px 18px;cursor:pointer;min-height:44px;font:inherit;color:inherit;background:none;border:0;text-align:left}
.pipeline-now .pn-toggle:hover .fold-btn{color:var(--fg)}
.pipeline-now .pn-summary{font-family:var(--mono);font-size:var(--fs-meta);font-weight:500;color:var(--fg-2);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pn-rows{display:flex;flex-direction:column;gap:4px;padding:4px 18px 14px;min-width:0}
.pn-row{display:flex;align-items:center;gap:9px;text-decoration:none;color:var(--fg-2);font-size:13.5px;padding:3px 0}
.pn-row:hover .pn-label{color:var(--fg)}
.pn-kind{font-family:var(--sans);font-size:12px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;border-radius:var(--r);padding:2px 7px;background:var(--sunken);color:var(--fg-3);flex:none}
.pn-kind.ci{color:#4f9cf0}
.pn-kind.autofix{color:#e8923f}
.pn-kind.agent_turn{color:#3f8f5f}
.pn-kind.merge{color:#8f5fbf}
.pn-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pn-since{font-family:var(--mono);font-size:12.5px;color:var(--fg-3);margin-left:auto;flex:none}
.row-warn{color:#e8923f}
.row-warn.ci-red{color:#f0564f}
.stat-sub{font-size:12.5px;font-weight:600;font-family:var(--mono);margin-left:8px;color:var(--fg-3)}
.stat-sub.warn{color:#f0564f}

/* release chips in the topbar — latest shipped + in regression + next RC */
.rel-group{display:inline-flex;gap:6px;align-items:center;flex:none}
.rel-chip{font-family:var(--mono);font-size:12.5px;font-weight:600;text-decoration:none;border:1px solid var(--line);border-radius:var(--r);padding:5px 9px;color:#3f8f5f;white-space:nowrap}
.rel-chip.reg{color:var(--s-autotest);border-color:color-mix(in srgb,var(--s-autotest) 40%,var(--line))}
.rel-chip.next{color:var(--nav);border-color:color-mix(in srgb,var(--nav) 40%,var(--line))}
.rel-chip:hover{border-color:var(--fg-3)}

/* released state on fix-version chips (admin field lists) */
/* Fix-version chip controls: released/upcoming state + default-on-new star.
   Real hit targets (24px) with hover affordance — not bare 12px glyphs. */
.opt-chip .chip-ic{all:unset;box-sizing:border-box;cursor:pointer;width:24px;height:24px;display:inline-flex;align-items:center;justify-content:center;border-radius:6px;font-size:15px;line-height:1;color:var(--fg-3);transition:background .12s,color .12s}
.opt-chip .chip-ic:hover{background:color-mix(in srgb,var(--fg) 12%,transparent);color:var(--fg)}
.opt-chip .chip-ic:focus-visible{outline:2px solid var(--fg-2);outline-offset:1px}
.opt-chip .chip-state.on{color:var(--s-merge)}
.opt-chip .chip-state.reg{color:var(--s-autotest)}
.opt-chip .chip-star.on{color:var(--s-autotest)}
.opt-chip.released{border-color:color-mix(in srgb,var(--s-merge) 45%,var(--line))}

/* drag-to-reorder rows (custom fields + sidebar layout) */
.drag-grip{cursor:grab;color:var(--fg-3);font-size:14px;letter-spacing:-2px;user-select:none;padding:4px 2px}
.cf-row.dragging{opacity:.45}
.rail-row{max-width:100%}
.rail-row.rail-hidden .cf-label{color:var(--fg-3);text-decoration:line-through}
.row-actions{margin-left:auto;display:inline-flex;align-items:center;gap:8px}
.row-actions .iconbtn{width:28px;height:28px;font-size:14px}
.row-actions .iconbtn.danger:hover{color:#f0564f;border-color:#f0564f}
.rail-state{min-width:44px;text-align:right}

/* linked-Zendesk count — customer-impact signal on list rows */
.zd-badge{font-family:var(--mono);font-size:12.5px;font-weight:600;border-radius:var(--r);padding:2px 7px;white-space:nowrap;color:#3f8f5f;background:rgba(63,143,95,.12)}
.zd-badge.hot{color:#f0564f;background:rgba(240,86,79,.12)}

/* duplicate-detection hint under the new-ticket title */
.dupe-hint{margin-top:8px;font-size:13.5px;color:var(--fg-2)}
.dupe-hint .dupe-lbl{color:var(--fg-2)}
.dupe-hint a{color:var(--fg-2);text-decoration:none;border:1px solid var(--line);border-radius:var(--r);padding:4px 9px;margin-right:4px;display:inline-flex;gap:6px;align-items:center}
.dupe-hint a:hover{border-color:var(--fg-3)}
.dupe-hint .dupe-st{color:var(--fg-3);font-size:12.5px}

/* Unlinked-Zendesk suggestions on the new-issue form (checked = link on create). */
.zd-hint{margin-top:8px;font-size:13px;color:var(--fg-2);border:1px solid color-mix(in srgb,#E8964B 35%,var(--line));background:color-mix(in srgb,#E8964B 6%,transparent);border-radius:var(--r);padding:9px 11px}
.zd-hint-hd{margin-bottom:5px}
.zd-hint-hd b{color:color-mix(in srgb,#E8964B 75%,var(--fg))}
.zd-hint-row{display:flex;gap:8px;align-items:baseline;padding:3px 0;cursor:pointer}
/* Beat `.create input{width:100%;padding:12px…}` — a checkbox must stay a checkbox. */
.create .zd-hint-row input[type=checkbox]{width:auto;min-height:0;padding:0;accent-color:#E8964B;flex:none;position:relative;top:2px}
.zd-hint-row input{accent-color:#E8964B;flex:none;position:relative;top:2px}
.zd-hint-row a{color:var(--fg);font-family:var(--mono);font-size:12.5px;text-decoration:none;white-space:nowrap}
.zd-hint-row a:hover{color:var(--nav)}
.zd-hint-subj{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.zd-hint-meta{color:var(--fg-3);font-size:12px;white-space:nowrap}
.zd-hint-ft{color:var(--fg-3);font-size:12px;margin-top:5px;border-top:1px solid var(--line-soft);padding-top:5px}

/* Bare numeric inputs (admin scaling knobs, per-issue counts) get the app's
   input surface instead of raw browser chrome. */
input[type="number"]{background:var(--sunken);border:1px solid var(--line);border-radius:var(--r);color:var(--fg);font-family:var(--sans);font-size:var(--fs-ui);padding:6px 8px;outline:none}
input[type="number"]:focus{border-color:var(--fg-3)}

/* create card — inputs clear the 44px floor */
.create{border:1px solid var(--line);border-radius:var(--r-lg);background:var(--surface);box-shadow:var(--shadow);padding:18px}
.create input,.create textarea{width:100%;background:var(--sunken);border:1px solid var(--line);border-radius:var(--r);color:var(--fg);font-family:var(--sans);font-size:var(--fs-lead);padding:12px 14px;outline:none}
.create input:focus,.create textarea:focus{border-color:var(--fg-3)}
.create textarea{resize:vertical;min-height:110px;margin-top:10px;line-height:1.55}
.create-foot{display:flex;align-items:center;gap:10px;margin-top:14px;flex-wrap:wrap}

/* New-issue modal — prompt-first composer, opened from the header + */
.btn-new{gap:6px}
.btn-new svg{width:15px;height:15px}
.ns-overlay{position:fixed;inset:0;background:color-mix(in srgb,#000 58%,transparent);display:flex;align-items:flex-start;justify-content:center;z-index:1000;padding:56px 20px 24px;overflow-y:auto;animation:ui-modal-fade .12s ease}
.ns-dialog{position:relative;width:min(720px,100%);background:var(--surface);border:1px solid var(--line);border-radius:var(--r-lg);box-shadow:0 24px 70px -20px rgba(0,0,0,.6),0 2px 8px rgba(0,0,0,.3);animation:ui-modal-pop .14s ease}
.ns-dialog-hd{display:flex;align-items:center;justify-content:space-between;padding:15px 18px;border-bottom:1px solid var(--line-soft)}
.ns-dialog-hd h2{font-size:var(--fs-lead);font-weight:600;letter-spacing:-.01em}
.ns-dialog .create{border:0;box-shadow:none;background:none;padding:18px;border-radius:0;display:flex;flex-direction:column;gap:12px}
body.ns-open{overflow:hidden}
/* A linked ZD ticket owns creation — the card's actions replace these. */
#new-session-card.zd-active #ns-file,#new-session-card.zd-active #ns-build{display:none}
#new-session-card.zd-active .ns-kbd{display:none}
:root[data-theme="light"] .ns-pick{background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%236B7280' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>")}
#new-session-card.drag{outline:2px dashed var(--fg-3);outline-offset:-6px;border-radius:var(--r-lg)}

.create input.ns-title{background:var(--sunken);border:1px solid var(--line);border-radius:var(--r);padding:12px 14px;font-size:var(--fs-lead);font-weight:550;letter-spacing:-.015em;min-height:44px;line-height:1.35}
.create input.ns-title:focus{border-color:var(--fg-3)}
.create input.ns-title::placeholder{color:var(--fg-3);font-weight:450}
.ns-dialog .create textarea#ns-desc{margin-top:0}

.ns-box{background:var(--sunken);border:1px solid var(--line);border-radius:var(--r-lg);padding:12px 14px 10px;display:flex;flex-direction:column;gap:8px}
.ns-box:focus-within{border-color:var(--fg-3)}
.ns-box .attach-tray{padding:0}
.create .ns-box textarea{background:transparent;border:0;border-radius:0;padding:4px 2px 8px;min-height:120px;margin:0;resize:none;font-size:var(--fs-lead);line-height:1.6;field-sizing:content}
.create .ns-box textarea::placeholder{color:var(--fg-3)}
.create .ns-box textarea:focus{border-color:transparent}
.ns-box-foot{display:flex;align-items:center;gap:8px;flex-wrap:wrap;min-height:36px}
.ns-box-foot .ns-attach{width:36px;height:36px;flex:none}
.ns-pick{appearance:none;-webkit-appearance:none;background:var(--surface);border:1px solid var(--line);border-radius:999px;color:var(--fg);font-family:var(--sans);font-size:var(--fs-ui);font-weight:500;height:36px;padding:0 28px 0 12px;outline:none;cursor:pointer;max-width:220px;background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%238A93A1' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>");background-repeat:no-repeat;background-position:right 10px center}
.ns-pick:hover,.ns-pick:focus{border-color:var(--fg-3);color:var(--fg)}
.ns-kbd{margin-left:auto;font-family:var(--sans);font-size:var(--fs-label);font-weight:600;color:var(--fg-2);letter-spacing:.02em;white-space:nowrap}
.ns-dialog .create-foot{margin-top:2px}
.create-foot .ns-meta{width:auto;min-height:36px}

/* New-issue Components — required when the same field gates automation submit. */
.ns-comp{position:relative;display:flex;flex-direction:column;gap:8px}
.ns-comp-label{font-family:var(--sans);font-size:var(--fs-label);font-weight:600;letter-spacing:.04em;text-transform:uppercase;color:var(--fg-3)}
.ns-comp-req{color:var(--danger);letter-spacing:0}
.ns-comp-box{display:flex;flex-wrap:wrap;gap:8px;align-items:center;background:var(--sunken);border:1px solid var(--line);border-radius:var(--r);padding:4px 8px;min-height:44px}
.ns-comp-box:focus-within{border-color:var(--fg-3)}
.ns-comp.ns-comp-bad .ns-comp-box{border-color:var(--danger)}
.create .ns-comp-box input{flex:1 1 160px;width:auto;min-width:140px;min-height:36px;background:transparent;border:0;padding:6px 8px;font-size:var(--fs-body)}
.create .ns-comp-box input:focus{border-color:transparent}
.ns-comp-token{display:inline-flex;align-items:center;gap:2px;max-width:100%;font-family:var(--sans);font-size:13.5px;line-height:1.3;padding:0 2px 0 12px;min-height:36px;border-radius:var(--r);border:1px solid var(--line);color:var(--fg);background:var(--surface)}
.ns-comp-token button{width:36px;height:36px;flex:none;border:0;background:none;color:var(--fg-2);cursor:pointer;font-size:16px;border-radius:var(--r)}
.ns-comp-token button:hover{color:var(--fg)}
.ns-comp-list{position:absolute;left:0;right:0;top:100%;margin-top:4px;z-index:6;max-height:220px;overflow:auto;background:var(--surface);border:1px solid var(--line);border-radius:var(--r-lg);box-shadow:0 18px 50px -18px rgba(0,0,0,.55),0 2px 6px rgba(0,0,0,.28);padding:5px}
.ns-comp-opt{display:block;width:100%;text-align:left;background:none;border:0;color:var(--fg);font-family:var(--sans);font-size:var(--fs-body);padding:9px 10px;border-radius:var(--r);cursor:pointer;min-height:36px}
.ns-comp-opt:hover,.ns-comp-opt.on{background:var(--raised)}
.ns-comp-empty{padding:12px;font-family:var(--sans);font-size:var(--fs-ui);color:var(--fg-2)}
.ns-comp-err{margin:0;font-family:var(--sans);font-size:var(--fs-ui);font-weight:500;line-height:1.45;color:var(--danger)}

/* Staged progress overlay for multi-step create (Draft & solve) */
.ns-working{position:absolute;inset:0;z-index:5;display:flex;align-items:center;justify-content:center;background:color-mix(in srgb,var(--surface) 90%,transparent);border-radius:var(--r-lg);animation:ui-modal-fade .12s ease}
@supports (backdrop-filter:blur(3px)){.ns-working{background:color-mix(in srgb,var(--surface) 74%,transparent);backdrop-filter:blur(3px)}}
.ns-steps{display:flex;flex-direction:column;gap:13px;padding:24px 28px}
.ns-step{display:flex;align-items:center;gap:11px;font-size:14px;color:var(--fg-3);transition:color .18s ease}
.ns-step.active{color:var(--fg)}
.ns-step.done{color:var(--fg-2)}
.ns-step.done .ns-step-ic{color:var(--s-merge)}
.ns-step-ic{width:16px;height:16px;flex:none;display:grid;place-items:center;font-size:12px;font-weight:600}
.ns-dot-idle{width:7px;height:7px;border-radius:50%;background:var(--fg-3);opacity:.45}

/* Zendesk pull-in — the linked-ticket card the pull resolves to */
.zd-pick{display:flex;gap:8px}
.zd-pick input{flex:1}
.zd-linked{margin-top:10px;padding:12px 13px;border:1px solid var(--line);border-radius:var(--r-lg);background:var(--sunken);display:flex;flex-direction:column;gap:11px}
.zd-tag{font-family:var(--mono);font-size:12.5px;font-weight:600;color:#3f8f5f;background:rgba(63,143,95,.12);border-radius:var(--r);padding:3px 8px;white-space:nowrap;flex:none}
.zd-linked-hd{display:flex;align-items:flex-start;gap:11px}
.zd-linked-txt{flex:1;min-width:0}
.zd-linked-subj{font-size:14px;color:var(--fg);font-weight:500;line-height:1.4}
.zd-linked-meta{font-size:12.5px;color:var(--fg-3);margin-top:3px;display:flex;gap:7px;flex-wrap:wrap}
.zd-linked-x{all:unset;cursor:pointer;color:var(--fg-3);font-size:14px;line-height:1;padding:2px 5px;border-radius:5px;flex:none}
.zd-linked-x:hover{color:var(--fg);background:var(--raised)}
.zd-actions{display:flex;gap:8px;flex-wrap:wrap;align-items:center;min-height:30px}
.zd-sep{flex:1}
.zd-asis{all:unset;cursor:pointer;color:var(--fg-3);font-size:13px;border-bottom:1px dashed var(--line);transition:color .15s ease,border-color .15s ease}
.zd-asis:hover{color:var(--fg-2);border-bottom-color:var(--fg-3)}
.zd-drafted-badge{display:inline-flex;align-items:center;gap:8px;font-size:13px;color:var(--s-merge)}
#new-session-card.zd-drafted .zd-hint{display:none}
.zd-hint{margin:0}
.zd-hint b{color:var(--fg-2);font-weight:600}
.zd-instruction-label{font-size:12.5px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--fg-2)}
.create textarea.zd-instruction{min-height:88px;margin-top:0;font-size:15px;line-height:1.6}
.zd-instruction-meta{font-size:13px;color:var(--fg-2);line-height:1.5}
.zd-existing{font-size:14px;color:var(--fg);padding:10px 12px;border:1px solid color-mix(in srgb,var(--s-autotest) 45%,var(--line));border-radius:var(--r);background:color-mix(in srgb,var(--s-autotest) 10%,transparent)}
.zd-existing a{font-family:var(--mono);font-size:13px;color:var(--nav)}
.zd-ticket-link{padding:8px 0;border-bottom:1px solid var(--line-soft)}
.zd-ticket-link:last-child{border-bottom:0}
.zd-ticket-link-head{display:flex;align-items:center;gap:8px;font-size:15px}
.zd-ticket-instruction{margin-top:8px;font-size:15px;line-height:1.6;color:var(--fg)}
.zd-ticket-instruction strong{font-weight:600}
.zd-ticket-provenance{margin-top:4px;font-size:13px;color:var(--fg-2);line-height:1.5}
.zd-ticket-source{margin-top:6px;font-size:13px;color:var(--fg-2);line-height:1.5}
.zd-ticket-source strong{font-weight:600}
.zd-context-preview summary{cursor:pointer;font-size:14px;color:var(--nav)}
.zd-context-preview pre{max-height:220px;overflow:auto;white-space:pre-wrap;margin:8px 0 0;padding:12px;border:1px solid var(--line);border-radius:var(--r);background:var(--surface);font-family:var(--sans);font-size:15px;line-height:1.6;color:var(--fg)}

/* ===== FORMS ===== */
.fld{width:100%;background:var(--sunken);border:1px solid var(--line);border-radius:var(--r);color:var(--fg);font-family:var(--sans);font-size:14px;padding:9px 11px;outline:none}
.fld:focus{border-color:var(--fg-3)}
.fld-sm{width:auto;font-size:12.5px;padding:5px 8px}

/* ===== CODE REVIEW / DIFF ===== */
.review-wrap{display:flex;flex-direction:column;gap:12px}
.review-bar{display:flex;align-items:center;gap:12px;background:var(--surface);border:1px solid var(--line);border-radius:var(--r-lg);padding:11px 14px;box-shadow:var(--shadow);flex-wrap:wrap}
.rb-sum{font-size:14px;color:var(--fg-2)}
.rb-sum strong{color:var(--fg)}
.rb-sum code{font-family:var(--mono);font-size:12.5px;background:var(--sunken);border:1px solid var(--line);padding:2px 6px;border-radius:4px}
.rb-spacer{flex:1}
.rb-verdict{font-family:var(--mono);font-size:13px;padding:5px 10px;border-radius:var(--r)}
.rb-verdict.ok{color:var(--s-merge);background:color-mix(in srgb,var(--s-merge) 12%,transparent)}
.rb-verdict.chg{color:var(--s-autotest);background:color-mix(in srgb,var(--s-autotest) 12%,transparent)}
.rb-verdict.review{color:var(--s-review);background:color-mix(in srgb,var(--s-review) 12%,transparent)}
.rb-verdict.fail{color:var(--danger);background:color-mix(in srgb,var(--danger) 12%,transparent)}
.rb-verdict.pending{color:var(--s-autotest);background:color-mix(in srgb,var(--s-autotest) 12%,transparent)}
.rb-verdict.rb-ai{font-family:var(--sans);font-size:14px;font-weight:600;border:0;cursor:pointer;min-height:36px}
.diff-file{border:1px solid var(--line);border-radius:var(--r-lg);overflow:hidden;background:var(--surface)}
.df-head{display:flex;align-items:center;gap:9px;width:100%;text-align:left;background:var(--raised);border:0;border-bottom:1px solid var(--line-soft);padding:8px 13px;cursor:pointer;font-family:var(--sans)}
/* Zendesk 355843: pin the per-file path + Edit/Copy while a long review
   diff scrolls. overflow:hidden on .diff-file would contain the sticky
   box to the card (taller than the viewport), so the review tab lifts
   that clip — same reason .rn-area-hd needs overflow:visible on its
   wrapper. top:60px sits under the sticky topbar; phones drop that
   offset because the topbar is relative there. */
.review-wrap .diff-file{overflow:visible}
.review-wrap .df-head{position:sticky;top:60px;z-index:3;border-radius:var(--r-lg) var(--r-lg) 0 0}
.review-wrap .diff-file[data-expanded="0"] .df-head{border-radius:var(--r-lg)}
.review-wrap .df-body{border-radius:0 0 var(--r-lg) var(--r-lg)}
@media (max-width:720px){
	.review-wrap .df-head{top:0}
}
.df-glyph{width:20px;height:20px;border-radius:4px;display:grid;place-items:center;font-family:var(--mono);font-size:12px;font-weight:600;flex:none}
.df-glyph.st-mod{color:var(--s-autotest);background:color-mix(in srgb,var(--s-autotest) 14%,transparent)}
.df-glyph.st-add{color:var(--s-merge);background:color-mix(in srgb,var(--s-merge) 14%,transparent)}
.df-glyph.st-del{color:var(--danger);background:color-mix(in srgb,var(--danger) 14%,transparent)}
/* Path sizes to its content (spacer takes leftover). flex:1 here used to
   split the row with .df-spacer, so names ellipsized while the spacer
   sat empty — Zendesk 353819. Shrink + ellipsis only when the row is tight. */
.df-path{font-family:var(--mono);font-size:13px;color:var(--fg);flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;direction:rtl;text-align:left}
.df-spacer{flex:1;min-width:0}
.df-add{color:var(--s-merge);font-family:var(--mono);font-size:12.5px}
.df-del{color:var(--danger);font-family:var(--mono);font-size:12.5px}
.df-open{flex:none;margin-left:6px;font-size:11.5px;color:var(--fg-3);border:1px solid var(--line);border-radius:6px;padding:2px 7px;cursor:pointer;white-space:nowrap}
.df-open:hover{color:var(--fg);border-color:var(--fg-3)}
.df-path-act{font-size:12.5px;padding:4px 8px}
.df-open.is-copied{color:var(--s-merge);border-color:color-mix(in srgb,var(--s-merge) 55%,transparent)}
.df-revert:hover{color:var(--danger);border-color:color-mix(in srgb,var(--danger) 55%,transparent)}
.blame-legend{display:flex;align-items:center;gap:3px;padding:6px 10px;font-size:11.5px;color:var(--fg-3);border-bottom:1px solid var(--line)}
.blame-legend .bl-swatch{display:inline-block;width:14px;height:8px;border-radius:2px}
.blame-legend .bl-lab{margin:0 5px}
.blame-legend .bl-count{margin-left:auto}
.df-chev{color:var(--fg-3);transition:transform .15s ease}
.diff-file[data-expanded="1"] .df-chev{transform:rotate(90deg)}
.diff-file[data-expanded="0"] .df-body{display:none}
/* The scroller is itself a grid whose code track is at least as wide as the
   longest line; rows subgrid onto it, so add/del tints and hover span the full
   scroll width instead of stopping at the first viewport's edge. --df-gut is
   the gutter column width — contexts that resize the gutters must keep it in
   sync (the sticky offsets below are computed from it).
   Engines without subgrid keep the per-row fallback columns (old behavior). */
.df-body{overflow-x:auto;display:grid;grid-template-columns:44px 44px 16px minmax(max-content,1fr) 26px;container-type:inline-size;--df-gut:44px}
.df-body>*{grid-column:1/-1}
/* Comment threads/forms and hunk headers sit between rows — pin them to the
   visible pane (100cqw = the scroller's width) so a wide diff can't stretch
   them, and hunk headers stay readable mid-scroll. */
.df-body>.lc-thread,.df-body>.line-comment-form,.df-body>.df-hunk,.df-body>.df-orphans{position:sticky;left:0;width:100cqw}
.df-hunk{font-family:var(--mono);font-size:12px;color:var(--fg-3);background:var(--sunken);padding:5px 13px;display:flex;align-items:center;gap:10px}
.df-hunk-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Expand-context gutter (review tab): reveal the lines the diff hides around a hunk. */
.df-expand{display:inline-flex;gap:4px;flex:none}
.df-expand button{border:0;width:24px;height:18px;border-radius:4px;background:color-mix(in srgb,var(--s-review) 15%,transparent);color:var(--s-review);font-size:12px;line-height:1;cursor:pointer;padding:0}
.df-expand button:hover{background:color-mix(in srgb,var(--s-review) 30%,transparent)}
.df-expand button:disabled{opacity:.5;cursor:default}
.df-expand-count{flex:none;font-size:11.5px;color:var(--fg-3)}
.df-hunk-tail{min-height:18px}
/* Row-capped file: how much is shown, plus Show full file (loads the rest
   on demand) and the patch download. The sentence is sans — mono is for
   identifiers, and this is a note. */
.df-lines-cut{justify-content:center;flex-wrap:wrap;gap:12px;color:var(--fg-2);padding:12px 13px;font-family:var(--sans);font-size:15px}
.df-lines-cut-note{text-align:center}
.df-lines-cut .btn{min-height:36px;flex:none}
.df-lines-cut a{color:var(--nav);text-decoration:none}
.df-lines-cut a:hover{text-decoration:underline}
.df-line{display:grid;grid-template-columns:44px 44px 16px 1fr 26px;grid-template-columns:subgrid;align-items:center;font-family:var(--mono);font-size:13px;line-height:1.7;position:relative}
.df-line:hover{background:var(--raised)}
.df-ln{text-align:right;padding-right:8px;color:var(--fg-3);font-size:12px;user-select:none}
.df-mark{text-align:center;user-select:none}
.df-code{white-space:pre;padding-right:12px;color:var(--fg-2)}
.df-line.t-add{background:color-mix(in srgb,var(--s-merge) 11%,transparent)}
.df-line.t-add .df-mark{color:var(--s-merge)}
.df-line.t-del{background:color-mix(in srgb,var(--danger) 10%,transparent)}
.df-line.t-del .df-mark{color:var(--danger)}
.df-comment-btn{opacity:0;border:0;width:20px;height:20px;border-radius:4px;background:var(--bone);color:var(--on-bone);font-size:13px;font-weight:600;line-height:1;cursor:pointer;justify-self:center}
.df-line:hover .df-comment-btn,.df-comment-btn:focus-visible{opacity:1}
/* A line with a conversation: review-hue bar on the row + a permanent 💬 in
   the comment gutter (the thread sits right under the row). Hover no longer
   matters — the marker is how a reviewer spots commented lines while
   scrolling (Zendesk 353974). */
.df-line.has-comment{box-shadow:inset 3px 0 0 var(--s-review)}
.df-thread-mark{border:0;width:22px;height:22px;border-radius:6px;background:var(--s-review);color:#fff;font-size:12px;line-height:1;cursor:pointer;justify-self:center;display:grid;place-items:center}
.df-thread-mark.all-resolved{background:color-mix(in srgb,var(--s-merge) 80%,var(--surface))}
.df-thread-mark:hover{filter:brightness(1.12)}
.df-binary-note{padding:14px;color:var(--fg-2);font-size:13.5px}
/* ── Conversations (review threads) ── */
.lc-thread{background:color-mix(in srgb,var(--s-review) 9%,var(--surface));border-top:1px solid color-mix(in srgb,var(--s-review) 40%,var(--line));border-bottom:1px solid color-mix(in srgb,var(--s-review) 40%,var(--line));box-shadow:inset 4px 0 0 var(--s-review);font-family:var(--sans);white-space:normal}
.lc-thread.resolved{background:var(--raised);border-top-color:var(--line-soft);border-bottom-color:var(--line-soft);box-shadow:inset 4px 0 0 color-mix(in srgb,var(--s-merge) 70%,var(--surface))}
.lc-thread.outdated:not(.resolved){box-shadow:inset 4px 0 0 var(--fg-3)}
.lc-thread.sev-high:not(.resolved){box-shadow:inset 4px 0 0 var(--danger);border-top-color:color-mix(in srgb,var(--danger) 40%,var(--line));border-bottom-color:color-mix(in srgb,var(--danger) 40%,var(--line));background:color-mix(in srgb,var(--danger) 7%,var(--surface))}
.lc-thread.lc-flash{outline:2px solid var(--s-review);outline-offset:-2px;animation:lc-flash 1.8s ease-out}
@keyframes lc-flash{0%{background:color-mix(in srgb,var(--s-review) 28%,var(--surface))}100%{background:inherit}}
.lc-thread-state{display:flex;align-items:center;gap:10px;flex-wrap:wrap;padding:8px 16px 0 18px;font-size:var(--fs-meta);color:var(--fg-2)}
.lc-state{font-family:var(--sans);font-size:var(--fs-label);font-weight:600;letter-spacing:.04em;text-transform:uppercase;color:var(--fg-2);border:1px solid var(--line);border-radius:4px;padding:2px 7px}
.lc-state.ok{color:var(--s-merge);border-color:color-mix(in srgb,var(--s-merge) 45%,transparent)}
.lc-was{font-family:var(--mono);font-size:12.5px;color:var(--fg-3);background:var(--sunken);border:1px solid var(--line-soft);border-radius:4px;padding:2px 7px;max-width:60ch;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.lc-hide{all:unset;cursor:pointer;margin-left:auto;font-size:12.5px;color:var(--fg-3)}
.lc-hide:hover{color:var(--fg)}
/* Folded shell for a resolved / outdated conversation — one line, click to read. */
.lc-collapsed{display:flex;align-items:center;gap:10px;width:100%;min-height:44px;text-align:left;background:none;border:0;padding:10px 16px 10px 18px;cursor:pointer;color:var(--fg-2);font-family:var(--sans);font-size:14px}
.lc-collapsed b{color:var(--fg);font-weight:600;flex:none}
.lc-collapsed-pv{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1}
.lc-show{flex:none;color:var(--nav);font-weight:600}
.lc-collapsed:hover .lc-show{text-decoration:underline}
.line-comment{display:flex;gap:12px;padding:12px 16px 4px 18px}
.line-comment.lc-reply{padding-top:10px}
.lc-replies{margin:6px 0 0 44px;padding-left:12px;border-left:2px solid color-mix(in srgb,var(--s-review) 35%,var(--line))}
.lc-thread.resolved .lc-replies{border-left-color:var(--line-soft)}
.lc-avatar{width:28px;height:28px;border-radius:50%;background:color-mix(in srgb,var(--s-review) 16%,var(--surface));border:1px solid color-mix(in srgb,var(--s-review) 40%,var(--line));color:var(--s-review);display:grid;place-items:center;font-family:var(--sans);font-size:12.5px;font-weight:600;flex:none}
.lc-reply .lc-avatar{width:24px;height:24px;font-size:12px}
.lc-main{min-width:0;flex:1}
.lc-meta{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap;font-size:var(--fs-meta);color:var(--fg-2)}
.lc-author{font-weight:600;color:var(--fg);font-size:15px}
.lc-when{font-family:var(--mono);font-size:12.5px;color:var(--fg-3)}
.lc-edited{font-size:12.5px;color:var(--fg-3);font-style:italic}
.lc-ai{font-family:var(--sans);font-size:12px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;color:#fff;background:var(--s-review);border-radius:4px;padding:2px 7px;line-height:1.3}
.lc-ai.sev-high{background:var(--danger)}
.lc-ai.sev-medium{background:var(--s-autotest);color:#1a1a1a}
.lc-ai.sev-low{background:var(--fg-3);color:var(--ink)}
.lc-acts{margin-left:auto;display:inline-flex;gap:2px}
.lc-act{border:0;background:none;color:var(--fg-3);cursor:pointer;font-size:12.5px;padding:1px 6px;border-radius:4px;font-family:var(--sans)}
.lc-act:hover{color:var(--fg);background:var(--raised)}
.lc-act.danger:hover{color:var(--danger)}
.lc-body{margin-top:6px;font-size:var(--fs-body);line-height:1.6;color:var(--fg);white-space:pre-wrap}
.lc-body.md{white-space:normal}
/* Markdown inside review threads — same rules as .bubble.md (kept in sync). */
.lc-body.md .md-line + .md-line{margin-top:2px}
.lc-body.md .md-gap{height:8px}
.lc-body.md .md-h{font-weight:700;font-size:15px;margin:8px 0 2px}
.lc-body.md .md-list{margin:4px 0 4px 20px;padding:0}
.lc-body.md .md-list li{margin:1px 0}
.lc-body.md .md-list .md-list{margin:1px 0 2px 20px}
.lc-body.md code{font-family:var(--mono);font-size:13px;background:var(--sunken);border:1px solid var(--line-soft);border-radius:5px;padding:1px 5px}
.lc-body.md pre.md-pre{font-family:var(--mono);font-size:13px;line-height:1.5;background:var(--sunken);border:1px solid var(--line-soft);border-radius:var(--r);padding:10px 12px;overflow-x:auto;white-space:pre;margin:6px 0}
.lc-body.md .md-pre-wrap{margin:6px 0}
.lc-body.md .md-pre-wrap > pre.md-pre{margin:0;padding-right:48px;white-space:pre-wrap;overflow-wrap:anywhere;overflow-x:visible}
.lc-body.md a{color:var(--nav)}
.lc-body.md .md-table-wrap{overflow-x:auto;margin:6px 0}
.lc-body.md table.md-table{border-collapse:collapse;font-size:14px}
.lc-body.md table.md-table th,.lc-body.md table.md-table td{border:1px solid var(--line-soft);padding:5px 9px;text-align:left}
.lc-body.md table.md-table th{background:var(--sunken);font-weight:600}
.lc-edit{margin-top:6px}
.lc-thread-foot{display:flex;align-items:flex-start;gap:8px;flex-wrap:wrap;padding:8px 16px 12px 62px}
.lc-reply-form{flex:1 1 320px;min-width:0}
.lc-thread-foot .btn{min-height:36px}
.line-comment-form{padding:12px 16px 14px 18px;background:color-mix(in srgb,var(--s-review) 8%,var(--surface));border-top:1px solid color-mix(in srgb,var(--s-review) 35%,var(--line));box-shadow:inset 4px 0 0 var(--s-review);font-family:var(--sans)}
/* The comment-mode textarea (suggestions use the code editor, styled separately). */
.lcf-comment{width:100%;box-sizing:border-box;background:var(--sunken);border:1px solid var(--line);border-radius:var(--r);color:var(--fg);font-family:var(--sans);font-size:var(--fs-body);line-height:1.5;padding:12px 14px;outline:none;resize:vertical;min-height:44px}
.lcf-comment:focus{border-color:var(--s-review)}
.lcf-bar{display:flex;gap:8px;margin-top:8px}
/* Conversations index at the top of the review tab. */
.review-convos{background:var(--surface);border:1px solid color-mix(in srgb,var(--s-review) 40%,var(--line));border-radius:var(--r-lg);box-shadow:inset 3px 0 0 var(--s-review);overflow:hidden}
.rc-head{display:flex;align-items:center;gap:12px;flex-wrap:wrap;padding:12px 16px;border-bottom:1px solid var(--line-soft)}
.rc-title{color:var(--s-review)}
.rc-count{font-size:14px;color:var(--fg-2)}
.rc-show-resolved{font-size:14px;color:var(--fg-2);gap:6px}
.rc-list{max-height:330px;overflow:auto}
.rc-item{display:grid;grid-template-columns:18px minmax(10em,max-content) auto minmax(0,1fr) auto;gap:10px;align-items:baseline;width:100%;text-align:left;background:none;border:0;border-bottom:1px solid var(--line-soft);padding:10px 16px;cursor:pointer;color:var(--fg);font-family:var(--sans);font-size:var(--fs-body);min-height:44px}
.rc-item:last-child{border-bottom:0}
.rc-item:hover,.rc-item:focus-visible{background:color-mix(in srgb,var(--s-review) 8%,transparent)}
.rc-item.is-resolved{display:none;color:var(--fg-2)}
.review-convos.show-resolved .rc-item.is-resolved{display:grid}

/* Pipeline AI review on the Code Review tab — summary of the latest
   ci_runs findings, above the diff. Spine colour is the run's state. */
.review-ai{background:var(--surface);border:1px solid color-mix(in srgb,var(--s-review) 40%,var(--line));border-radius:var(--r-lg);box-shadow:inset 3px 0 0 var(--s-review);overflow:hidden}
.review-ai.is-ok{border-color:color-mix(in srgb,var(--s-merge) 40%,var(--line));box-shadow:inset 3px 0 0 var(--s-merge)}
.review-ai.is-fail{border-color:color-mix(in srgb,var(--danger) 40%,var(--line));box-shadow:inset 3px 0 0 var(--danger)}
.review-ai.is-pending{border-color:color-mix(in srgb,var(--s-autotest) 40%,var(--line));box-shadow:inset 3px 0 0 var(--s-autotest)}
.review-ai.is-chg{border-color:color-mix(in srgb,var(--s-autotest) 40%,var(--line));box-shadow:inset 3px 0 0 var(--s-autotest)}
.rai-head{display:flex;align-items:center;gap:12px;flex-wrap:wrap;padding:15px 18px;border-bottom:1px solid var(--line-soft)}
.rai-title{color:var(--s-review)}
.review-ai.is-ok .rai-title{color:var(--s-merge)}
.review-ai.is-fail .rai-title{color:var(--danger)}
.rai-status{font-size:14px;font-weight:600;color:var(--fg)}
.rai-body{padding:12px 0 4px}
.rai-empty,.rai-sum,.rai-count{margin:0 18px 12px;font-size:var(--fs-lead);line-height:1.65;color:var(--fg)}
.rai-count{font-size:var(--fs-body);color:var(--fg-2)}
.rai-sum{font-size:var(--fs-body);color:var(--fg)}
.rai-list{max-height:330px;overflow:auto}
.rai-item{display:grid;grid-template-columns:auto minmax(10em,max-content) minmax(0,1fr) auto;gap:10px;align-items:baseline;width:100%;text-align:left;background:none;border:0;border-bottom:1px solid var(--line-soft);padding:12px 18px;cursor:pointer;color:var(--fg);font-family:var(--sans);font-size:var(--fs-body);min-height:44px}
.rai-item:last-child{border-bottom:0}
.rai-item:hover,.rai-item:focus-visible{background:color-mix(in srgb,var(--s-review) 8%,transparent)}
.rai-item.is-blocking:hover,.rai-item.is-blocking:focus-visible{background:color-mix(in srgb,var(--danger) 8%,transparent)}
.rai-item.is-waived{color:var(--fg-2);opacity:.7}
.rai-sev{font-family:var(--sans);font-size:var(--fs-label);font-weight:600;letter-spacing:.04em;text-transform:uppercase;border-radius:4px;padding:2px 7px;line-height:1.3;color:#fff;background:var(--fg-3)}
.rai-sev.sev-critical,.rai-sev.sev-major{background:var(--danger)}
.rai-sev.sev-minor{background:var(--fg-3);color:var(--ink)}
.rai-loc{font-family:var(--mono);font-size:var(--fs-meta);font-weight:600;color:var(--s-review);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;direction:rtl;text-align:left}
.rai-item.is-blocking .rai-loc{color:var(--danger)}
.rai-item-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--fg)}
.rai-waived{font-size:12.5px;color:var(--fg-3);white-space:nowrap}
@media (max-width:720px){
	.rai-item{grid-template-columns:auto minmax(0,1fr);gap:4px 10px;padding:12px 14px}
	.rai-item .rai-item-title,.rai-item .rai-waived{grid-column:2}
}
.rc-status{color:var(--s-review);font-size:12px;text-align:center}
.rc-item.is-resolved .rc-status{color:var(--s-merge)}
.rc-loc{font-family:var(--mono);font-size:var(--fs-meta);font-weight:600;color:var(--s-review);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;direction:rtl;text-align:left}
.rc-item.is-resolved .rc-loc{color:var(--fg-2)}
.rc-who{display:inline-flex;align-items:baseline;gap:6px;font-size:14px;font-weight:600;color:var(--fg);white-space:nowrap}
.rc-preview{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--fg)}
.rc-item.is-resolved .rc-preview{color:var(--fg-2)}
.rc-dim,.rb-dim{color:var(--fg-3);font-weight:400}
.rc-replies{font-size:12.5px;color:var(--fg-3);white-space:nowrap}
.df-cmt-count{font-family:var(--sans);font-size:var(--fs-label);font-weight:600;color:#fff;background:var(--s-review);border-radius:999px;padding:3px 9px;flex:none;cursor:pointer;white-space:nowrap}
.df-cmt-count.all-resolved{color:var(--s-merge);background:color-mix(in srgb,var(--s-merge) 14%,transparent);border:1px solid color-mix(in srgb,var(--s-merge) 40%,transparent)}
.df-cmt-count:hover{filter:brightness(1.12)}
.df-orphans{border-top:1px solid color-mix(in srgb,var(--s-review) 30%,var(--line))}
.df-orphans-hd{font-family:var(--sans);font-size:var(--fs-label);font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--s-review);padding:10px 16px 6px}
.review-orphans .df-head{cursor:default}
.review-orphans .df-path{direction:ltr;font-family:var(--sans);font-size:14px;color:var(--fg-2)}
/* Floating review pill (bottom-center): Back to top after you leave the
   approve bar, plus prev/next through open conversations. */
.review-nav{position:fixed;left:50%;transform:translateX(-50%);bottom:18px;z-index:60;display:flex;align-items:center;gap:4px;padding:4px 4px 4px 8px;background:var(--surface);border:1px solid color-mix(in srgb,var(--s-review) 55%,var(--line));border-radius:999px;box-shadow:var(--shadow)}
.review-nav:has(.rn-top[hidden]){padding-left:12px}
.review-nav[hidden]{display:none}
.rn-top{all:unset;cursor:pointer;font-family:var(--sans);font-size:var(--fs-ui);font-weight:600;color:var(--fg);padding:6px 12px;min-height:36px;display:inline-flex;align-items:center;white-space:nowrap;border-radius:999px}
.rn-top:hover{background:var(--raised)}
.rn-top:not([hidden])+.rn-count:not([hidden]){border-left:1px solid var(--line);padding-left:10px;margin-left:2px}
.rn-count{all:unset;cursor:pointer;font-family:var(--sans);font-size:14px;font-weight:600;color:var(--fg);padding-right:6px;white-space:nowrap}
.rn-btn{border:0;width:36px;height:36px;border-radius:50%;background:color-mix(in srgb,var(--s-review) 16%,transparent);color:var(--s-review);font-size:16px;font-weight:600;cursor:pointer;line-height:1}
.rn-btn:hover{background:var(--s-review);color:#fff}
@media (max-width:720px){
	.review-nav{bottom:76px}
	.rc-item{grid-template-columns:18px minmax(0,1fr);gap:4px 10px;padding:12px 14px}
	.rc-item .rc-preview,.rc-item .rc-replies{grid-column:2}
	.lc-thread-foot{padding-left:18px}
	.lc-replies{margin-left:16px}
}
@media (pointer:coarse){
	.review-wrap .df-comment-btn{opacity:.85}
}
/* Activity board: mirrored review conversations. */
.ev.is-review::before{background:var(--s-review)}
.ev-rc-loc{font-family:var(--mono);font-size:13px;color:var(--s-review);background:color-mix(in srgb,var(--s-review) 10%,transparent);border:1px solid color-mix(in srgb,var(--s-review) 35%,transparent);border-radius:4px;padding:1px 6px}
.ev-rc-tag{font-family:var(--sans);font-size:12px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;color:var(--fg-2);border:1px solid var(--line);border-radius:4px;padding:1px 6px;margin-left:4px}
.ev-rc-tag.open{color:var(--s-review);border-color:color-mix(in srgb,var(--s-review) 45%,transparent)}
.ev-rc-tag.ok{color:var(--s-merge);border-color:color-mix(in srgb,var(--s-merge) 45%,transparent)}
.ev-line .lc-ai{margin-left:4px;font-size:11.5px;font-size:12px}
.diff-empty{border:1px dashed var(--line);border-radius:var(--r-lg);padding:30px;text-align:center;color:var(--fg-2);font-size:15px;line-height:1.6}
.diff-empty strong{color:var(--fg)}
.diff-empty-mark{font-size:22px;margin-bottom:6px;color:var(--fg-3)}
.diff-empty .fine{font-size:13.5px}
.diff-note{text-align:center;color:var(--fg-2);font-size:13.5px}
.diff-loading{padding:24px;text-align:center;color:var(--fg-2);font-size:14px}

/* view switcher (Overview / Code review) */
/* Wraps when out of space (admin's 12 tabs in a narrow window) — pages with
   few tabs never wrap, so nothing changes there. */
.views{display:flex;flex-wrap:wrap;gap:6px;padding:4px 0 0}
.views button{font-family:var(--sans);font-size:13px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;background:none;border:1px solid transparent;color:var(--fg-3);padding:9px 14px;border-radius:var(--r);cursor:pointer;display:inline-flex;align-items:center;gap:7px}
.views button[aria-current="true"]{color:var(--fg);border-color:var(--line);background:var(--surface)}
.views .count{font-family:var(--mono);font-size:12px;color:var(--fg-3)}
/* Issue page: assignee sits on this same row (far right) — no extra card. */
.views-ticket{align-items:center;flex-wrap:nowrap}
.views-assignee{margin-left:auto;display:flex;align-items:center;min-width:0;padding:0 2px;font-size:15px}
.views-assignee[hidden]{display:none}
.views-assignee .meta-set-val{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* spinner */
.spinner{display:inline-block;width:13px;height:13px;border:2px solid var(--line);border-top-color:var(--fg-2);border-radius:50%;animation:spin .8s linear infinite;vertical-align:-2px}
@keyframes spin{to{transform:rotate(360deg)}}

/* ===== ASSISTANT DOCK ===== */
/* Launcher = the ✦ iconbtn in the topbar (ui_head.php); the panel still docks
   bottom-right so it never covers the header. */
.asst-panel{position:fixed;bottom:22px;right:22px;z-index:46;width:min(400px,calc(100vw - 2rem));height:min(600px,calc(100vh - 3rem));background:var(--surface);border:1px solid var(--line);border-radius:var(--r-lg);box-shadow:var(--shadow);display:flex;flex-direction:column;overflow:hidden}
/* Expanded mode: the dock grows into a centered overlay (⤢ in the header). */
.asst-panel.expanded{bottom:auto;right:auto;top:50%;left:50%;transform:translate(-50%,-50%);width:min(920px,94vw);height:min(86vh,900px)}
.asst-backdrop{position:fixed;inset:0;z-index:45;background:color-mix(in srgb,var(--ink) 45%,transparent)}
.asst-panel.expanded .asst-msgs{padding:18px 22px}
.asst-panel.expanded .asst-b.bot{max-width:78ch}
.asst-hd{display:flex;align-items:center;gap:8px;padding:12px 14px;border-bottom:1px solid var(--line-soft)}
.asst-hd-title{flex:1;min-width:0;font-family:var(--sans);font-size:var(--fs-ui);font-weight:600;color:var(--fg);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;line-height:1.3}
.asst-hd .iconbtn{flex:none}
/* Scope strip: shows when the dock is bound to the page's active filter. */
.asst-scope{padding:8px 14px;border-bottom:1px solid var(--line-soft);background:var(--sunken);font-size:var(--fs-label);font-weight:600;line-height:1.5;color:var(--fg-2)}
.asst-scope code{font-family:var(--mono);font-size:var(--fs-meta);background:var(--raised);border:1px solid var(--line-soft);border-radius:4px;padding:1px 5px;color:var(--fg)}
.asst-msgs{flex:1;overflow-y:auto;padding:14px;display:flex;flex-direction:column;gap:11px}
.asst-hist{flex:1;overflow-y:auto;padding:8px;display:flex;flex-direction:column;gap:4px}
.asst-hist-empty{padding:18px 14px;font-size:var(--fs-lead);line-height:1.65;color:var(--fg)}
.asst-hist-row{display:flex;align-items:center;gap:8px;border-radius:var(--r);padding:4px 4px 4px 0}
.asst-hist-row.on,.asst-hist-row:hover{background:var(--raised)}
.asst-hist-open{flex:1;min-width:0;display:flex;flex-direction:column;align-items:flex-start;gap:2px;background:none;border:0;color:var(--fg);cursor:pointer;text-align:left;padding:8px 10px;min-height:44px;border-radius:var(--r)}
.asst-hist-name{font-family:var(--sans);font-size:var(--fs-body);font-weight:500;color:var(--fg);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}
.asst-hist-when{font-family:var(--sans);font-size:var(--fs-meta);color:var(--fg-2)}
.asst-hist-del{flex:none;width:36px;height:36px;background:none;border:0;color:var(--fg-3);cursor:pointer;border-radius:var(--r);font-size:15px}
.asst-hist-del:hover{color:var(--fg);background:var(--sunken)}
.asst-b{max-width:88%;font-size:var(--fs-body);line-height:1.6;padding:10px 13px;border-radius:var(--r);white-space:pre-wrap;word-wrap:break-word}
.asst-b.bot{align-self:flex-start;background:var(--raised);border:1px solid var(--line-soft);color:var(--fg);white-space:normal}
.asst-b.me{align-self:flex-end;background:var(--bone);color:var(--on-bone)}
/* Markdown inside assistant answers */
.asst-b .asst-line{margin:0}
.asst-b .asst-line + .asst-line{margin-top:2px}
.asst-b .asst-gap{height:8px}
.asst-b .asst-h{font-weight:700;margin:2px 0}
.asst-b strong{font-weight:700}
.asst-b em{font-style:italic}
.asst-b code{font-family:var(--mono);font-size:12.5px;background:var(--sunken);border:1px solid var(--line-soft);border-radius:4px;padding:0 4px}
.asst-b .asst-pre{font-family:var(--mono);font-size:12.5px;line-height:1.55;background:var(--sunken);border:1px solid var(--line-soft);border-radius:var(--r);padding:8px 10px;margin:6px 0;overflow-x:auto;white-space:pre}
.asst-b .asst-pre code{background:none;border:0;padding:0}
.asst-b .asst-ul{margin:4px 0 4px 0;padding-left:18px}
.asst-b .asst-ul li{margin:2px 0}
.asst-b .asst-table-wrap{overflow-x:auto;margin:6px 0}
.asst-b .asst-table{border-collapse:collapse;font-size:13px}
.asst-b .asst-table th,.asst-b .asst-table td{border:1px solid var(--line-soft);padding:4px 8px;text-align:left;white-space:nowrap;vertical-align:top}
.asst-b .asst-table th{font-weight:600;background:var(--sunken);font-family:var(--sans);letter-spacing:.02em}

/* ===== TICKET-LIST QUERY BAR + SAVED VIEWS ===== */
.qbar{display:flex;align-items:center;gap:8px;margin-top:8px;background:var(--surface);border:1px solid var(--line);border-radius:var(--r-lg);padding:6px 8px 6px 12px;box-shadow:var(--shadow)}
.qbar:focus-within{border-color:var(--fg-3)}
.qbar-ico{color:var(--fg-3);font-size:16px;flex:none}
.qbar input{flex:1;min-width:0;background:none;border:0;outline:none;color:var(--fg);font-family:var(--mono);font-size:14px;padding:7px 2px}
.qbar input::placeholder{color:var(--fg-3)}
.qbar-clear{flex:none;color:var(--fg-3);text-decoration:none;font-size:13px;width:22px;height:22px;display:grid;place-items:center;border-radius:50%}
.qbar-clear:hover{background:var(--raised);color:var(--fg)}
.qhint{margin:12px 2px 0}
.qhint-lead{margin:0;font-size:14px;line-height:1.6;color:var(--fg-2)}
.qhint code{font-family:var(--mono);font-size:13px;background:var(--sunken);border:1px solid var(--line-soft);border-radius:5px;padding:2px 6px;margin:0 1px;color:var(--fg)}
.qhint-fields{display:flex;flex-wrap:wrap;gap:8px;margin-top:12px}
.qhint-f{font-family:var(--mono);font-size:13px;color:var(--fg-2);background:var(--raised);border:1px solid var(--line);border-radius:var(--r);padding:6px 11px;cursor:pointer;transition:border-color .12s,color .12s}
.qhint-f:hover{border-color:var(--fg-3);color:var(--fg)}
/* "?" search-field reference popover */
.qbar-wrap{position:relative}
.qbar-help-btn{flex:none;width:26px;height:26px;border-radius:50%;border:1px solid var(--line);background:var(--raised);color:var(--fg-2);font-size:13px;font-weight:700;cursor:pointer;display:grid;place-items:center;line-height:1;transition:border-color .12s,color .12s,background .12s}
.qbar-help-btn:hover{border-color:var(--fg-3);color:var(--fg)}
.qbar-help-btn[aria-expanded="true"]{background:var(--fg);color:var(--surface);border-color:var(--fg)}
.qbar-help{position:absolute;top:calc(100% + 6px);right:0;width:min(480px,calc(100vw - 32px));max-height:min(70vh,560px);overflow-y:auto;z-index:60;background:var(--surface);border:1px solid var(--line);border-radius:var(--r-lg);box-shadow:var(--shadow);padding:6px}
.qbar-help[hidden]{display:none}
.qbar-help-hd{display:flex;align-items:center;justify-content:space-between;padding:8px 8px 6px;font-size:14px}
.qbar-help-x{background:none;border:0;color:var(--fg-3);cursor:pointer;font-size:14px;width:24px;height:24px;border-radius:6px;line-height:1}
.qbar-help-x:hover{background:var(--raised);color:var(--fg)}
.qbar-help-syntax{margin:0 8px 8px;font-size:13px;line-height:1.55;color:var(--fg-2)}
.qbar-help-syntax code{font-family:var(--mono);font-size:12px;background:var(--sunken);border:1px solid var(--line-soft);border-radius:5px;padding:1px 5px;color:var(--fg)}
.qbar-help-list{display:flex;flex-direction:column;gap:1px}
.qbar-help-row{display:grid;grid-template-columns:minmax(120px,33%) 1fr;grid-template-areas:"key help" "key ex";column-gap:12px;row-gap:3px;align-items:baseline;text-align:left;width:100%;background:none;border:0;border-radius:var(--r);padding:9px 8px;cursor:pointer}
.qbar-help-row:hover{background:var(--raised)}
.qhr-key{grid-area:key;display:flex;flex-direction:column;gap:2px;font-family:var(--mono);font-size:13px;font-weight:600;color:var(--fg)}
.qhr-alias{font-family:var(--sans);font-weight:400;font-size:11.5px;color:var(--fg-3)}
.qhr-help{grid-area:help;font-size:13px;line-height:1.45;color:var(--fg-2)}
.qhr-ex{grid-area:ex;justify-self:start;font-family:var(--mono);font-size:12px;color:var(--fg-3);background:var(--sunken);border:1px solid var(--line-soft);border-radius:5px;padding:2px 6px}
.qbar-picker{width:400px;z-index:1100}
.ui-modal-label-row{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:6px}
.ui-modal-label-row .ui-modal-label{margin-bottom:0}
.qbar-use-current{flex:none}
.qpick-head{display:flex;flex-direction:column;gap:2px;padding:12px 14px;border-bottom:1px solid var(--line-soft);background:var(--sunken)}
.qpick-title{font-family:var(--sans);font-size:var(--fs-ui);font-weight:600;color:var(--fg)}
.qpick-hint{font-family:var(--sans);font-size:var(--fs-label);color:var(--fg-2)}
.qpick-list{max-height:320px;padding:6px}
.qpick-opt{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;column-gap:12px;min-height:44px;white-space:normal}
.qpick-label{min-width:0;overflow:hidden;text-overflow:ellipsis;text-align:left;font-family:var(--sans);font-size:var(--fs-ui);color:var(--fg)}
.qpick-meta{max-width:180px;overflow:hidden;text-overflow:ellipsis;text-align:right;font-family:var(--sans);font-size:var(--fs-label);color:var(--fg-2)}
.qpick-empty,.qpick-count{padding:14px 12px;font-family:var(--sans);font-size:var(--fs-meta);line-height:1.5;color:var(--fg-2)}
.views-row{display:flex;flex-wrap:wrap;gap:8px;margin-top:14px;align-items:center}
/* Only-mine lives on the views row so the list ↔ grid toggle keeps it
   in the same place. Not a .btn — the phone Views fold must not hide it. */
.views-row .qbar-mine{margin-left:4px;flex:none}
.view-chip{display:inline-flex;align-items:center;background:var(--surface);border:1px solid var(--line);border-radius:999px;overflow:hidden}
.view-chip.on{border-color:var(--fg-3);background:var(--raised)}
.view-chip a{padding:8px 13px;font-size:14px;color:var(--fg);text-decoration:none;font-weight:500}
/* Tool icons already pad the right edge; keep the label tight against them. */
.view-chip:has(.view-tools) a{padding-right:4px}
.view-chip a:hover{text-decoration:none}
.view-tools{display:inline-flex;align-items:center;gap:2px;padding:0 6px 0 0}
.view-scope{display:inline-flex;align-items:center;justify-content:center;color:var(--fg-2);flex:none;width:22px}
.view-scope svg{display:block}
.view-mail,.view-edit{border:0;background:none;color:var(--fg-2);cursor:pointer;display:inline-flex;align-items:center;justify-content:center;min-width:28px;min-height:36px;padding:8px 2px}
.view-mail:hover,.view-edit:hover{color:var(--fg)}
.view-mail.on{color:var(--nav)}
.view-mail svg,.view-edit svg{display:block}

/* ===== CUSTOM FIELDS ===== */
/* Admin editor */
.cf-list{display:flex;flex-direction:column;margin-bottom:14px}
.cf-row{display:flex;align-items:center;gap:11px;padding:8px 2px;border-bottom:1px solid var(--line-soft);flex-wrap:wrap}
.cf-row:last-child{border-bottom:none}
.cf-label{font-weight:500;font-size:14px;min-width:140px}
.cf-key{font-size:12.5px;color:var(--fg-3)}
.cf-type{font-family:var(--sans);font-size:12px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;color:var(--fg-2);border:1px solid var(--line);border-radius:4px;padding:2px 8px;flex:none}
.cf-place{width:auto;flex:none}
.cf-opts{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}
.cf-vis,.cf-add-vis{display:flex;flex-wrap:wrap;gap:8px;align-items:center;width:100%;padding:4px 0 4px 28px}
.cf-add-vis{padding-left:0;margin-top:8px}
.cf-vis-chip{font-family:var(--sans);font-size:var(--fs-ui);font-weight:500;color:var(--fg-2);background:var(--surface);border:1px solid var(--line);border-radius:var(--r);padding:8px 12px;min-height:36px;cursor:pointer}
.cf-vis-chip:hover{color:var(--fg);border-color:var(--fg-3)}
.cf-vis-chip.on{color:var(--fg);background:var(--raised);border-color:var(--fg-3)}
.cf-add{display:flex;gap:8px;align-items:center;flex-wrap:wrap}
.cf-add #cf-label{flex:1;min-width:220px}
.tr-add{display:flex;gap:8px;align-items:center;flex-wrap:wrap;padding:12px 14px;border-top:1px solid var(--line-soft)}
.perms-table td.ck:last-child,.perms-table th.ck:last-child{width:34px}
/* Drag-to-reorder the "Move to" moves within a stage (grouped by from-status). */
.perms-table th.drag-h,.perms-table td.tr-drag{width:28px}
.perms-table .tr-group-hd td{background:var(--sunken);border-bottom:1px solid var(--line);padding-top:15px;padding-bottom:9px}
.perms-table .tr-group-hd .fine{margin-left:8px;text-transform:none;letter-spacing:0}
.perms-table td.tr-drag{color:var(--fg-3);cursor:grab;text-align:center;font-size:15px;line-height:1;user-select:none}
.perms-table .tr-row:hover td.tr-drag{color:var(--fg-2)}
.perms-table .tr-row.dragging{opacity:.45;background:var(--sunken)}
.perms-table .tr-row.dragging td.tr-drag{cursor:grabbing}
.perms-table .arrow{color:var(--fg-3);margin-right:4px}
/* Special merge actions (unmerge / cut back-merge): reorderable, not role-gated. */
.perms-table .tr-action .act-label{font-family:var(--sans);font-size:13.5px;font-weight:600;color:var(--fg-2)}
.perms-table .tr-action .act-lock{opacity:.5;font-size:12px}
select.fld{background:var(--sunken);border:1px solid var(--line);border-radius:var(--r);color:var(--fg);font-family:var(--sans);font-size:13px;padding:7px 9px;outline:none;cursor:pointer}
/* Native <select> popup. Chrome keeps a light menu while options inherit the
   control's color, so a dark-theme select (color: var(--fg), or inherit on
   the review branch picker) draws near-white text on white — about 1.1:1.
   Zendesk 356645. The closed control keeps its own color and background;
   only the menu is pinned to a light surface with dark text, which is also
   correct in the light theme. color-scheme:light stops the UA painting that
   menu with the page's dark scheme and the light foreground. */
select{color-scheme:light}
select option,select optgroup{background-color:#fff;color:#15191F}
/* Review branch picker. Shares .fld colors; width:auto so it sizes to the
   branch name instead of stretching the review bar (.fld is width:100%). */
.rb-branch-sel{width:auto;min-height:36px;margin-left:10px}
/* Inline model switcher in the chat header — muted to sit beside .t-micro. */
.sess-model-sel{background:var(--sunken);border:1px solid var(--line);border-radius:var(--r);color:var(--fg-3);font-family:var(--mono);font-size:12px;padding:2px 6px;outline:none;cursor:pointer}
.sess-model-sel:hover{color:var(--fg)}
.sess-model-sel:focus{border-color:var(--fg-3)}
.sess-model-sel:disabled{opacity:.5;cursor:default}
/* Ticket-side inline value editor */
.cf-val{cursor:pointer}
.cf-val.cf-unset{color:var(--fg-3);border-bottom:1px dashed var(--line)}
.meta dd .cf-val{white-space:normal;word-break:break-word}
.cf-edit{width:100%;background:var(--sunken);border:1px solid var(--fg-3);border-radius:var(--r);color:var(--fg);font-family:var(--sans);font-size:12.5px;padding:3px 6px;outline:none}
textarea.cf-edit{min-height:70px;resize:vertical;line-height:1.5}
.asst-b a{color:var(--fg);text-decoration:underline;text-underline-offset:2px;text-decoration-color:var(--fg-3)}
.asst-b a:hover{text-decoration-color:var(--fg)}
.asst-b.me a{color:var(--on-bone);text-decoration-color:color-mix(in srgb,var(--on-bone) 55%,transparent)}
.asst-chips{display:flex;flex-wrap:wrap;gap:7px}
/* "Related: FT-12 FT-30" strip under an answer (semantic-retrieval sources). */
.asst-srcs{font-size:var(--fs-meta);color:var(--fg-3);margin:-4px 0 2px;line-height:1.9}
.asst-srcs-lbl{font-family:var(--sans);font-size:var(--fs-label);font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--fg-3);margin-right:4px}
.asst-src{font-family:var(--mono);font-size:var(--fs-meta);padding:2px 7px;border:1px solid var(--line-soft);border-radius:4px;background:var(--raised);color:var(--fg-2);text-decoration:none}
.asst-src:hover{color:var(--fg);border-color:var(--fg-3)}
.asst-src-via{font-family:var(--mono);font-size:var(--fs-meta);margin-left:5px;color:var(--fg-2)}
.asst-src.zd{border-color:color-mix(in srgb,var(--nav) 35%,var(--line))}
.asst-src.doc{font-family:var(--sans)}
.asst-src.qr{border-style:dashed}
/* Unlinked Zendesk report — visually apart from tracked-issue chips. */
.asst-src.zdu{border-color:color-mix(in srgb,#E8964B 45%,var(--line));color:color-mix(in srgb,#E8964B 70%,var(--fg-2))}

/* Related sources as a compact one-per-row list (chips wrapped into mosaic noise). */
.asst-srcs-list{display:flex;flex-direction:column;gap:3px;align-items:stretch}
.asst-srcs-list .asst-srcs-lbl{margin-bottom:2px}
.asst-srcrow{display:flex;gap:7px;align-items:baseline;min-width:0;font-size:12px;text-decoration:none;color:var(--fg-2);border:1px solid var(--line-soft);border-radius:6px;padding:3px 8px;background:var(--raised)}
.asst-srcrow:hover{border-color:var(--fg-3)}
.asst-srcrow .sk{font-family:var(--mono);font-size:11.5px;color:var(--fg);white-space:nowrap;flex:none}
.asst-srcrow .st{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.asst-srcrow .stag{flex:none;font-size:10px;color:var(--fg-3);border:1px solid var(--line);border-radius:8px;padding:0 6px}
.asst-srcrow.zdu .sk{color:color-mix(in srgb,#E8964B 75%,var(--fg))}
.asst-srcrow.zdu .stag{color:color-mix(in srgb,#E8964B 70%,var(--fg-2));border-color:color-mix(in srgb,#E8964B 40%,var(--line))}
.asst-src-more{align-self:flex-start;border:0;background:none;color:var(--fg-3);font-size:11.5px;cursor:pointer;padding:2px 0;text-decoration:underline;text-decoration-color:color-mix(in srgb,var(--fg-3) 50%,transparent)}
.asst-src-more:hover{color:var(--fg-2)}
.asst-zd-ref{color:color-mix(in srgb,#E8964B 75%,var(--fg))}
.asst-rate{display:flex;gap:4px;margin:-2px 0 6px}
.asst-rate-btn{font-size:12px;line-height:1;padding:3px 7px;border:1px solid transparent;border-radius:4px;background:none;cursor:pointer;opacity:.45;filter:grayscale(1)}
.asst-rate-btn:hover{opacity:.9;filter:none;border-color:var(--line-soft)}
.asst-rate-btn.on{opacity:1;filter:none;border-color:var(--line);background:var(--raised)}
.asst-chip{font-family:var(--sans);font-size:var(--fs-label);font-weight:600;padding:6px 11px;border-radius:var(--r);border:1px dashed var(--line);background:none;color:var(--fg-3);cursor:pointer;min-height:36px}
.asst-chip:hover{color:var(--fg);border-color:var(--fg-3);border-style:solid}
.asst-foot{padding:12px;border-top:1px solid var(--line-soft);display:flex;gap:8px;align-items:flex-end}
.asst-foot textarea{flex:1;background:var(--sunken);border:1px solid var(--line);border-radius:var(--r);color:var(--fg);font-family:var(--sans);font-size:14px;padding:10px 12px;resize:none;height:42px;max-height:120px;outline:none}
.asst-foot textarea:focus{border-color:var(--fg-3)}
.asst-typing{display:inline-flex;gap:4px}
.asst-typing i{width:5px;height:5px;border-radius:50%;background:var(--fg-3);animation:asstp 1.2s infinite ease-in-out}
.asst-typing i:nth-child(2){animation-delay:.2s}.asst-typing i:nth-child(3){animation-delay:.4s}
@keyframes asstp{0%,60%,100%{opacity:.3}30%{opacity:1}}

/* ============================================================ BUILD WORKSPACE (session.php) */
.ws-head{display:flex;align-items:center;gap:14px;padding:20px 0 16px}
/* Session title (was an inline style) — lives here so the mobile section can rewrap it. */
.ws-head .ws-title{margin:0;flex:1;max-width:620px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ws-head .sandbox-chip{font-family:var(--mono);font-size:13px;color:var(--fg-2);display:flex;align-items:center;gap:8px}
/* Issue workflow stage — far right of the session header so it is visible
   while the chat has no pipeline spine of its own. */
.ws-head .ws-stage{margin-left:auto}
.banner{border:1px solid var(--line);border-radius:var(--r-lg);padding:12px 15px;font-size:14px;margin-bottom:12px;background:var(--surface)}
.banner code{font-family:var(--mono);font-size:12.5px;background:var(--sunken);border:1px solid var(--line);border-radius:4px;padding:1px 5px}
.banner.ok{border-color:color-mix(in srgb,var(--s-merge) 40%,var(--line))}
.banner.ok strong{color:var(--s-merge)}
.banner.error{border-color:color-mix(in srgb,var(--danger) 40%,var(--line))}
.banner.error{color:var(--fg)}
/* Heads-up, not a failure: the stage amber (automated testing) rather than danger red. */
.banner.warn{border-color:color-mix(in srgb,var(--s-autotest) 55%,var(--line))}
.banner.warn strong{color:var(--s-autotest)}
.diff-trunc{display:flex;align-items:center;gap:12px;flex-wrap:wrap}
.diff-trunc .dt-msg{color:var(--fg-2)}
.diff-trunc .dt-msg strong{color:var(--fg)}
.diff-trunc .btn{text-decoration:none;white-space:nowrap}
.diff-note a{color:var(--nav);text-decoration:none}
.diff-note a:hover{text-decoration:underline}

/* Three panes (sessions rail | chat | changes) with drag-resizer gutters between
   them. Widths come from CSS vars so JS can persist them; the mobile rule below
   hard-codes one column and simply ignores the vars. */
/* 1px visible dividers — the ::after on .build-gutter keeps a ~9px grab zone. */
.build{display:grid;grid-template-columns:var(--rail-w,250px) 1px minmax(0,var(--chat-fr,1.15fr)) 1px minmax(0,var(--right-fr,1fr));gap:0;border:1px solid var(--line);border-radius:var(--r-lg);background:var(--surface);overflow:hidden;height:calc(100vh - 210px);min-height:560px;box-shadow:var(--shadow)}
.build-gutter{position:relative;background:var(--line);cursor:col-resize;transition:background .12s}
.build-gutter::after{content:"";position:absolute;top:0;bottom:0;left:-4px;right:-4px}
.build-gutter:hover,.build-gutter.dragging{background:var(--nav)}
body.col-resizing{cursor:col-resize;user-select:none}
body.col-resizing iframe{pointer-events:none}
/* Collapsed sessions rail = a narrow icon strip; hovering a lane shows its title.
   !important so the collapsed width wins over any inline --rail-w the user set by
   dragging the rail wider (inline styles otherwise beat this class rule). */
.build.rail-collapsed{--rail-w:56px!important}
/* Keep the rail gutter IN the grid (just non-draggable) — display:none removes its
   track and shifts every following pane one column left, collapsing the layout. */
.build.rail-collapsed>[data-resize="rail"]{pointer-events:none;cursor:default}
.build.rail-collapsed>[data-resize="rail"]:hover{background:var(--line)}
.build.rail-collapsed #ws-rail .rail-title,
.build.rail-collapsed #ws-rail .menu-wrap,
.build.rail-collapsed #ws-rail .lane-name,
.build.rail-collapsed #ws-rail .lane-rename,
.build.rail-collapsed #ws-rail .lane-top .t-micro,
.build.rail-collapsed #ws-rail .lane-sub,
.build.rail-collapsed #ws-rail .ws-budget{display:none}
.build.rail-collapsed #ws-rail .bcol-hd{justify-content:center;padding:13px 0}
.build.rail-collapsed #ws-rail .lane{padding:13px 0}
.build.rail-collapsed #ws-rail .lane-top{justify-content:center;gap:0}
.build.rail-collapsed #ws-rail .rail-issue-list .lane{justify-content:center;gap:0}
.rail-toggle{border:0;background:none;color:var(--fg-3);cursor:pointer;font-size:15px;line-height:1;padding:2px 6px;border-radius:5px;flex:none}
.rail-toggle:hover{color:var(--fg);background:var(--raised)}
/* Rail scope tabs — "All chats" (every live chat, grouped by issue) vs "This
   issue" (siblings, the original rail). The .rail-all class on .build picks
   which list renders; both are in the DOM so switching never refetches. */
.rail-scope{display:inline-flex;background:var(--sunken);border:1px solid var(--line-soft);border-radius:var(--r);overflow:hidden;flex:none;min-width:0}
.rail-scope button{background:none;border:0;color:var(--fg-2);font:inherit;font-size:12.5px;font-weight:600;letter-spacing:.03em;padding:5px 10px;min-height:30px;cursor:pointer;white-space:nowrap}
.rail-scope button:hover{color:var(--fg)}
.rail-scope button[aria-pressed="true"]{background:var(--raised);color:var(--fg)}
#ws-rail .rail-all-list{display:none}
.build.rail-all #ws-rail .rail-all-list{display:block}
.build.rail-all #ws-rail .rail-issue-list{display:none}
/* This-issue rail: one line so the title keeps the leftover width. State
   lives in the dot (+ 💤 when sleeping); mode/branch stay in the tooltip.
   The old two-line row (lane-top + lane-sub) crushed titles to "C…". */
.rail-issue-list .lane{display:flex;align-items:center;gap:8px;padding:12px 16px;min-height:44px}
.rail-issue-list .lane-name{flex:1;min-width:0}
.rail-issue-list .lane-glyph{flex:none}
/* Branch chip on This-issue rows (only when the issue has several branches):
   a mono pill after the title that can still truncate, so "bm-12.0.152"
   reads at a glance without stealing the title's line. */
.rail-issue-list .lane-branch{font-family:var(--mono);font-size:12px;color:var(--fg-2);border:1px solid var(--line);border-radius:9px;padding:0 6px;line-height:1.6;max-width:42%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rail-issue-list .lane[aria-current="true"] .lane-branch{color:var(--fg);border-color:var(--fg-3)}
.rail-grp{border-bottom:1px solid var(--line-soft)}
.rail-grp:last-child{border-bottom:none}
.rail-grp-hd{display:flex;align-items:center}
.rail-grp-hd:hover{background:var(--raised)}
.rail-grp-fold{display:flex;align-items:center;gap:8px;flex:1;min-width:0;background:none;border:0;padding:11px 4px 11px 12px;cursor:pointer;text-align:left;color:inherit;min-height:40px}
.rail-grp-chev{color:var(--fg-3);flex:none;transition:transform .15s ease}
.rail-grp.folded .rail-grp-chev{transform:rotate(-90deg)}
@media (prefers-reduced-motion: reduce){ .rail-grp-chev{transition:none} }
.rail-grp-key{font-family:var(--mono);font-size:13px;color:var(--fg-2);flex:none}
.rail-grp-title{font-size:13.5px;font-weight:550;color:var(--fg);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1}
.rail-grp-dot{width:8px;height:8px;border-radius:50%;flex:none}
.rail-grp-new{border:0;background:none;color:var(--fg-3);cursor:pointer;font-size:15px;line-height:1;padding:8px 12px 8px 8px;flex:none;border-radius:4px;opacity:.55;align-self:stretch}
.rail-grp-hd:hover .rail-grp-new,.rail-grp-new:focus-visible{opacity:1}
.rail-grp-new:hover{color:var(--fg)}
.rail-grp.folded .rail-grp-rows{display:none}
/* One-line all-chats rows: state lives in the dot's color (full text in the
   tooltip), 💤/🧪 glyphs, compact age. The sub-line was two rows of prose. */
.rail-grp-rows .lane.lane-slim{display:flex;align-items:center;gap:9px;padding:10px 14px 10px 30px;min-height:38px}
.lane-slim .lane-name{font-size:14px;font-weight:500;flex:1}
.lane-glyph{flex:none;font-size:12px;line-height:1}
.lane-slim .lane-when{margin-left:0;flex:none;font-family:var(--mono);font-size:13px;color:var(--fg-3);font-variant-numeric:tabular-nums}
.rail-grp-need{flex:none;font-family:var(--mono);font-size:12.5px;font-weight:600;color:var(--s-qa);border:1px solid color-mix(in srgb,var(--s-qa) 45%,transparent);background:color-mix(in srgb,var(--s-qa) 12%,transparent);border-radius:9px;padding:0 6px;line-height:1.5}
/* Rail chat search — its own header row (flex-basis:100%); a cramped rail wraps
   the + New menu down beside it instead of overflowing into the chat pane. */
#ws-rail .bcol-hd{flex-wrap:wrap}
.rail-search{display:none;flex-basis:100%;min-width:0;gap:8px;align-items:center}
.build.rail-all #ws-rail .rail-search{display:flex}
.rail-search input{flex:1;min-width:0;background:var(--sunken);border:1px solid var(--line-soft);border-radius:var(--r);color:var(--fg);font:inherit;font-size:13.5px;padding:8px 11px;min-height:36px;outline:none}
.rail-foldall{flex:none;display:flex;align-items:center;justify-content:center;width:36px;min-height:36px;background:var(--sunken);border:1px solid var(--line-soft);border-radius:var(--r);color:var(--fg-3);cursor:pointer}
.rail-foldall:hover{color:var(--fg);border-color:var(--fg-3)}
.rail-search input::placeholder{color:var(--fg-3)}
.rail-search input:focus{border-color:var(--fg-3)}
/* !important: beats the .rail-searching overflow-reveal below, so a hidden-tail
   group that does NOT match the query stays hidden while searching. */
.rail-grp.search-miss,.rail-grp .lane.search-miss{display:none!important}
.rail-grp.search-open .rail-grp-rows{display:block}
/* Overflow cap: groups past ~50 chats hide behind one "Show all" row; opening
   it (or a live search) reveals the tail. The current chat's group is exempt
   server-side and never carries .rail-overflow. */
.rail-grp.rail-overflow{display:none}
.rail-all-list.rail-show-all .rail-grp.rail-overflow,
.rail-all-list.rail-searching .rail-grp.rail-overflow{display:block}
.rail-all-list.rail-show-all .rail-more,
.rail-all-list.rail-searching .rail-more{display:none}
.rail-more{display:block;width:100%;background:none;border:0;border-bottom:1px solid var(--line-soft);color:var(--fg-2);font:inherit;font-size:13.5px;font-weight:500;padding:12px 16px;text-align:left;cursor:pointer;min-height:40px}
.rail-more:hover{background:var(--raised);color:var(--fg)}
.rail-search-none{padding:16px;font-size:var(--fs-ui);color:var(--fg-2)}
/* New activity since you last opened that chat: ringed dot + firmer title. */
.lane-new .lane-name{font-weight:650}
.lane-new .dot{box-shadow:0 0 0 2px color-mix(in srgb,var(--nav) 45%,transparent)}
/* Submitted chats are done — sunk to the bottom of their group and faded. */
.lane.lane-done{opacity:.55}
.lane.lane-done:hover,.lane.lane-done:focus-visible{opacity:.9}
.lane-glyph-done{color:var(--s-merge);font-size:13px;font-weight:600}
/* Collapsed rail + all-chats scope: the icon strip stays one dot per chat —
   group headers and search vanish, folds are ignored so no dot disappears. */
.build.rail-collapsed #ws-rail .rail-grp-hd,
.build.rail-collapsed #ws-rail .rail-search,
.build.rail-collapsed #ws-rail .rail-more,
.build.rail-collapsed #ws-rail .lane-glyph,
.build.rail-collapsed #ws-rail .lane-when{display:none}
.build.rail-collapsed #ws-rail .rail-grp.folded .rail-grp-rows{display:block}
.build.rail-collapsed #ws-rail .lane.lane-slim{justify-content:center;padding:13px 0}
/* Right (Changes/Activity) pane collapse — the mirror of the rail's icon
   strip: the pane folds to a vertical "Changes" edge tab. Desktop only;
   phones open this pane as a bottom sheet, so the toggle hides there. */
.right-edge{display:none}
@media (min-width:1101px){
	.build.right-collapsed{grid-template-columns:var(--rail-w,250px) 1px minmax(0,1fr) 1px 44px}
	.build.right-collapsed>[data-resize="split"]{pointer-events:none;cursor:default}
	.build.right-collapsed>[data-resize="split"]:hover{background:var(--line)}
	.build.right-collapsed #ws-bcol>*:not(.right-edge){display:none}
	.build.right-collapsed .right-edge{display:flex;align-items:flex-start;justify-content:center;padding-top:14px}
	.right-edge{writing-mode:vertical-rl;background:none;border:0;color:var(--fg-2);font:inherit;font-size:13.5px;font-weight:500;letter-spacing:.02em;cursor:pointer;width:100%;height:100%}
	.right-edge:hover{color:var(--fg);background:var(--raised)}
	.right-edge-n{font-family:var(--mono);font-size:13px;color:var(--s-merge);margin-top:6px}
}
@media (max-width:1100px){.right-toggle{display:none}}
/* Build workspace: lock the whole page to the viewport so ONLY the panes scroll
   (no stray page scroll). Body is a flex column [topbar · shell]; the shell is a
   nested column whose .build fills the gap between ws-head and the submitbar. */
body.session-body:not(.embed){height:100vh;height:100dvh;overflow:hidden;display:flex;flex-direction:column}
body.session-body:not(.embed) .topbar{flex:none}
/* width:100% + no cap: as a flex item with auto margins the shell would otherwise
   size to its CONTENT (fit-content), so switching Changes↔Activity visibly grew and
   shrank the page. The workspace is an app view — let it fill the viewport instead. */
body.session-body:not(.embed) .shell{flex:1 1 auto;min-height:0;height:auto;padding-bottom:0;display:flex;flex-direction:column;overflow:hidden;width:100%;max-width:none}
body.session-body:not(.embed) .ws-head,body.session-body:not(.embed) .banner,body.session-body:not(.embed) .submitbar,body.session-body:not(.embed) .rebase-bar,body.session-body:not(.embed) .shell>.console{flex:none}
body.session-body:not(.embed) .build{height:auto;flex:1 1 auto;min-height:0}
@media (max-width:1100px){
	body.session-body:not(.embed){height:auto;overflow:auto;display:block}
	body.session-body:not(.embed) .shell{height:auto;padding-bottom:40px;display:block}
	body.session-body:not(.embed) .build{flex:none;height:auto}
}
.build.has-bar{border-radius:var(--r-lg) var(--r-lg) 0 0}
@media (max-width:1100px){.build{grid-template-columns:1fr;height:auto}.build-gutter{display:none}.build>.bcol:not(:first-of-type){border-top:1px solid var(--line)}}
.build>*{min-width:0}
.bcol{display:flex;flex-direction:column;min-height:0}
.bcol-hd{display:flex;align-items:center;gap:10px;padding:13px 15px;border-bottom:1px solid var(--line-soft);flex:none}
/* Chat header title: shrink + ellipsis so a long session name cannot
   shove the action buttons into the next pane (Zendesk 354316). Same
   flex recipe as .df-path — size to content, shrink when the row is tight.
   Overflow stays off .bcol-hd itself so Options / menus are not clipped. */
#ws-chat .bcol-hd{min-width:0;max-width:100%}
#ws-chat .bcol-hd > :not(#session-title):not(.spacer):not(.hd-branch){flex-shrink:0}
/* Chat-header branch pill: full branch basename next to the title; it
   shrinks (ellipsis) before the option chips do on a narrow pane. */
#ws-chat .bcol-hd .hd-branch{flex:0 1 auto;min-width:48px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:var(--mono);font-size:12.5px;color:var(--fg-2);border:1px solid var(--line);background:var(--sunken);border-radius:9px;padding:1px 8px;line-height:1.5}
#ws-chat .bcol-hd #session-title{flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
#ws-chat .bcol-hd #session-title:has(input){flex:1 1 auto;min-width:120px;overflow:visible}
#ws-chat .bcol-hd:has(#session-title input) .spacer{flex:0 0 0}
#ws-chat .bcol-hd #session-title .title-input{font-size:inherit;font-weight:inherit;letter-spacing:inherit;text-transform:inherit;min-height:0;padding:1px 6px}
#ws-chat .bcol-hd .spacer{min-width:0}
/* Chat header ⋯ (hdFold in session.php): when the column is too narrow for
   the action chips, the whole #hd-acts group moves into this popover and lays
   out as a column. Options ▾ flattens into its checkbox rows there — the menu
   is forced visible even with [hidden], because the click-outside handler
   keeps re-hiding every menu and that must not matter inside the popover.
   Chips keep their ids and handlers, so no JS elsewhere notices the move. */
.hd-acts{display:flex;align-items:center;gap:inherit;min-width:0}
.hd-more-btn{padding:7px 10px;min-width:36px;justify-content:center;font-size:15px}
.hd-more-btn[aria-expanded="true"]{color:var(--fg);background:var(--raised)}
.hd-more-pop{position:absolute;right:0;top:calc(100% + 6px);z-index:50;min-width:260px;max-width:min(380px,calc(100vw - 24px));padding:5px;background:var(--surface);border:1px solid var(--line);border-radius:var(--r-lg);box-shadow:var(--shadow)}
.hd-more-pop .hd-acts{flex-direction:column;align-items:stretch;gap:2px}
.hd-more-pop .ha-sep{display:none}
.hd-more-pop .btn{display:block;width:100%;max-width:none;text-align:left;padding:10px 10px;font-size:var(--fs-ui);line-height:1.15;color:var(--fg);border-radius:var(--r);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.hd-more-pop .overlay-push{display:flex}
.hd-more-pop .overlay-push-split{width:100%}
.hd-more-pop .overlay-push-main{flex:1 1 auto;width:auto;min-width:0}
.hd-more-pop .overlay-push-more{flex:none;width:auto;text-align:center}
.hd-more-pop #ws-opts-wrap > .btn{display:none}
.hd-more-pop #ws-opts-menu,.hd-more-pop #ws-opts-menu[hidden]{display:block !important;position:static;min-width:0;max-width:none;max-height:none;overflow:visible;margin-top:4px;padding:4px 0 0;border:0;border-top:1px solid var(--line-soft);border-radius:0;box-shadow:none}
.hd-more-pop .menu-model{border-bottom:0;padding:6px 10px}
#ws-chat .bcol-hd.hd-no-when .hd-when{display:none}
/* Changes pane header: tabs + Download/Refresh/Merge/Expand + Open the
   test site overflow a single nowrap row when the desktop column is
   narrowed (the splitter, not a viewport shrink). Track the pane width
   so wrapping follows the column. Overflow stays off .bcol-hd itself
   so menus are not clipped — same recipe as the chat header above.
   Zendesk 354908. */
#ws-bcol{container-type:inline-size;container-name:ws-right;min-width:0}
#ws-bcol .bcol-hd{min-width:0;max-width:100%}
#ws-bcol .bcol-hd > .head-actions{flex-wrap:wrap;row-gap:8px;min-width:0}
#ws-bcol .bcol-hd .tool-link{white-space:nowrap}
@container ws-right (max-width: 820px) {
	#ws-bcol .bcol-hd{flex-wrap:wrap;row-gap:8px;align-items:center}
	#ws-bcol .bcol-hd > .seg{flex:1 1 auto;min-width:0;max-width:calc(100% - 36px);order:1;overflow-x:auto;scrollbar-width:none}
	#ws-bcol .bcol-hd > .seg::-webkit-scrollbar{display:none}
	#ws-bcol .bcol-hd > .right-toggle{order:2;flex:none}
	#ws-bcol .bcol-hd > .spacer{display:none}
	#ws-bcol .bcol-hd > .head-actions{order:4;flex:1 1 auto}
}
.bcol-bd{flex:1;overflow:auto;min-height:0}
.ws-budget{flex:none;border-top:1px solid var(--line-soft);padding:11px 13px}
.ws-budget .bar{height:3px;background:var(--line-soft);border-radius:2px;margin-top:7px;overflow:hidden}
.ws-budget .bar>div{height:100%;background:var(--fg-3);border-radius:2px}

/* chat turns — hairlines, no bubbles for the assistant */
.spec-box{margin:12px 13px;border:1px solid var(--line-soft);border-radius:var(--r);background:var(--sunken)}
.spec-box summary{cursor:pointer;padding:10px 13px;font-family:var(--sans);font-size:var(--fs-label);font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--fg-3)}
.spec-box>div{padding:0 13px 13px;font-size:14px;line-height:1.6;color:var(--fg-2);white-space:pre-wrap}
.msg{padding:14px 16px;border-bottom:1px solid var(--line-soft);display:flex;flex-direction:column}
.msg .who-line{display:flex;align-items:baseline;justify-content:space-between;gap:12px;margin-bottom:7px}
.msg .who{font-family:var(--sans);font-size:var(--fs-label);font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--fg-3);margin-bottom:0}
.msg.user .who{color:var(--fg-2)}
.msg .msg-when{font-family:var(--mono);font-size:var(--fs-meta);font-weight:400;letter-spacing:0;text-transform:none;color:var(--fg-2);white-space:nowrap;flex:none}
#ws-chat .bcol-hd .hd-when{font-family:var(--mono);font-size:var(--fs-meta);color:var(--fg-2);white-space:nowrap;flex:none}
/* Claude's replies read as plain flowing text — no container. Chat is primary
   content, so it sits on the lead tier. */
.msg .bubble{font-size:15px;line-height:1.62;color:var(--fg);white-space:pre-wrap;word-wrap:break-word;background:none;border:0;border-radius:0;padding:0}
/* Your messages are a boxed, inset bubble with a left accent, so they're easy to
   tell apart from the reply at a glance. */
.msg.user .bubble{background:var(--sunken);border:1px solid var(--line);border-left:2px solid var(--fg-3);border-radius:var(--r);padding:11px 13px}
.msg.user.queued .bubble{border-left-color:var(--s-qa);opacity:.75}
.queued-tag{margin-top:4px;font-size:11px;color:var(--s-qa);letter-spacing:.02em;display:flex;align-items:center;gap:8px}
.queued-x{border:0;background:none;color:var(--s-qa);cursor:pointer;font-size:16px;line-height:1;padding:0 3px;border-radius:4px;opacity:.7}
.queued-x:hover{opacity:1;color:var(--danger);background:var(--surface)}
.msg-images{display:flex;gap:6px;flex-wrap:wrap;margin:0 0 7px}
.msg-images img{width:54px;height:54px;object-fit:cover;border-radius:var(--r);border:1px solid var(--line)}
.typing{display:inline-flex;gap:4px}
.typing i{width:5px;height:5px;border-radius:50%;background:var(--fg-3);animation:asstp 1.2s infinite ease-in-out}
.typing i:nth-child(2){animation-delay:.2s}.typing i:nth-child(3){animation-delay:.4s}
.console{font-family:var(--mono);font-size:12px;line-height:1.6;color:var(--fg-2);background:var(--sunken);border:1px solid var(--line-soft);border-radius:var(--r);padding:9px 11px;margin-top:8px;white-space:pre-wrap;max-height:220px;overflow:auto}
.console:empty{display:none}
/* Tool log stays open unless the user hid it (ft-hide-tools). The status-line
   "tools ▸ / tools ▾" control is the only closer. */
.msg.tools-hidden > .console{display:none}
.turn-status .tools-toggle{all:unset;cursor:pointer;margin-left:auto;font-family:var(--sans);font-size:var(--fs-label);font-weight:600;color:var(--fg-3);min-height:36px;padding:0 4px;display:inline-flex;align-items:center}
.turn-status.running .tools-toggle,.turn-status.done .tools-toggle,.turn-status.error .tools-toggle{color:var(--fg-3)}
.turn-status .tools-toggle:hover{color:var(--fg-2)}
/* E2E spec-run result cards (run-spec's DOCKET_SPEC_RESULT lines, rendered by
   renderSpecCards): green = every spec passed, red/danger = anything else. */
.spec-runs{display:flex;flex-direction:column;gap:6px;margin:8px 0 0}
.spec-card{border:1px solid var(--line);border-radius:var(--r);padding:9px 12px;font-size:13px;background:var(--surface)}
.spec-card.pass{border-color:color-mix(in srgb,var(--s-merge) 45%,transparent);background:color-mix(in srgb,var(--s-merge) 9%,var(--surface))}
.spec-card.fail{border-color:color-mix(in srgb,var(--danger) 45%,transparent);background:color-mix(in srgb,var(--danger) 9%,var(--surface))}
.spec-card-hd{font-weight:600;font-size:13px}
.spec-card.pass .spec-card-hd{color:var(--s-merge)}
.spec-card.fail .spec-card-hd{color:var(--danger)}
.spec-line{font-family:var(--mono);font-size:12.5px;color:var(--fg-2);margin-top:3px}
/* Session Artifacts tab: agent-browser screenshots as a thumbnail grid
   (loadArtifacts). Bytes come through api/attachment.php like every other
   attachment; clicking opens the full image in a new tab. */
.artifacts-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(190px,1fr));gap:10px;padding:12px}
.artifact-card{position:relative;display:flex;flex-direction:column;border:1px solid var(--line);border-radius:var(--r);overflow:hidden;background:var(--surface);text-decoration:none}
.artifact-card img,.artifact-card video{width:100%;height:126px;object-fit:cover;object-position:top;display:block;background:var(--sunken)}
.artifact-play{position:absolute;top:47px;left:50%;transform:translateX(-50%);font-size:22px;color:#fff;text-shadow:0 1px 6px rgba(0,0,0,.7);pointer-events:none}
.artifact-meta{padding:6px 9px}
.artifact-name{font-size:12.5px;color:var(--fg);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.artifact-when{font-size:12px;color:var(--fg-3)}
/* HTML artifacts (agent-authored mockups/prototypes): a scaled-down live
   preview inside a sandboxed iframe. pointer-events off in thumbnails so the
   card's click (→ lightbox) always wins over the page inside. */
.artifact-frame{position:relative;overflow:hidden;background:#fff}
.artifact-card .artifact-frame,.msg-art .artifact-frame{height:126px}
.artifact-frame.thumb iframe{width:400%;height:400%;transform:scale(.25);transform-origin:0 0;border:0;pointer-events:none;display:block;background:#fff}
/* In-chat artifact strip: this turn's new screenshots / videos / mockups,
   rendered directly under the agent's bubble (renderTurnArtifacts). */
.msg-artifacts{display:flex;flex-wrap:wrap;gap:8px;margin-top:8px}
.msg-art{position:relative;width:172px;border:1px solid var(--line);border-radius:var(--r);overflow:hidden;background:var(--surface);cursor:zoom-in}
.msg-art img,.msg-art video{width:100%;height:108px;object-fit:cover;object-position:top;display:block;background:var(--sunken)}
.msg-art .artifact-frame{height:108px}
.msg-art .artifact-play{top:38px}
.msg-art-name{font-size:11.5px;color:var(--fg-2);padding:4px 7px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;border-top:1px solid var(--line)}
/* Artifact lightbox: click a shot → full-size modal with ←/→ through the
   set and Esc to close (openShot). Same overlay conventions as .rev-overlay. */
.shot-overlay{position:fixed;inset:0;z-index:320;background:color-mix(in srgb,var(--bg) 80%,transparent);backdrop-filter:blur(2px);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;opacity:0;pointer-events:none;transition:opacity .16s ease}
.shot-overlay.open{opacity:1;pointer-events:auto}
.shot-overlay img,.shot-overlay video{max-width:92vw;max-height:82vh;border:1px solid var(--line);border-radius:var(--r);background:var(--surface);box-shadow:0 18px 60px rgba(0,0,0,.45)}
/* Full-size HTML artifact in the lightbox: an interactive (still sandboxed)
   page — fixed generous size so mockups lay out like a real viewport. */
.shot-overlay .shot-frame{width:min(1100px,92vw);height:min(760px,80vh);border:1px solid var(--line);border-radius:var(--r);background:#fff;box-shadow:0 18px 60px rgba(0,0,0,.45)}
.shot-bar{display:flex;align-items:center;gap:12px;font-size:12.5px;color:var(--fg-2)}
.shot-bar .shot-name{font-family:var(--mono);color:var(--fg)}
.shot-nav{position:fixed;top:50%;transform:translateY(-50%);font-size:28px;line-height:1;padding:16px 12px;color:var(--fg-2);background:transparent;border:0;cursor:pointer}
.shot-nav:hover{color:var(--fg)}
.shot-nav.prev{left:6px}
.shot-nav.next{right:6px}
.shot-x{position:fixed;top:10px;right:14px;font-size:20px;color:var(--fg-2);background:transparent;border:0;cursor:pointer;padding:8px}
.shot-x:hover{color:var(--fg)}
/* Trailing TL;DR line of an agent reply, lifted into a summary strip
   (renderBubbleMd). Deliberately colorless — hue stays reserved for state. */
.msg .tldr{margin-top:10px;padding:8px 12px;border-left:3px solid var(--fg-3);background:var(--sunken);border-radius:0 var(--r) var(--r) 0;font-size:14px;color:var(--fg)}
.msg .tldr .tldr-tag{font-family:var(--mono);font-size:12px;letter-spacing:.04em;color:var(--fg-2);font-weight:600;margin-right:7px}
.turn-status{font-family:var(--mono);font-size:12.5px;margin-top:8px;display:flex;align-items:center;gap:7px;color:var(--fg-3)}
.turn-status.running{color:var(--s-autotest)}
.turn-status.done{color:var(--s-merge)}
.turn-status.error{color:var(--danger)}
.turn-status .dot{width:6px;height:6px;border-radius:50%;background:currentColor}
.turn-status .reason{color:var(--fg-3)}

/* composer */
.chat-input{flex:none;border-top:1px solid var(--line);padding:13px 15px}
.chat-input textarea{width:100%;background:var(--sunken);border:1px solid var(--line);border-radius:var(--r);color:var(--fg);font-family:var(--sans);font-size:15px;padding:12px 14px;resize:none;min-height:48px;max-height:220px;outline:none}
.chat-input textarea:focus{border-color:var(--fg-3)}
.chat-input textarea:disabled{opacity:.6}
.ci-toolbar{display:flex;align-items:center;gap:10px;margin-top:10px;flex-wrap:wrap}
/* The hint keeps a readable floor; when space runs out the ACTIONS cluster
   wraps to its own row as a unit (never the send arrow alone). An empty hint
   collapses to nothing and forces no wrap. */
.ci-hint{font-size:13px;color:var(--fg-3);flex:1}
.ci-hint:not(:empty){min-width:160px}
/* Chips + Send wrap together as one cluster, pinned right. */
.ci-actions{display:flex;align-items:center;gap:10px;margin-left:auto}
/* Composer chips match the 36px icon-button row (uniform control height). */
.ci-actions .sess-model-sel{height:36px;display:inline-flex;align-items:center;padding:0 12px;font-size:12.5px;background:var(--surface);color:var(--fg-2);white-space:nowrap;overflow:hidden}
.ci-actions .sess-model-sel:hover{color:var(--fg);border-color:var(--fg-3)}
/* Context gauge chip: a small donut ring (like Claude Code's) — the fill arc is the used share. Neutral until the window actually fills; amber from 70%, red from 85% (auto-compact territory). */
.ci-actions .ctx-chip{padding:0 9px;color:var(--fg-2)}
.ctx-chip svg{display:block}
.ctx-ring-bg{fill:none;stroke:var(--line);stroke-width:2.5}
.ctx-ring-fill{fill:none;stroke:currentColor;stroke-width:2.5;stroke-linecap:round}
.ctx-chip.warn{color:var(--s-autotest);border-color:color-mix(in srgb,var(--s-autotest) 45%,var(--line))}
.ctx-chip.hot{color:var(--danger);border-color:color-mix(in srgb,var(--danger) 45%,var(--line))}
/* Compaction divider: the moment older chat history became a summary. */
.msg-divider{display:flex;align-items:center;gap:10px;margin:14px 0;color:var(--fg-3);font-size:12.5px;text-align:center}
.msg-divider::before,.msg-divider::after{content:'';flex:1;border-top:1px dashed var(--line)}
.msg-divider span{max-width:80%}
/* Ghost reply suggestion: the placeholder IS the suggestion, so it steps up from hint-grey to readable metadata grey; the hint becomes the mobile tap target. */
.chat-input textarea.suggesting::placeholder{color:var(--fg-2);opacity:1}
.ci-hint.suggest-on{color:var(--fg-2);cursor:pointer}
.attach-btn{width:36px;height:36px;border-radius:var(--r);border:1px solid var(--line);background:var(--surface);color:var(--fg-2);display:grid;place-items:center;cursor:pointer;flex:none}
.attach-btn:hover{color:var(--fg);border-color:var(--fg-3)}
/* Bell ON must read at a glance — the old color+border step-up was identical to :hover. Filled glyph + sunken well = latched toggle, still neutral (color stays reserved for state). */
.ding-btn.on{color:var(--fg);border-color:var(--fg-3);background:var(--sunken);box-shadow:inset 0 1px 3px rgba(0,0,0,.35)}
.ding-btn.on svg{fill:currentColor}
/* Zendesk pull-in toggle in the chat composer — text glyph, reads as a chip. */
.zd-pull-btn{font-family:var(--mono);font-size:12px;font-weight:600;letter-spacing:.02em}
.zd-pull-btn:disabled{opacity:.5;cursor:default}
/* Background spec run (e2e chats): pulse while the tokenless run is going;
   a filled glyph marks an armed run-until-green loop. */
/* Live strip above the composer while a background run executes: the button
   pulse alone was invisible in practice (s732) — this names the specs and
   counts the elapsed time, server-rendered so reloads keep it. */
.runspec-live{display:flex;align-items:center;gap:8px;font-family:var(--mono);font-size:12.5px;color:var(--s-autotest);padding:0 2px 9px}
.runspec-live .dot{width:6px;height:6px;border-radius:50%;background:currentColor;animation:runspec-pulse 1.4s ease-in-out infinite;flex:none}
.runspec-live .elapsed{color:var(--fg-3)}
/* Branch→site upgrade (and a site chat's first provision): a sentence, so
   sans at --fs-ui — not the runspec mono strip. Hue is the in-flight token. */
.site-upgrade-live{display:flex;align-items:center;gap:8px;font-family:var(--sans);font-size:var(--fs-ui);font-weight:500;color:var(--fg);padding:0 2px 9px;line-height:1.5}
.site-upgrade-live .dot{width:8px;height:8px;border-radius:50%;background:var(--s-autotest);box-shadow:0 0 0 3px color-mix(in srgb,var(--s-autotest) 20%,transparent);animation:runspec-pulse 1.4s ease-in-out infinite;flex:none}
.site-upgrade-live .elapsed{font-family:var(--mono);font-size:var(--fs-meta);color:var(--fg-2);font-weight:400}
.runspec-btn.running{color:var(--fg);border-color:var(--fg-3);animation:runspec-pulse 1.4s ease-in-out infinite}
.runspec-btn.armed{color:var(--fg);border-color:var(--fg-3)}
.runspec-btn.armed svg{fill:currentColor}
.runspec-btn:disabled{cursor:default}
/* Auto-fix composer: labeled Run test — same 36px attach-btn well, sans label. */
.run-test-btn{width:auto;padding:0 12px;font-family:var(--sans);font-size:var(--fs-ui,14px);font-weight:500;letter-spacing:0;white-space:nowrap}
.run-test-btn.running{color:var(--fg);border-color:var(--fg-3);animation:runspec-pulse 1.4s ease-in-out infinite}
.run-test-btn:disabled{cursor:default;opacity:.6}
@keyframes runspec-pulse{0%,100%{opacity:1}50%{opacity:.45}}
.send-btn{width:36px;height:36px;border-radius:var(--r);border:none;background:var(--bone);color:var(--on-bone);display:grid;place-items:center;cursor:pointer;flex:none}
.send-btn:hover{filter:brightness(.94)}
.send-btn:disabled{opacity:.5;cursor:default}
.attach-tray{display:flex;flex-wrap:wrap;gap:7px;padding:0 0 9px}
.attach-thumb{position:relative;width:52px;height:52px;border-radius:var(--r);overflow:hidden;border:1px solid var(--line)}
.attach-thumb img{width:100%;height:100%;object-fit:cover}
.attach-x{position:absolute;top:2px;right:2px;width:17px;height:17px;border:0;border-radius:50%;background:rgba(0,0,0,.6);color:#fff;font-size:12px;cursor:pointer}
/* Non-image attachment chip (logs, diffs, source) — labeled, no thumbnail. */
.attach-file{position:relative;display:flex;align-items:center;gap:6px;max-width:180px;height:52px;padding:0 26px 0 10px;border-radius:var(--r);border:1px solid var(--line);background:var(--bg-1,transparent)}
.attach-file-ic{flex:none;font-size:16px;line-height:1}
.attach-file-nm{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:12px;color:var(--fg-2)}
.attach-file .attach-x{background:var(--fg-2,#888)}
/* File attachments inside a sent message bubble. */
.msg-files{display:flex;gap:6px;flex-wrap:wrap;margin:0 0 7px}
.msg-file{display:inline-flex;align-items:center;gap:6px;max-width:220px;padding:5px 9px;border-radius:var(--r);border:1px solid var(--line);background:var(--bg-1,transparent);font-size:12px;color:var(--fg-2);text-decoration:none}
.msg-file span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Interactive QA checklist (idea 13): rows layered over the qa_steps text. */
.qa-step{padding:8px 10px;margin:4px 0;border:1px solid var(--line-soft);border-radius:var(--r);background:var(--bg-1,transparent)}
.qa-step.qa-pass{border-color:color-mix(in srgb,var(--s-merge) 45%,transparent)}
.qa-step.qa-fail{border-color:color-mix(in srgb,var(--danger) 55%,transparent)}
.qa-step.qa-na{opacity:.6}
.qa-step-top{display:flex;align-items:flex-start;gap:8px}
.qa-step-n{flex:none;width:20px;height:20px;display:inline-flex;align-items:center;justify-content:center;border:1px solid var(--line);border-radius:50%;font-size:11px;color:var(--fg-2)}
.qa-step-text{flex:1;font-size:13.5px;line-height:1.45}
.qa-btns{display:inline-flex;gap:4px;margin-left:auto}
.qa-btn{width:26px;height:24px;border:1px solid var(--line);border-radius:var(--r);background:transparent;color:var(--fg-2);cursor:pointer;font-size:13px;line-height:1}
.qa-btn:hover{border-color:var(--fg-3)}
.qa-btn.on{color:#fff;border-color:transparent}
.qa-step.qa-pass .qa-btn.on{background:var(--s-merge)}
.qa-step.qa-fail .qa-btn.on{background:var(--danger)}
.qa-step.qa-na .qa-btn.on{background:var(--fg-3)}
.qa-step-note{margin:6px 0 0 28px;font-size:12.5px;color:var(--fg-2);white-space:pre-wrap}
.qa-agent-chip{flex:none;font-size:11px;padding:1px 7px;border-radius:999px;border:1px solid var(--line);color:var(--fg-2)}
.qa-agent-pass{color:var(--s-merge);border-color:color-mix(in srgb,var(--s-merge) 45%,transparent)}
.qa-agent-fail{color:var(--danger);border-color:color-mix(in srgb,var(--danger) 55%,transparent)}
.qa-lastfail{margin:0 0 8px;padding:7px 10px;border-radius:var(--r);font-size:12.5px;color:var(--danger);border:1px dashed color-mix(in srgb,var(--danger) 55%,transparent)}
/* The failed-step fix action must not blend in with quiet buttons. */
.btn.qa-fix-btn{margin-top:6px;color:var(--danger);border-color:color-mix(in srgb,var(--danger) 55%,transparent)}
.btn.qa-fix-btn:hover{background:color-mix(in srgb,var(--danger) 12%,transparent);border-color:var(--danger)}
/* Screenshot lightbox: evidence + comment thumbnails open here, not a tab. */
.img-modal{position:fixed;inset:0;z-index:300;background:rgba(0,0,0,.7);display:flex;align-items:center;justify-content:center;flex-direction:column;gap:10px;padding:24px}
.img-modal img{max-width:92vw;max-height:80vh;border-radius:var(--r);border:1px solid var(--line);background:#fff}
.img-modal-bar{display:flex;gap:10px;align-items:center;color:#fff;font-size:13px}
.img-modal-bar a{color:#fff;border-bottom:1px dashed rgba(255,255,255,.5)}
.qa-md{margin:6px 0}
/* Attachments on activity-feed comments + pre-walk evidence (idea 12). */
.ev-attachments{display:flex;flex-wrap:wrap;gap:8px;margin-top:6px;align-items:center}
.ev-att-img{display:block;max-width:180px;max-height:130px;border-radius:var(--r);overflow:hidden;border:1px solid var(--line)}
.ev-att-img img{display:block;max-width:180px;max-height:130px;object-fit:cover}
/* Inline markdown images (![alt](url)) — click opens the lightbox. */
.md-img{display:block;max-width:min(100%,520px);max-height:360px;border:1px solid var(--line);border-radius:var(--r);margin:6px 0;cursor:zoom-in}
/* Issue Attachments card (rail): every claimed attachment in one place. */
#att-card.drag{outline:2px dashed var(--fg-3);outline-offset:-2px}
.att-list{display:flex;flex-direction:column;padding:4px 8px 10px}
.att-empty{margin:4px 6px 2px}
.att-row{display:flex;align-items:center;gap:9px;padding:5px 6px;border-radius:var(--r)}
.att-row:hover{background:var(--sunken)}
.att-thumb{flex:none;width:36px;height:36px;border-radius:6px;overflow:hidden;border:1px solid var(--line);cursor:zoom-in}
.att-thumb img{display:block;width:100%;height:100%;object-fit:cover}
.att-ico{flex:none;width:36px;height:36px;border:1px solid var(--line-soft);border-radius:6px;display:grid;place-items:center;font-size:15px}
.att-meta{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}
.att-name{font-size:13.5px;color:var(--fg);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;cursor:pointer}
.att-name:hover{text-decoration:underline}
.att-sub{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* Attachment row icon buttons (copy-markdown, remove): bare reset (no stray
   container padding), circular, muted by default and reveal on row hover. */
.att-x,.att-copy{flex:none;appearance:none;-webkit-appearance:none;margin:0;padding:0;border:none;background:none;font-family:var(--sans);width:28px;height:28px;border-radius:50%;color:var(--fg-3);line-height:1;cursor:pointer;display:grid;place-items:center;opacity:.5;transition:opacity .12s,color .12s,background .12s,transform .08s}
.att-x{font-size:20px}
/* The ⧉ glyph reads smaller than × at the same size — bump it to match weight. */
.att-copy{font-size:17px}
.att-row:hover .att-x,.att-row:hover .att-copy{opacity:.85}
.att-copy:hover{opacity:1;color:var(--fg);background:var(--sunken)}
.att-x:hover{opacity:1;color:var(--danger);background:color-mix(in srgb,var(--danger) 15%,transparent)}
.att-copy:focus-visible{opacity:1;outline:2px solid var(--fg-3);outline-offset:1px}
.att-x:focus-visible{opacity:1;outline:2px solid var(--danger);outline-offset:1px}
.att-x:active,.att-copy:active{transform:scale(.88)}
/* Field editors accept dropped files — mirror the attach-card drop cue. */
.edit-area.drag{outline:2px dashed var(--fg-3);outline-offset:-2px}
.drop-hint{display:none}
/* Markdown cheat sheet (popup on ticket.php) + full guide (markdown.php). */
/* The composer hint doubles as the trigger — a plain-text button (no UA
   chrome in either theme), just a dashed underline to say "clickable". */
button.md-help-link{appearance:none;-webkit-appearance:none;background:none;border:none;margin:0;padding:0 0 1px;font-family:var(--sans);text-align:left;cursor:pointer;border-bottom:1px dashed var(--line)}
button.md-help-link:hover{color:var(--fg-2);border-bottom-color:var(--fg-3)}
button.md-help-link:hover b{color:var(--fg)}
button.md-help-link:focus-visible{outline:2px solid var(--fg-3);outline-offset:2px;border-radius:3px}
.md-help{background:var(--surface);border:1px solid var(--line);border-radius:var(--r);padding:18px 20px;max-width:560px;width:min(560px,92vw);max-height:84vh;overflow:auto;display:flex;flex-direction:column;gap:12px}
.md-help-grid{display:grid;grid-template-columns:minmax(150px,auto) 1fr;gap:7px 16px;align-items:center}
.md-help-src{font-family:var(--mono);font-size:13px;color:var(--fg-2);white-space:nowrap}
.md-help-out .md-line,.md-help-out .md-h{margin:0}
.md-help-tip{margin:0}
.md-help-foot{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-top:2px;padding-top:14px;border-top:1px solid var(--line-soft)}
.md-help-foot a.btn{text-decoration:none}
.mdg-row{display:grid;grid-template-columns:1fr 1fr;gap:14px;padding:10px 0;border-top:1px solid var(--line-soft)}
.mdg-row:first-child{border-top:0;padding-top:0}
.mdg-lbl{margin-bottom:5px}
.mdg-src pre{margin:0;font-family:var(--mono);font-size:13px;line-height:1.55;white-space:pre-wrap;background:var(--sunken);border:1px solid var(--line-soft);border-radius:var(--r);padding:9px 11px}
.mdg-out{min-width:0;overflow-wrap:break-word}
@media (max-width:720px){ .mdg-row{grid-template-columns:1fr} }

/* right pane: view toggle + preview + provision */
.seg{display:inline-flex;gap:2px;background:var(--sunken);border:1px solid var(--line);border-radius:var(--r);padding:2px}
.seg-btn{font-family:var(--sans);font-size:12.5px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;background:none;border:0;color:var(--fg-3);padding:7px 11px;border-radius:5px;cursor:pointer;display:inline-flex;align-items:center;gap:6px}
.seg-btn.active{background:var(--surface);color:var(--fg)}
.seg-count{font-family:var(--mono);font-size:12px;color:var(--fg-3)}
.head-actions{display:flex;gap:10px}
.tool-link{font-family:var(--mono);font-size:12.5px;color:var(--fg-2);cursor:pointer}
.ha-sep{color:var(--fg-3);opacity:.5;margin:0 8px;user-select:none}
/* Push to site: scope dropdown + button sit as one header control. */
.overlay-push{display:inline-flex;align-items:center}
.overlay-push[hidden]{display:none !important}
.overlay-push-split{display:inline-flex;align-items:stretch}
.overlay-push-main{border-top-right-radius:0;border-bottom-right-radius:0}
.overlay-push-more{border-top-left-radius:0;border-bottom-left-radius:0;padding-left:8px;padding-right:8px;min-width:36px;justify-content:center}
.overlay-push-split .btn + .btn{border-left:1px solid var(--line-soft)}
#overlay-scope-menu{min-width:260px}
.tool-link:hover{color:var(--fg)}
.sandbox-name{font-family:var(--mono);font-size:12.5px;color:var(--fg-3)}
/* Right pane swappable views fill + scroll without a wrapper element. */
.bcol>.preview-frame,.bcol>.diff-view,.bcol>.activity-view,.bcol>.term-view{flex:1;min-height:0;overflow:auto}
.bcol>.preview-frame{overflow:hidden}
/* Session Terminal pane (docs/TERMINAL_PLAN.md): the xterm surface uses the
   code-editor tokens so both themes stay coherent. */
.bcol>.term-view{display:flex;flex-direction:column;overflow:hidden}
.term-view[hidden]{display:none}
.term-bar{display:flex;align-items:center;gap:10px;padding:6px 12px;border-bottom:1px solid var(--line-soft);flex:none;min-height:32px}
.term-caveat{opacity:.75;max-width:44ch;text-align:right}
.term-target{font-family:var(--mono);font-size:12px;background:var(--sunken);color:var(--fg);border:1px solid var(--line);border-radius:5px;padding:3px 6px}
.term-pane{flex:1;min-height:0;background:var(--code-bg);padding:6px 2px 6px 8px}
.term-pane .xterm{height:100%}
@media (max-width:720px){.term-caveat{display:none}}
.bcol>.preview-empty{flex:1;min-height:0}
.preview-frame{width:100%;height:100%;border:0;background:#fff}
.preview-empty{height:100%;display:grid;place-items:center;padding:24px}
.provision-card{text-align:center;max-width:360px}
.provision-card .big{font-size:17px;font-weight:600;margin:12px 0 8px}
.provision-card .fine{font-size:14px;color:var(--fg-2);line-height:1.6}
.provision-card .elapsed{font-family:var(--mono);font-size:13px;color:var(--fg-2);margin-top:10px}
.provision-card .wake-btn{margin-top:16px}
.provision-card .wake-status{min-height:1.4em;margin-top:8px;font-size:var(--fs-ui);color:var(--fg-2)}
.provision-card .wake-alt{margin-top:12px}
.sleep-bar{display:flex;align-items:center;gap:12px;flex-wrap:wrap;padding:12px 16px;border-top:1px solid var(--line-soft);background:var(--raised);flex:none}
.sleep-bar .sleep-copy{flex:1;min-width:180px;font-size:var(--fs-ui);font-weight:500;color:var(--fg);line-height:1.5}
.sleep-bar .sleep-copy .fine{display:block;font-weight:400;color:var(--fg-2);margin-top:4px}
.sleep-bar .wake-status{font-size:var(--fs-ui);color:var(--fg-2)}
.sleep-bar .wake-btn{flex:none}
.diff-view,.activity-view{padding:0}
/* Wide diffs: keep the horizontal scrollbar VISIBLE (macOS auto-hides the
   native one, leaving no hint the diff continues off-screen). */
.diff-view{overflow-x:auto}
.diff-view::-webkit-scrollbar{height:10px;width:10px}
.diff-view::-webkit-scrollbar-track{background:transparent}
.diff-view::-webkit-scrollbar-thumb{background:color-mix(in srgb,var(--fg-3) 55%,transparent);border-radius:5px}
.diff-view::-webkit-scrollbar-thumb:hover{background:var(--fg-3)}
/* Pop-out: a pane (Changes or chat) takes over the window for full-width review. */
.bcol.col-max{position:fixed;inset:16px;z-index:70;background:var(--surface);border:1px solid var(--line);border-radius:10px;box-shadow:0 24px 64px rgba(0,0,0,.45)}
body.col-max-open::before{content:"";position:fixed;inset:0;z-index:69;background:rgba(0,0,0,.45)}
.diff-loading{padding:24px;text-align:center;color:var(--fg-3);font-size:13px;font-family:var(--mono)}
.diff-empty-mark{font-size:22px;color:var(--fg-3)}

/* session diff (4-col; no per-line comment button) */
.build .df-body,.diff-view .df-body{grid-template-columns:44px 44px 18px minmax(max-content,1fr)}
/* Review tab: the comment (+) cell is a 4th sticky gutter column, LEFT of the
   code — a trailing column ends up off-screen on files with long lines. */
.review-wrap .df-body{grid-template-columns:40px 40px 16px 28px minmax(max-content,1fr);--df-gut:40px}
.review-wrap .df-line{grid-template-columns:40px 40px 16px 28px 1fr;grid-template-columns:subgrid}
.df-badges{display:flex;gap:7px;align-items:center}
.df-new{font-family:var(--mono);font-size:12px;color:var(--s-merge);border:1px solid color-mix(in srgb,var(--s-merge) 40%,transparent);border-radius:4px;padding:1px 6px}
.df-bin{font-family:var(--mono);font-size:12px;color:var(--fg-3);border:1px solid var(--line);border-radius:4px;padding:1px 6px}
.df-more{width:100%;text-align:center;background:var(--sunken);border:0;border-top:1px solid var(--line-soft);color:var(--fg-3);font-family:var(--mono);font-size:12.5px;padding:8px;cursor:pointer}
.df-more:hover{color:var(--fg)}
.diff-section{margin-bottom:2px}
/* z-index 2: sticky line-number gutters (.df-ln / .df-mark) also use z-index 1
   so they cover horizontally-scrolling code. Same z-index + later in the tree
   lets those gutters paint over this header as the Changes pane scrolls —
   "CHANGES / In the sandbox — not yet committed" sliding under the numbers. */
.diff-sec-head{display:flex;align-items:baseline;gap:8px;padding:9px 13px;position:sticky;top:0;background:var(--surface);border-bottom:1px solid var(--line-soft);z-index:2}
.diff-sec-title{font-family:var(--sans);font-size:var(--fs-label);font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--fg-2)}
.diff-sec-sub{font-family:var(--mono);font-size:12.5px;color:var(--fg-3)}
.diff-sec-head .sec-expand{all:unset;cursor:pointer;margin-left:auto;font-family:var(--mono);font-size:12.5px;color:var(--fg-3);white-space:nowrap}
.diff-sec-head .sec-expand:hover{color:var(--fg)}
/* Restore points (Changes tab): one row per chat commit, newest first */
.restore-row{display:flex;align-items:center;gap:12px;padding:9px 13px;border-top:1px solid var(--line-soft)}
.restore-row:first-of-type{border-top:0}
.restore-row .rp-name{font-weight:550;white-space:nowrap}
.restore-row .rp-meta{color:var(--fg-2);font-size:13px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1}
.restore-row .rp-btn{white-space:nowrap}
.diff-summary{display:flex;align-items:center;gap:10px;padding:10px 14px;border-bottom:1px solid var(--line-soft);font-family:var(--mono);font-size:12.5px;color:var(--fg-3)}
/* Uncommitted-changes prominence: an always-visible amber flag (even when file
   accordions are collapsed) + an amber accent on the uncommitted section header. */
/* Sleeping chat: the wake card rides as a fixed bar above the (read-only)
   stashed diff instead of replacing the whole pane with a placeholder. */
.sleep-head{flex:none;display:flex;align-items:flex-start;gap:14px;padding:13px 15px;border-bottom:1px solid var(--line-soft);background:color-mix(in srgb,var(--fg-3) 7%,var(--surface))}
.sleep-head .sleep-copy{flex:1;min-width:0}
.sleep-head .sleep-big{font-size:15px;font-weight:600;margin-bottom:5px}
.sleep-head .fine{font-size:13px;color:var(--fg-2);line-height:1.55;margin:0}
.sleep-head .wake-alt{margin-top:6px}
.sleep-act{flex:none;text-align:right}
.sleep-act .wake-status{min-height:1.2em;margin-top:6px;font-size:12.5px;color:var(--fg-2)}
.bcol-lbl{font-weight:550;display:inline-flex;align-items:center;gap:7px}
.diff-note-warn{margin:11px 12px 0;padding:9px 12px;border-radius:var(--r);text-align:left;background:color-mix(in srgb,var(--s-autotest) 10%,var(--surface));border:1px solid color-mix(in srgb,var(--s-autotest) 40%,transparent);color:var(--fg-2)}
@media(max-width:700px){.sleep-head{flex-direction:column;gap:10px}.sleep-act{text-align:left}}
.uncommitted-flag{display:flex;align-items:center;gap:9px;margin:11px 12px 6px;padding:9px 12px;border-radius:var(--r);background:color-mix(in srgb,var(--s-autotest) 13%,var(--surface));border:1px solid color-mix(in srgb,var(--s-autotest) 45%,transparent);color:var(--fg);font-size:13px;line-height:1.45}
.uncommitted-flag code{font-family:var(--mono);color:var(--fg-2)}
.uf-dot{width:8px;height:8px;border-radius:50%;background:var(--s-autotest);box-shadow:0 0 0 3px color-mix(in srgb,var(--s-autotest) 22%,transparent);flex:none}
.diff-section.local .diff-sec-head{box-shadow:inset 3px 0 0 var(--s-autotest)}
.diff-section.local .diff-sec-title{color:var(--s-autotest)}
.seg-count.warn{color:#1c1403;background:var(--s-autotest);border-radius:20px;padding:1px 7px;font-weight:600}
.ds-bar{flex:1;height:4px;border-radius:2px;background:var(--line-soft);overflow:hidden;display:flex}
.seg-add{background:var(--s-merge);height:100%}.seg-del{background:var(--danger);height:100%}
.add-n{color:var(--s-merge)}.del-n{color:var(--danger)}

/* activity timeline (session Activity view) */
.timeline{padding:8px 0}
.tl-row{display:flex;gap:11px;padding:9px 13px;border-bottom:1px solid var(--line-soft)}
.tl-icon{width:24px;height:24px;border-radius:50%;background:var(--raised);border:1px solid var(--line);display:grid;place-items:center;font-size:11px;flex:none;color:var(--fg-2)}
.tl-body{min-width:0;flex:1}
.tl-title{font-size:14px;color:var(--fg)}
.tl-detail{font-family:var(--mono);font-size:12.5px;color:var(--fg-3);margin-top:3px;white-space:pre-wrap}
.tl-when{font-family:var(--mono);font-size:12.5px;color:var(--fg-3);margin-left:auto}

/* submit bar (sits directly under .build, attached) */
.submitbar{border:1px solid var(--line);border-top:none;border-radius:0 0 var(--r-lg) var(--r-lg);background:var(--raised);display:flex;align-items:center;gap:16px;padding:14px 18px;flex-wrap:wrap;box-shadow:var(--shadow)}
/* The explanation is a sentence a human reads → sans, readable size. */
.submitbar .submit-status{flex:1;font-family:var(--sans);font-size:14px;line-height:1.5;color:var(--fg-2);min-width:220px}
/* Slim variant: a detached strip, not a text-heavy panel glued to the page
   bottom. The status span sits empty until a commit/submit streams progress
   into it; explanations live in the buttons' tooltips. */
.submitbar.slim{border:1px solid var(--line);border-radius:var(--r-lg);margin-top:10px;padding:9px 14px;gap:14px;box-shadow:none}
.submitbar.slim .submit-status{font-size:13px;min-width:0}
.submitbar.slim .check{font-size:13px;color:var(--fg-3)}
.submitbar.slim .check:hover{color:var(--fg-2)}
/* Walk-away auto-submit: an on/off switch on the LEFT of the bar, opposite
   the commit cluster, so it cannot be read as another "tick this then click
   Commit" checkbox. Armed state uses --s-autotest (the pipeline it fires). */
.asub-toggle{display:inline-flex;align-items:center;gap:10px;flex:none;min-height:36px;cursor:pointer;user-select:none;color:var(--fg-2)}
.asub-toggle:hover{color:var(--fg)}
.asub-copy{display:flex;flex-direction:column;gap:0;line-height:1.25;min-width:0}
.asub-name{font-size:var(--fs-ui);font-weight:500;white-space:nowrap}
.asub-state{font-size:var(--fs-label);font-weight:600;letter-spacing:.04em}
.asub-toggle.on{color:var(--fg)}
.asub-toggle.on .asub-state{color:var(--s-autotest)}
.asub-toggle.on .switch input:checked + .slider{background:var(--s-autotest);border-color:transparent}
.asub-toggle .switch input:focus-visible + .slider{outline:2px solid var(--s-review);outline-offset:2px}
.bar-discard{all:unset;cursor:pointer;font-size:13px;color:var(--fg-3);border-bottom:1px dashed transparent}
.bar-discard:hover{color:var(--s-open);border-bottom-color:var(--s-open)}
/* Live-log heartbeat: quiet stretches between output lines still look alive. */
.log-pulse{padding:6px 14px 12px;font-family:var(--mono);font-size:12px;color:var(--fg-3)}
.log-pulse span{animation:log-dot 1.4s infinite;display:inline-block}
.log-pulse span:nth-child(2){animation-delay:.25s}
.log-pulse span:nth-child(3){animation-delay:.5s}
@keyframes log-dot{0%,60%,100%{opacity:.2}30%{opacity:1}}
.submitbar code{font-family:var(--mono);font-size:13px;background:var(--sunken);border:1px solid var(--line);border-radius:4px;padding:1px 5px;color:var(--fg)}
.check{display:flex;align-items:center;gap:9px;font-size:14px;color:var(--fg-2);cursor:pointer}
/* Custom checkbox — the native control read as an ambiguous faint square; this
   gives it a clear border unchecked and a filled tick checked. */
.check input{appearance:none;-webkit-appearance:none;width:17px;height:17px;flex:none;margin:0;border:1.5px solid var(--fg-3);border-radius:5px;background:var(--surface);cursor:pointer;position:relative;transition:background .12s,border-color .12s}
.check:hover input{border-color:var(--fg-2)}
.check input:checked{background:var(--fg);border-color:var(--fg)}
.check input:checked::after{content:"";position:absolute;left:5px;top:2px;width:4px;height:8px;border:solid var(--surface);border-width:0 2px 2px 0;transform:rotate(45deg)}
.check input:focus-visible{outline:2px solid var(--s-review);outline-offset:2px}
.handoff-console,#handoff-console,#provision-console{grid-column:1/-1;font-family:var(--mono);font-size:12px;color:var(--fg-2);background:var(--sunken);white-space:pre-wrap;max-height:160px;overflow:auto;padding:0}
#handoff-console:not(:empty),#provision-console:not(:empty){padding:10px 15px;border-top:1px solid var(--line-soft)}
.capacity{font-family:var(--mono);font-size:12.5px}

/* ============================================================ ADMIN */
.admin-sec{display:none}.admin-sec.active{display:block}
.admin-users-hd{gap:12px}
.admin-users-hd .fld{flex:1;min-width:220px;max-width:480px}
.admin-users-empty{display:flex;align-items:center;gap:12px;flex-wrap:wrap;padding:18px 16px;margin:0;font-size:var(--fs-lead);color:var(--fg)}
.admin-table{width:100%;border-collapse:collapse;font-size:14px}
.admin-table th{text-align:left;font-family:var(--sans);font-size:var(--fs-label);font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--fg-3);padding:11px 14px;border-bottom:1px solid var(--line)}
.admin-table td{padding:11px 14px;border-bottom:1px solid var(--line-soft);vertical-align:middle}
.admin-table tr:last-child td{border-bottom:0}
.admin-table tr.is-synthetic{opacity:.55}
.admin-table .mono{font-family:var(--mono);font-size:12.5px;color:var(--fg-2)}
/* Internal / dev site host cards: keep Test SSH / Refresh / Paste / Edit on
   the same row as the host name. Long SSH/path/DB strings wrap inside the
   left column instead of shoving the actions onto a second left-aligned line. */
.int-host-hd{align-items:center;flex-wrap:nowrap;gap:12px}
.int-host-id{display:flex;align-items:flex-start;gap:8px;flex:1;min-width:0}
.int-host-id-text{min-width:0;flex:1}
.int-host-id-text .t-section{flex:none}
.int-host-meta{margin:4px 0 0;overflow-wrap:anywhere}
.int-host-actions{display:flex;align-items:center;gap:8px;flex:none;flex-wrap:nowrap;margin-left:auto}
.tag-syn{font-family:var(--sans);font-size:12px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;background:var(--raised);color:var(--fg-3);padding:2px 7px;border-radius:4px;margin-left:6px}
.perms-table td.ck,.perms-table th.ck{text-align:center;width:56px}
.perms-table .arrow{color:var(--fg-3);margin:0 6px}
.perms-table input[type="checkbox"]{appearance:none;-webkit-appearance:none;width:17px;height:17px;margin:0;border:1.5px solid var(--line);border-radius:4px;background:var(--sunken);cursor:pointer;position:relative;vertical-align:middle}
.perms-table input[type="checkbox"]:hover{border-color:var(--fg-3)}
.perms-table input[type="checkbox"]:checked{background:var(--fg);border-color:var(--fg)}
.perms-table input[type="checkbox"]:checked::after{content:"";position:absolute;left:5px;top:1px;width:4px;height:9px;border:solid var(--ink);border-width:0 2px 2px 0;transform:rotate(45deg)}
.perms-table input[type="checkbox"]:disabled{cursor:default;opacity:.4}
/* flex:none — a switch must never be squished by a long flex sibling (the
   knob is absolutely positioned, so a shrunken track paints the knob over
   the neighboring text). */
.switch{position:relative;display:inline-block;flex:none;width:40px;height:22px}
.switch input{opacity:0;width:0;height:0}
.switch .slider{position:absolute;inset:0;background:var(--line-soft);border-radius:22px;transition:.18s;cursor:pointer;border:1px solid var(--line)}
.switch .slider::before{content:"";position:absolute;height:16px;width:16px;left:2px;top:2px;background:var(--fg-2);border-radius:50%;transition:.18s}
.switch input:checked + .slider{background:var(--s-merge);border-color:transparent}
.switch input:checked + .slider::before{transform:translateX(18px);background:#fff}
.switch input:disabled + .slider{opacity:.5;cursor:default}
.field-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:14px}
.field-card h3{margin:0 0 10px;font-family:var(--sans);font-size:var(--fs-label);font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--fg-2);display:flex;align-items:center;gap:8px}
.opt-count{font-family:var(--mono);font-size:12px;font-weight:500;letter-spacing:0;color:var(--fg-3);background:var(--sunken);border:1px solid var(--line-soft);border-radius:999px;padding:1px 8px}
.opt-filter{margin-bottom:10px;font-family:var(--mono);font-size:13px}
/* Long lists (e.g. 700 imported components) scroll inside the card instead of
   stretching the whole admin page. align-content keeps wrapped rows packed at
   the top rather than spread across the capped height. */
.opt-list{display:flex;flex-wrap:wrap;gap:7px;padding-bottom:12px;max-height:340px;overflow-y:auto;align-content:flex-start;scrollbar-width:thin}
.opt-none{font-size:13.5px;color:var(--fg-2)}
.opt-chip{display:inline-flex;align-items:center;gap:6px;background:var(--sunken);border:1px solid var(--line);border-radius:var(--r);padding:5px 6px 5px 11px;font-family:var(--mono);font-size:13px;color:var(--fg)}
.opt-chip .chip-val{padding:0 2px}
/* Fix-version chips lead with their two toggles — tighten the left edge so
   the icons read as part of the chip, not floating punctuation. */
.opt-chip.fv-chip{padding:4px 6px;gap:2px}
.opt-chip.fv-chip .chip-val{padding:0 4px}
/* Legend + setting rows on the Fix versions admin card. */
.fv-legend{display:flex;flex-wrap:wrap;gap:16px;margin-top:12px;padding-top:12px;border-top:1px solid var(--line-soft);font-size:13px;color:var(--fg-2)}
.fv-legend .lg{display:inline-flex;align-items:center;gap:6px}
.fv-legend .lg-ic{font-size:15px;line-height:1}
.fv-legend .lg-rel{color:var(--s-merge)}
.fv-legend .lg-up{color:var(--fg-3)}
.fv-legend .lg-reg{color:var(--s-autotest)}
.fv-legend .lg-star{color:var(--s-autotest)}
.setting-row{display:flex;align-items:flex-start;gap:12px;margin-top:12px;padding-top:12px;border-top:1px solid var(--line-soft)}
.setting-row .switch{margin-top:1px}
.setting-text{display:flex;flex-direction:column;gap:2px;min-width:0}
.setting-name{font-size:var(--fs-ui);font-weight:600;color:var(--fg)}
.jira-import{display:flex;align-items:center;gap:10px;margin-top:12px;padding-top:12px;border-top:1px solid var(--line-soft)}
.jira-import .btn{flex:none}
/* Model picker inside the new-chat menu. */
.menu-model{padding:8px 12px 10px;border-bottom:1px solid var(--line-soft)}
.menu-model-lbl{display:block;font-size:var(--fs-label);font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--fg-3);margin-bottom:6px}
.menu-model .fld{width:100%}
/* Create-test-case popup: wider than a plain menu (skill list, include grid, authorizations, notes). */
.tc-menu{min-width:440px;width:min(520px, calc(100vw - 24px));max-height:min(88vh, 900px)}
.tc-check{display:flex;align-items:flex-start;gap:8px;padding:3px 0;cursor:pointer;font-size:13px;line-height:1.35}
.tc-check input{margin-top:2px;flex:none}
.tc-grid{display:grid;grid-template-columns:1fr 1fr;gap:0 10px}
.tc-menu textarea.fld{resize:vertical;font-family:var(--sans);font-size:13px}
.tc-menu label.menu-model{display:flex;align-items:flex-start;gap:8px}
.tc-menu label.menu-model input{margin-top:2px;flex:none}
.tc-ws{padding:3px 0;font-size:13px;line-height:1.35}
.tc-ws .tc-ws-where{margin-top:1px}
.tc-override summary{margin-bottom:0;list-style:none}
.tc-override summary::-webkit-details-marker{display:none}
.tc-override summary::before{content:"▸ ";display:inline-block;width:1em}
.tc-override[open] summary{margin-bottom:6px}
.tc-override[open] summary::before{content:"▾ "}
#new-chat-branch,#ws-new-branch{font-family:var(--mono)}
.lane-branch{white-space:nowrap}
.opt-x{border:0;background:none;color:var(--fg-3);font-size:14px;line-height:1;cursor:pointer;width:18px;height:18px;border-radius:50%}
.opt-x:hover{background:color-mix(in srgb,var(--danger) 15%,transparent);color:var(--danger)}
.opt-add{display:flex;gap:8px}
.fine{font-size:13.5px;color:var(--fg-2)}
.fine code{font-family:var(--mono);font-size:12.5px;background:var(--sunken);border:1px solid var(--line);padding:1px 5px;border-radius:4px}

/* ===== MODALS (uiModal / uiAlert / uiConfirm / uiPrompt) ===== */
.ui-modal-overlay{position:fixed;inset:0;background:color-mix(in srgb,#000 58%,transparent);display:flex;align-items:center;justify-content:center;z-index:1000;padding:20px;animation:ui-modal-fade .12s ease}
.ui-modal{background:var(--surface);border:1px solid var(--line);border-radius:var(--r-lg);box-shadow:0 24px 70px -20px rgba(0,0,0,.6),0 2px 8px rgba(0,0,0,.3);width:min(440px,100%);max-height:calc(100vh - 40px);overflow:auto;animation:ui-modal-pop .14s ease}
.ui-modal.wide{width:min(880px,100%)}
.ui-modal-title{font-family:var(--sans);font-size:13px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--fg-2);padding:16px 18px 0}
.ui-modal-body{padding:12px 18px 4px}
.ui-modal-msg{font-size:15px;color:var(--fg);line-height:1.55;white-space:pre-wrap}
.ui-modal-field{display:block;margin-top:12px}
.ui-modal-label{display:block;font-family:var(--sans);font-size:var(--fs-label);font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--fg-3);margin-bottom:6px}
.ui-modal-field input,.ui-modal-field textarea,.ui-modal-field select{width:100%;background:var(--sunken);border:1px solid var(--line);border-radius:var(--r);color:var(--fg);font-family:var(--sans);font-size:14px;padding:8px 10px;resize:vertical}
.ui-modal-field input.mono,.ui-modal-field textarea.mono{font-family:var(--mono);font-size:12.5px;line-height:1.6}
.ui-modal-field input:focus,.ui-modal-field textarea:focus{outline:none;border-color:var(--fg-3)}
.ui-modal-combo-list{margin-top:8px;max-height:240px;overflow:auto;background:var(--raised);border:1px solid var(--line);border-radius:var(--r)}
.ui-modal-combo-row{display:block;width:100%;text-align:left;min-height:36px;padding:10px 12px;border:0;background:none;color:var(--fg);font-family:var(--sans);font-size:14px;font-weight:500;line-height:1.5;cursor:pointer}
.ui-modal-combo-row:hover,.ui-modal-combo-row.sel{background:var(--sunken)}
.ui-modal-combo-empty{padding:12px;font-size:15px;line-height:1.5;color:var(--fg)}
.ui-modal-check{margin-top:14px;color:var(--fg);font-size:15px;font-weight:500}
.ui-modal-check-hint{margin:6px 0 0 26px;font-size:14px;color:var(--fg-2);line-height:1.5}
.ui-modal-actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:8px;padding:13px 17px 16px}
/* One-click suggestion chips inside a modal (reuse the dashed .asst-chip look). */
.ui-modal-chips{display:flex;flex-wrap:wrap;gap:7px;margin-top:11px}
@keyframes ui-modal-fade{from{opacity:0}to{opacity:1}}
@keyframes ui-modal-pop{from{opacity:0;transform:translateY(6px) scale(.98)}to{opacity:1;transform:none}}
/* Commit-progress modal: spinner + the job's latest narration line while the
   commit job runs, with the full log behind a disclosure (auto-opened on error). */
.cp-status{display:flex;align-items:flex-start;gap:9px;font-size:15px;line-height:1.55;color:var(--fg)}
.cp-status .spinner{flex:none;margin-top:4px}
.cp-glyph{flex:none}
.cp-glyph.cp-err{color:var(--danger)}
/* Two-line reserve: the headline is the job's latest log line, which flips
   between one and two wrapped lines — without the reserve the modal height
   jitters on every poll. A JS ratchet covers the rare 3+ line status. 47px =
   2 lines at 15px/1.55, rounded up to match offsetHeight so the ratchet's
   first write is a no-op. */
.cp-text{flex:1;min-width:0;min-height:47px}
/* Reserve layout space for controls that appear later (the details toggle,
   the Close button) so revealing them never changes the modal's height. */
.cp-hide{visibility:hidden}
.cp-elapsed{flex:none;font-family:var(--mono);font-size:12px;color:var(--fg-3);margin-top:2px}
.cp-log-toggle{all:unset;cursor:pointer;display:inline-block;margin-top:10px;font-size:12.5px;color:var(--fg-3)}
.cp-log-toggle:hover{color:var(--fg-2)}
.ui-modal .console{margin-top:8px;max-height:240px}

/* ===== REVIEW: suggestions + full-file edit ===== */
.df-actions{display:flex;gap:6px;align-items:center}
.df-edit{font-family:var(--sans);font-size:12.5px;font-weight:600;letter-spacing:.03em;text-transform:uppercase;color:var(--fg-3);border:1px solid var(--line);border-radius:var(--r);padding:4px 10px;cursor:pointer;flex:none;margin-left:2px}
.df-edit:hover{color:var(--fg);border-color:var(--fg-3);background:var(--surface)}
.suggestion{border:1px solid color-mix(in srgb,var(--s-merge) 45%,var(--line));border-radius:var(--r);margin:6px 0 4px;overflow:hidden;background:color-mix(in srgb,var(--s-merge) 5%,var(--surface))}
.suggestion-hd{display:flex;align-items:center;gap:8px;padding:6px 11px;font-family:var(--sans);font-size:12.5px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;color:var(--s-merge);border-bottom:1px solid var(--line-soft)}
.suggestion-hd .sg-loc{margin-left:auto;font-family:var(--mono);font-size:12.5px;font-weight:400;color:var(--fg-3);text-transform:none;letter-spacing:0}
.suggestion pre{margin:0;padding:9px 12px;font-family:var(--mono);font-size:13px;line-height:1.6;color:var(--fg);white-space:pre;overflow-x:auto;tab-size:4}
.suggestion pre .sg-old{display:block;color:var(--danger);text-decoration:line-through;opacity:.7}
.suggestion pre .sg-new{display:block;color:var(--s-merge)}
.suggestion-foot{display:flex;gap:8px;align-items:center;padding:7px 10px;border-top:1px solid var(--line-soft)}
.suggestion-foot .sg-note{font-size:12px;color:var(--fg-3);margin-right:auto}
.lcf-toggle{display:flex;gap:5px;margin-bottom:8px}
.lcf-toggle button{font-family:var(--sans);font-size:12.5px;font-weight:600;letter-spacing:.03em;text-transform:uppercase;background:var(--sunken);border:1px solid var(--line);color:var(--fg-3);padding:6px 11px;border-radius:var(--r);cursor:pointer}
.lcf-toggle button.on{background:var(--surface);color:var(--fg);border-color:var(--fg-3)}
/* Full-file code editor (gutter + textarea) */
/* Shared code editor — a dedicated code surface (var(--code-*)) so it reads as a
   real editor. Used by the full-file editor and the suggestion input. */
.code-editor{background:var(--code-bg);border:1px solid var(--code-line);border-radius:var(--r);overflow:hidden}
.ce-head{display:flex;align-items:center;gap:9px;padding:7px 12px;border-bottom:1px solid var(--code-line);background:var(--code-head)}
.ce-file{font-family:var(--mono);font-size:13px;color:var(--code-fg)}
.ce-lang{margin-left:auto;font-family:var(--sans);font-size:12px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--code-gutter);border:1px solid var(--code-line);border-radius:4px;padding:1px 7px}
.ce-body{display:flex;overflow:hidden;background:var(--code-bg)}
.ce-gutter{flex:none;box-sizing:border-box;min-width:46px;padding:11px 9px 11px 12px;text-align:right;font-family:var(--mono);font-size:13px;line-height:1.65;color:var(--code-gutter);background:var(--code-bg);border-right:1px solid var(--code-line);white-space:pre;overflow:hidden;user-select:none}
.ce-ta{flex:1;min-width:0;box-sizing:border-box;background:var(--code-bg);border:0;color:var(--code-fg);caret-color:var(--code-fg);font-family:var(--mono);font-size:13px;line-height:1.65;padding:11px 14px;outline:none;white-space:pre;overflow:auto;tab-size:4;resize:none}
.ce-ta::selection{background:color-mix(in srgb,var(--s-review) 40%,transparent)}
/* Compact (suggestion) — auto-grows with content. */
.code-editor.compact .ce-ta{min-height:44px;max-height:240px}
/* Full-file editor: seamless inside its bordered wrapper + a fixed tall body. */
.file-editor{border-top:1px solid var(--line-soft)}
.file-editor .code-editor{border:0;border-radius:0}
.file-editor .ce-body{height:min(460px,58vh)}
.file-editor .ce-ta{height:100%}
.file-editor-bar{display:flex;gap:8px;align-items:center;padding:9px 12px;border-top:1px solid var(--code-line);background:var(--code-head)}
.file-editor-bar .fe-note{font-size:12px;color:var(--fg-3);margin-right:auto}
.fe-committing{display:inline-flex;align-items:center;gap:6px;font-size:12px;color:var(--fg-3)}

@media (prefers-reduced-motion:reduce){.spine-track .seg.active::after,.spinner,.asst-typing i,.typing i,.dot.run,.ui-modal-overlay,.ui-modal{animation:none}}

/* ── Code browser (code.php) ─────────────────────────────────────────── */
.code-toolbar{display:flex;align-items:center;gap:12px;margin-bottom:12px}
.code-crumbs{flex:1;min-width:0;font-family:var(--mono);font-size:13px;color:var(--fg-3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.code-crumbs a{color:var(--fg-2);text-decoration:none}
.code-crumbs a:hover{color:var(--fg);text-decoration:underline}
.code-split{display:grid;grid-template-columns:320px minmax(0,1fr);gap:16px;align-items:start}
.code-tree{padding:8px 6px;max-height:calc(100vh - 180px);overflow:auto}
/* Tree rows are real click targets: 14px names, roomy padding, and BIG
   expand arrows — the tiny 10px twisties were unusable. */
.code-row{display:flex;align-items:center;gap:8px;width:100%;text-align:left;padding:8px 9px;border:0;background:none;color:var(--fg-2);font:inherit;font-size:14px;border-radius:6px;cursor:pointer;white-space:nowrap;overflow:hidden}
.code-row:hover{background:var(--sunken);color:var(--fg)}
.code-row.sel{background:var(--sunken);color:var(--fg)}
.code-row .nm{overflow:hidden;text-overflow:ellipsis}
.code-row.is-dir .nm{font-weight:500}
.code-kids{margin-left:16px;border-left:1px solid var(--line-soft);padding-left:5px}
.code-main{padding:0;min-height:300px}
/* Open-file tabs across the top of the code viewer (VS Code-style). */
.cb-tabs{display:flex;align-items:stretch;overflow-x:auto;background:var(--sunken);border-bottom:1px solid var(--line);border-radius:var(--r-lg) var(--r-lg) 0 0;scrollbar-width:thin}
.cb-tab{all:unset;box-sizing:border-box;display:flex;align-items:center;gap:6px;padding:8px 8px 8px 13px;max-width:220px;font-family:var(--mono);font-size:12.5px;color:var(--fg-2);border-right:1px solid var(--line-soft);border-top:2px solid transparent;cursor:pointer;white-space:nowrap;flex:none}
.cb-tab:hover{color:var(--fg);background:color-mix(in srgb,var(--surface) 55%,transparent)}
.cb-tab.active{background:var(--surface);color:var(--fg);border-top-color:var(--nav)}
.cb-tab .cb-tab-nm{overflow:hidden;text-overflow:ellipsis}
.cb-tab .cb-tab-dirty{color:var(--s-review, var(--fg-2));font-size:9px;flex:none}
.cb-tab .cb-tab-x{flex:none;padding:1px 6px;border-radius:5px;color:var(--fg-3);font-size:14px;line-height:1}
.cb-tab .cb-tab-x:hover{color:var(--fg);background:var(--sunken)}
.code-pre{margin:0;padding:12px 0;font-size:13px;line-height:1.65;counter-reset:cline;background:var(--code-bg);border-radius:0 0 var(--r-lg) var(--r-lg)}
.code-pre .cl{counter-increment:cline;padding:0 14px 0 0;white-space:pre}
.code-pre .cl::before{content:counter(cline);display:inline-block;width:54px;padding-right:14px;text-align:right;color:var(--code-gutter);opacity:.75;user-select:none;font-size:12px}
/* svn blame gutter — one rev/author cell per line, between the number and the code. */
.code-pre.blame .cl-blame{display:inline-block;width:150px;padding-right:10px;margin-right:8px;border-right:1px solid var(--line-soft);color:var(--code-gutter);opacity:.85;font-size:11px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;user-select:none;vertical-align:top}
#cb-blame-btn[aria-current="true"]{background:var(--raised);box-shadow:inset 0 0 0 1px var(--line-soft);color:var(--fg)}
.code-hist{display:flex;gap:12px;align-items:center;padding:10px 15px;border-bottom:1px solid var(--line-soft);font-size:13.5px}
.code-hist:last-child{border-bottom:0}
.cb-overlay{position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:200;display:flex;align-items:center;justify-content:center}
.code-find-row{display:block;width:100%;text-align:left;padding:9px 15px;border:0;background:none;color:var(--fg-2);font-size:13.5px;cursor:pointer;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.code-find-row:hover,.code-find-row.sel{background:var(--sunken);color:var(--fg)}
@media (max-width:900px){.code-split{grid-template-columns:1fr}.code-tree{max-height:32vh}}

/* ── CodeView: syntax tokens, indent guides, overlay editor ──────────── */
.cv{font-family:var(--mono);font-size:13px;line-height:1.65;tab-size:4;color:var(--code-fg)}
.cv .cl{white-space:pre}
.cv-c{color:var(--code-gutter);font-style:italic}
.cv-s{color:var(--cv-s)}
.cv-k{color:var(--cv-k)}
.cv-n{color:var(--cv-n)}
.cv-v{color:var(--cv-v)}
.cv-f{color:var(--cv-f)}
.cv-t{color:var(--cv-t)}
.cv-a{color:var(--cv-a)}
.cv-ig{box-shadow:inset 1px 0 0 var(--code-line)}
.cv-editwrap{position:relative;min-height:200px;background:var(--code-bg);border:1px solid var(--code-line);border-radius:var(--r)}
.cv-editwrap .cv-hl{position:absolute;inset:0;z-index:0;margin:0;padding:12px 14px;overflow:hidden;pointer-events:none;background:transparent;font-family:var(--mono);font-size:13px;line-height:1.65;tab-size:4;color:var(--code-fg)}
.cv-editwrap .cv-ta{position:relative;z-index:1;display:block;width:100%;height:100%;min-height:inherit;margin:0;padding:12px 14px;border:0;outline:none;resize:none;background:transparent;color:transparent;-webkit-text-fill-color:transparent;caret-color:var(--code-fg);font-family:var(--mono);font-size:13px;line-height:1.65;tab-size:4;white-space:pre;overflow:auto}
/* Site session "preview": the SIS site refuses cross-origin framing, so the
   pane hands the tester the real thing — a prominent open-in-new-tab card. */
/* "Open the test site" button in the right-pane tab bar (the site refuses to
   be framed, so it always opens in its own tab). */
.site-open-btn{white-space:nowrap}
/* Collapsed agent briefing (system seed prompt) at the top of agent chats. */
.msg-seed{margin-bottom:4px}
/* The collapsed pill spans the full chat column — same footprint expanded or
   collapsed, so toggling it never changes the perceived chat width. */
.seed-fold{display:block;width:100%}
.seed-fold summary{list-style:none;cursor:pointer;display:flex;align-items:center;gap:8px;font-size:12.5px;color:var(--fg-3);padding:6px 12px;border:1px dashed var(--line);border-radius:999px;user-select:none}
.seed-fold .seed-hint{margin-left:auto}
.seed-fold summary::-webkit-details-marker{display:none}
.seed-fold summary:hover{color:var(--fg-2);border-color:var(--fg-3)}
.seed-fold .seed-hint{font-size:11.5px;color:var(--fg-3);border-bottom:1px dotted var(--fg-3)}
.seed-fold[open] summary{border-radius:var(--r) var(--r) 0 0}
.seed-fold[open] .seed-hint{display:none}
.seed-fold .bubble{margin-top:0;border-radius:0 var(--r) var(--r) var(--r);white-space:pre-wrap;font-size:13px;color:var(--fg-2)}
/* Editor line-number gutter — mirrors the read view's numbers; the textarea
   and highlight shift right by the gutter width so overlay alignment holds. */
.cv-editwrap.cv-has-gutter{padding-left:52px}
.cv-editwrap.cv-has-gutter .cv-hl{left:52px}
.cv-editwrap .cv-gutter{position:absolute;left:0;top:0;bottom:0;width:52px;margin:0;padding:12px 0;overflow:hidden;pointer-events:none;background:color-mix(in srgb,var(--ink) 40%,transparent);border-right:1px solid var(--line-soft);border-radius:var(--r) 0 0 var(--r)}
/* line-height is pinned to the code's row height (13px × 1.65) — the smaller
   gutter font would otherwise re-resolve the inherited numeric line-height
   and drift 1.65px per line against the textarea. */
.cv-editwrap .cv-gutter .cl{padding-right:12px;text-align:right;color:var(--code-gutter);opacity:.75;font-size:12px;line-height:21.45px;user-select:none}
.cv-editwrap .cv-ta::selection{background:rgba(100,140,255,.3);color:transparent}
.cv-editwrap:focus-within{border-color:var(--fg-3)}
/* Fallback (big files): plain textarea shows its own text */
.cv-editwrap.cv-plain .cv-ta{color:var(--code-fg);-webkit-text-fill-color:var(--code-fg)}
.cv-editwrap.cv-plain .cv-ta::selection{color:var(--code-fg)}

/* Code browser layout polish */
.code-toolbar{margin:18px 0 14px}
.code-split > .card{margin:0}
.code-row .tw{flex:none;font-size:17px;width:22px;line-height:1;color:var(--fg-3);text-align:center}
.code-row:hover .tw{color:var(--fg)}
.code-pre .cl{white-space:pre}

/* Searchable branch combobox */
.cb-combo{position:relative}
.cb-combo input{width:250px;font-family:var(--mono);font-size:13.5px}
.cb-combo-list{position:absolute;top:calc(100% + 4px);left:0;width:340px;max-height:340px;overflow:auto;z-index:120;background:var(--raised);border:1px solid var(--line);border-radius:var(--r-lg);box-shadow:var(--shadow)}
.cb-combo-row{display:block;width:100%;text-align:left;padding:9px 13px;border:0;background:none;color:var(--fg-2);font-size:13.5px;font-family:var(--mono);cursor:pointer;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cb-combo-row:hover,.cb-combo-row.sel{background:var(--sunken);color:var(--fg)}
.cb-combo-row .t-micro{margin-left:8px}

/* Highlighted diffs: token colors carry the syntax; add/del reads from a bg tint.
   Do not color .df-code itself green/red — that overrides .cv-* tokens (ZD 354408). */
.df-code.cv{font:inherit;line-height:inherit;color:var(--code-fg);background:transparent}
.df-line.t-add{background:color-mix(in srgb,var(--s-merge) 13%,transparent)}
.df-line.t-del{background:color-mix(in srgb,var(--danger) 11%,transparent)}
/* Sticky gutters: line numbers and the +/− marker stay put while the code
   scrolls under them. Solid backgrounds (the row tint mixed onto the surface,
   same percentages as the row rules above) hide the passing code. Cells must
   self-stretch — an EMPTY cell (add rows have no old number) centered by the
   row's align-items would collapse to 0px tall and paint no background — so
   vertical centering moves inside the cell via flex. */
.df-line>.df-ln,.df-line>.df-mark,.df-line>.df-cbtn{position:sticky;z-index:1;background:var(--surface);align-self:stretch;display:flex;align-items:center}
.df-line>.df-ln{justify-content:flex-end}
.df-line>.df-mark,.df-line>.df-cbtn{justify-content:center}
.df-line>.df-ln:first-child{left:0}
.df-line>.df-ln+.df-ln{left:var(--df-gut,44px)}
.df-line>.df-mark{left:calc(var(--df-gut,44px)*2)}
.df-line>.df-cbtn{left:calc(var(--df-gut,44px)*2 + 16px)}
.df-line:hover>.df-ln,.df-line:hover>.df-mark,.df-line:hover>.df-cbtn{background:var(--raised)}
.df-line.t-add>.df-ln,.df-line.t-add>.df-mark,.df-line.t-add>.df-cbtn{background:color-mix(in srgb,var(--s-merge) 13%,var(--surface))}
.df-line.t-del>.df-ln,.df-line.t-del>.df-mark,.df-line.t-del>.df-cbtn{background:color-mix(in srgb,var(--danger) 11%,var(--surface))}

/* Review editors: highlight overlay behind the (transparent) textarea. */
.ce-main{position:relative;flex:1;min-width:0;display:flex}
.ce-main .ce-ta{flex:1;min-width:0}
.ce-hl{position:absolute;inset:0;margin:0;padding:11px 14px;overflow:hidden;pointer-events:none;font-family:var(--mono);font-size:13px;line-height:1.65;tab-size:4;color:var(--code-fg);background:transparent}
.ce-hl .cl{white-space:pre}
.code-editor .ce-ta.ce-clear{color:transparent;caret-color:var(--code-fg)}
.code-editor .ce-ta.ce-clear::selection{background:color-mix(in srgb,var(--s-review) 40%,transparent);color:transparent}

/* Line permalink highlight + clickable gutter */
.code-pre .cl.hl{background:color-mix(in srgb,var(--s-autotest) 16%,transparent)}
.code-pre .cl::before{cursor:pointer}
.code-pre .cl:hover::before{color:var(--fg-2);opacity:1}

/* Revision popup — a right-edge commit dossier opened from any rev number
   (blame gutter, Why answers, file history). */
.cl-blame-rev{color:var(--code-gutter);text-decoration:none;border-bottom:1px dotted color-mix(in srgb,var(--code-gutter) 55%,transparent);cursor:pointer}
.cl-blame-rev:hover{color:var(--fg);border-bottom-color:var(--fg-2)}
.rev-link{font-family:var(--mono);color:var(--fg-2);text-decoration:none;border-bottom:1px dotted var(--fg-3);cursor:pointer}
.rev-link:hover{color:var(--fg);border-bottom-color:var(--fg-2)}
.rev-overlay{position:fixed;inset:0;z-index:300;background:color-mix(in srgb,var(--bg) 55%,transparent);backdrop-filter:blur(1.5px);opacity:0;pointer-events:none;transition:opacity .16s ease}
.rev-overlay.open{opacity:1;pointer-events:auto}
.rev-panel{position:absolute;top:0;right:0;bottom:0;width:min(720px,94vw);background:var(--surface);border-left:1px solid var(--line);box-shadow:-24px 0 60px rgba(0,0,0,.28);padding:20px 24px 28px;overflow-y:auto;transform:translateX(14px);opacity:.4;transition:transform .18s cubic-bezier(.2,.8,.25,1),opacity .18s ease}
.rev-overlay.open .rev-panel{transform:none;opacity:1}
/* Full-width mode: read wide diffs without horizontal scrolling. */
.rev-overlay.wide .rev-panel{width:96vw}
.rev-overlay.wide .rev-panel .df-body{grid-template-columns:52px 52px 16px minmax(max-content,1fr);--df-gut:52px}
.rev-hd{border-bottom:1px solid var(--line-soft);padding-bottom:10px;margin-bottom:12px}
.rev-hd-line{display:flex;align-items:center;justify-content:space-between}
.rev-num{font-size:20px;font-weight:650;letter-spacing:.01em}
.rev-close{cursor:pointer;font-size:22px;line-height:1;color:var(--fg-3);padding:2px 6px;border-radius:var(--r)}
.rev-close:hover{color:var(--fg);background:var(--raised)}
.rev-byline{margin-top:3px;font-size:13px;color:var(--fg-2)}
.rev-dot{color:var(--fg-3)}
.rev-msg{white-space:pre-wrap;font-size:14px;line-height:1.55;padding:10px 12px;border-left:3px solid var(--line);background:color-mix(in srgb,var(--raised) 60%,transparent);border-radius:0 var(--r) var(--r) 0;margin-bottom:14px}
.rev-tickets{display:flex;flex-direction:column;gap:6px;margin-bottom:14px}
.rev-ticket{display:flex;align-items:center;gap:10px;padding:8px 11px;border:1px solid var(--line);border-radius:var(--r);text-decoration:none;background:var(--surface)}
.rev-ticket:hover{border-color:var(--fg-3);background:var(--raised)}
.rev-tkey{flex:none;font-size:12.5px;font-weight:650;color:var(--fg)}
.rev-ttitle{flex:1;font-size:13px;color:var(--fg-2);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rev-tstatus{flex:none;font-size:11px;color:var(--fg-3);text-transform:capitalize}
.rev-sec-title{font-size:var(--fs-label);font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--fg-2);margin:2px 0 7px}
.rev-paths{border:1px solid var(--line);border-radius:var(--r);padding:6px 0;margin-bottom:14px;max-height:240px;overflow-y:auto}
.rev-path{display:flex;align-items:center;gap:8px;padding:2.5px 11px;font-size:12px;color:var(--fg-2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.rev-act{flex:none;width:16px;height:16px;display:grid;place-items:center;font-size:10.5px;font-weight:700;border-radius:4px}
.rev-act.st-mod{color:var(--s-autotest);background:color-mix(in srgb,var(--s-autotest) 14%,transparent)}
.rev-act.st-add{color:var(--s-merge);background:color-mix(in srgb,var(--s-merge) 14%,transparent)}
.rev-act.st-del{color:var(--danger);background:color-mix(in srgb,var(--danger) 14%,transparent)}
.rev-loading{padding:40px 0;text-align:center;color:var(--fg-2);font-size:14px}
/* The popup's diffs reuse the shared .diff-file/.df-* cards (review tab). */
.rev-panel .diff-file{margin-bottom:10px}
.rev-panel .df-body{grid-template-columns:40px 40px 16px minmax(max-content,1fr);--df-gut:40px}

/* Field picker: selected values pinned on top with one-click remove */
.fp-sel-wrap{display:flex;flex-wrap:wrap;gap:5px;padding:7px 9px;border-bottom:1px solid var(--line-soft);margin-bottom:4px}
.fp-sel-chip{display:inline-flex;align-items:center;gap:6px;max-width:100%;padding:3px 7px 3px 9px;border:1px solid var(--line);border-radius:999px;background:var(--raised);cursor:pointer;font-size:12.5px;color:var(--fg)}
.fp-sel-chip:hover{border-color:var(--danger);color:var(--danger)}
.fp-sel-chip:hover .fp-sel-x{color:var(--danger)}
.fp-sel-lab{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.fp-sel-x{color:var(--fg-3);font-size:14px;line-height:1}

/* Impersonation banner — visible on every page while "signed in as" someone */
.impersonate-bar{display:flex;align-items:center;justify-content:center;gap:14px;padding:7px 16px;background:color-mix(in srgb,var(--s-review) 18%,var(--surface));border-bottom:1px solid color-mix(in srgb,var(--s-review) 45%,var(--line));font-size:13px;color:var(--fg)}
.imp-exit{cursor:pointer;font-size:12.5px;font-weight:600;color:var(--fg);border:1px solid color-mix(in srgb,var(--s-review) 55%,var(--line));border-radius:999px;padding:3px 11px;background:var(--surface)}
.imp-exit:hover{background:var(--raised)}

/* Multi-role chips on the Users tab + permissions matrix */
.user-roles{display:inline-flex;align-items:center;gap:5px;cursor:pointer;padding:3px 4px;border-radius:var(--r)}
.user-roles:hover{background:var(--raised)}
.user-roles[disabled]{cursor:default;opacity:.55}
.role-chip{display:inline-block;padding:2px 9px;border:1px solid var(--line);border-radius:999px;background:var(--raised);font-size:12px;color:var(--fg)}
.role-chip.is-admin{border-color:color-mix(in srgb,var(--s-review) 55%,var(--line));color:var(--s-review)}
.role-chip.is-off{opacity:.5}
.role-edit{color:var(--fg-3);font-size:12px;margin-left:2px}
/* .menu sets right:0; without right:auto this pop stretches from the
   trigger to the viewport edge. Cap both axes so a long user list
   cannot become a full-page overlay. */
.user-roles-pop{position:fixed;z-index:400;right:auto;min-width:220px;max-width:min(360px,calc(100vw - 16px));padding:6px 0 0;max-height:min(420px,calc(100vh - 16px));overflow-y:auto}
.user-roles-pop.ur-pop-members{display:flex;flex-direction:column;width:360px;max-width:min(360px,calc(100vw - 16px));max-height:min(420px,calc(100vh - 16px));padding:0;overflow:hidden}
.ur-pop-members .ur-pop-hint{flex:none;padding:10px 12px 8px;white-space:normal}
.ur-pop-members .ur-pop-search{flex:none;width:100%;min-height:44px;border:0;border-bottom:1px solid var(--line-soft);border-radius:0;background:var(--sunken);color:var(--fg);font-family:var(--sans);font-size:var(--fs-ui);padding:11px 13px;outline:none}
.ur-pop-members .ur-pop-search::placeholder{color:var(--fg-3)}
.ur-pop-members .ur-pop-list{flex:1 1 auto;min-height:0;overflow-y:auto}
.ur-pop-members .ur-pop-empty{padding:14px 12px;font-family:var(--sans);font-size:var(--fs-body);color:var(--fg-2);line-height:1.5}
.ur-pop-members .ur-pop-foot{flex:none;padding:8px 12px;border-top:1px solid var(--line)}
.ur-pop-members .ur-row-name{min-width:0;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ur-pop-members .ur-row-star{flex:none;padding-left:8px;cursor:pointer}
.ur-row{display:flex;align-items:center;gap:9px;padding:7px 12px;cursor:pointer;font-size:13.5px}
.ur-row.is-locked{opacity:.55;cursor:not-allowed}
.ur-row:hover{background:var(--raised)}
.ur-row input{width:15px;height:15px;accent-color:var(--s-merge)}
.perm-matrix .pm-role{text-align:center;font-size:12px}
.perm-matrix .pm-cell{text-align:center}
.perm-matrix .pm-cell input{width:16px;height:16px;accent-color:var(--s-merge);cursor:pointer}
.perm-matrix .pm-always{color:var(--s-merge);font-weight:700}
.perm-matrix .pm-group td{font-size:var(--fs-label);font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--fg-2);background:var(--sunken);padding:7px 13px}

/* Resources card (job page): stat-chip info tips + sparkline scale/hover.
   The tip is pure CSS (::after) so it works without JS; the sparkline
   crosshair/readout is progressive enhancement bound in job.php. */
.info-tip{display:inline-grid;place-items:center;width:15px;height:15px;margin-left:5px;border:1px solid var(--line);border-radius:50%;background:var(--raised);color:var(--fg-3);font-size:12px;line-height:1;font-style:normal;cursor:help;position:relative;vertical-align:-2px}
.info-tip::after{content:attr(data-tip);position:absolute;bottom:calc(100% + 8px);left:50%;transform:translateX(-50%);width:290px;padding:9px 11px;border:1px solid var(--line);border-radius:var(--r-md);background:var(--surface);color:var(--fg-2);font-size:12.5px;font-family:var(--sans);font-weight:400;line-height:1.5;text-align:left;box-shadow:var(--shadow);opacity:0;pointer-events:none;transition:opacity .12s ease;z-index:60;white-space:normal}
.info-tip:hover::after{opacity:1}
/* Chips near the card's left edge: keep the bubble on-screen. */
.res-chips>div:first-child .info-tip::after,.res-chips>div:nth-child(2) .info-tip::after{left:0;transform:none}
.spark{display:flex;gap:8px;align-items:stretch}
.spark-scale{display:flex;flex-direction:column;justify-content:space-between;text-align:right;min-width:34px;font-family:var(--mono);font-size:12px;color:var(--fg-3);padding:0 0 1px}
.spark-plot{position:relative;flex:1;min-width:0}
.spark-cursor{position:absolute;top:0;bottom:2px;width:1px;background:var(--fg-3);opacity:.65;pointer-events:none}
.spark-tip{position:absolute;top:-6px;transform:translate(-50%,-100%);padding:3px 8px;border:1px solid var(--line);border-radius:var(--r-md);background:var(--surface);font-family:var(--mono);font-size:12px;color:var(--fg);white-space:nowrap;box-shadow:var(--shadow);pointer-events:none;z-index:60}

/* Phone-only chrome for the session workspace (the status strip above the
   composer, the sheet scrim, and the sheet ✕ buttons): rendered in the markup
   at every width, but they only EXIST visually inside the ≤720px media query
   below — desktop and tablet never see them. */
.ws-strip,.ws-scrim,.ws-sheet-x,.ws-chats-btn,.nav-burger,.ci-more-btn,.bar-more-btn,.bar-more,.mb-tabbar,.cb-acts-btn,.ws-acts-pop,.vs-more-btn{display:none}
.cb-fileacts{display:contents}
/* The composer's icon cluster (attach/ZD/chime/mic): a wrapper that is
   invisible to desktop layout — on phones it becomes the ＋ pop-up card. */
.ci-tools{display:contents}

/* ============================================================
   MOBILE (≤720px) — phone-width refinements ONLY. Every rule is
   inside this one media query, so desktop and tablet rendering
   are byte-for-byte untouched. Priorities: the dashboard, the
   ticket page, and the session workspace; plus the shared topbar.
   ============================================================ */
@media (max-width:720px){
	/* ── Topbar: ONE brand row — wordmark + burger — with the full-width
	   search below. The whole nav (links, More, + New, bell, theme, avatar)
	   folds behind the burger as a drop-down card; on an admin phone the
	   inline nav wrapped to three rows before any content showed. Not sticky
	   — relative anchors the card. Release chips / org tag stay desktop-only. */
	.topbar{position:relative;height:auto;flex-wrap:nowrap;padding:10px 12px;gap:10px}
	.org,.rel-group{display:none}
	/* Search rides the same line: wordmark left, search filling the middle,
	   burger right — one row of chrome, total. */
	.wordmark{font-size:17px}
	.topsearch{flex:1 1 auto;min-width:0;max-width:none;position:static}
	.topsearch>span.ic{display:none}
	.topsearch input{padding:8px 12px;text-overflow:ellipsis}
	/* Results anchor to the (relative) topbar, spanning the full width — the
	   narrow inline input can't host a readable dropdown. */
	.hdr-results{left:10px;right:10px;width:auto;max-width:none}
	.nav-burger{display:grid;place-items:center;width:38px;height:38px;margin-left:auto;border:1px solid var(--line);border-radius:var(--r);background:var(--surface);color:var(--fg-2);font-size:16px;cursor:pointer}
	body.nav-open .nav-burger{color:var(--fg);border-color:var(--fg-3);background:var(--raised)}
	.topnav{display:none}
	body.nav-open .topnav{display:flex;position:absolute;top:100%;right:10px;z-index:70;max-width:calc(100vw - 20px);min-width:min(320px,calc(100vw - 20px));margin:4px 0 0;padding:10px;background:var(--surface);border:1px solid var(--line);border-radius:var(--r-lg);box-shadow:var(--shadow);flex-wrap:wrap;justify-content:flex-start;gap:8px}
	body.nav-open .topnav a{padding:8px 10px;font-size:14px}
	body.nav-open .topnav-more>button{padding:8px 10px;font-size:14px}
	/* More can sit on either edge of the wrapping hamburger card.
	   A trigger-anchored 250px+ panel overflows the other side
	   (right:0 clips the left; left:0 clips the right). Pin the
	   panel to the card — already viewport-clamped — and let
	   hdrMoreFit also fix it to the screen. */
	body.nav-open .topnav-more{position:static}
	body.nav-open .topnav-more .menu{left:10px;right:10px;width:auto;min-width:0;max-width:none;transform:none}
	body.nav-open .topnav-more .menu-item span{white-space:normal}
	/* Bell panel: same overflow as More — a right-anchored 344px / 86vw
	   sheet from a wrap-row trigger hangs off the left of the viewport
	   (ZD 354117, iPhone 17 Pro Max CSS width 440). Pin to the hamburger
	   card — already viewport-clamped — and let notifFit also fix it. */
	body.nav-open .notif-wrap{position:static}
	body.nav-open .notif-panel{left:10px;right:10px;width:auto;max-width:none}
	.shell,.wrap{padding-left:12px;padding-right:12px}

	/* IOS Safari zooms into any focused control under 16px — pin the main
	   text-entry surfaces at 16px on phones only. */
	.topsearch input,.chat-input textarea,.composer textarea,.asst-foot textarea,.qbar input,.create input,.create textarea,.edit-area,.title-input,.fld,.ns-pick{font-size:16px}

	/* Composer toolbar carries the model/effort switchers — keep the selects
	   from eating the row on phones (the toolbar itself wraps at all widths). */
	.ci-toolbar .sess-model-sel{max-width:46vw}

	/* ── Session composer: ONE row — ＋ · model · effort · send. The icon
	   cluster (attach/ZD/chime/mic) pops up from the ＋ instead of wrapping
	   the toolbar to two rows. Standalone page only; embeds keep the wrap. */
	body.session-body:not(.embed) .chat-composer{position:relative}
	body.session-body:not(.embed) .ci-more-btn{display:grid}
	body.session-body:not(.embed) .ci-toolbar{flex-wrap:nowrap;gap:8px}
	body.session-body:not(.embed) .ci-hint{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
	body.session-body:not(.embed) .ci-hint:not(:empty){min-width:0}
	body.session-body:not(.embed) .ci-toolbar .sess-model-sel{max-width:30vw}
	/* The chip cluster (model · effort · skill · ctx) SHRINKS before anything
	   clips — labels hard-truncate, the send arrow stays on screen. The row
	   grew chips since the one-row design (skill, ctx) and was pushing send
	   off the right edge on phones. */
	body.session-body:not(.embed) .ci-actions{flex:1 1 auto;min-width:0;justify-content:flex-end;gap:8px}
	/* Chips live inside .menu-wrap spans whose min-width:auto refuses to
	   shrink — with justify-content:flex-end the cluster then overflows LEFT,
	   over the ＋. Let the wrappers shrink and the chips truncate inside. */
	body.session-body:not(.embed) .ci-actions > .menu-wrap{flex:0 1 auto;min-width:36px;display:flex}
	body.session-body:not(.embed) .ci-actions > .menu-wrap > .sess-model-sel{flex:1 1 auto;max-width:100%;min-width:0}
	body.session-body:not(.embed) .ci-actions .sess-model-sel{flex:0 1 auto;min-width:36px;display:block;line-height:34px;padding:0 10px;text-overflow:ellipsis}
	body.session-body:not(.embed) .ci-actions .send-btn{flex:none}
	body.session-body:not(.embed) .ci-tools{display:none;position:absolute;left:10px;bottom:100%;margin-bottom:6px;flex-wrap:wrap;gap:8px;padding:9px;background:var(--raised);border:1px solid var(--line);border-radius:var(--r-lg);box-shadow:var(--shadow);z-index:20}
	body.session-body:not(.embed) #composer.tools-open .ci-tools{display:flex}
	body.session-body:not(.embed) #composer.tools-open .ci-more-btn{color:var(--fg);border-color:var(--fg-3);background:var(--sunken);box-shadow:inset 0 1px 3px rgba(0,0,0,.35)}
	/* Model/effort drop-ups anchor to their chip's right edge and are wider
	   than the space beside it — pin them as full-width panels above the
	   bottom edge instead (same treatment as the + New menu). */
	body.session-body:not(.embed) #composer .menu{position:fixed;left:10px;right:10px;top:auto;bottom:calc(10px + env(safe-area-inset-bottom));width:auto;min-width:0;max-width:none;max-height:70vh;max-height:70dvh;overflow-y:auto;z-index:97}
	/* ── Commit bar: one row — More ▾ · status · Commit. The checkboxes,
	   checkpoint commit, and Discard fold into the More popover (the mobile
	   shell JS moves them there and back across the breakpoint). */
	body.session-body:not(.embed) .bar-more-btn{display:inline-flex;flex:none}
	body.session-body:not(.embed) #ws-bcol .submitbar{flex-wrap:nowrap;position:relative}
	body.session-body:not(.embed) .submitbar .submit-status,
	body.session-body:not(.embed) .submitbar .fine{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
	body.session-body:not(.embed) .submitbar #submit-btn,
	body.session-body:not(.embed) .submitbar #commit-btn.btn-primary{margin-left:auto}
	body.session-body:not(.embed) .bar-more{position:absolute;bottom:calc(100% + 8px);left:10px;right:10px;z-index:30;display:none;flex-direction:column;align-items:stretch;gap:14px;padding:14px;background:var(--raised);border:1px solid var(--line);border-radius:var(--r-lg);box-shadow:var(--shadow)}
	body.session-body:not(.embed) .submitbar.more-open .bar-more{display:flex}
	body.session-body:not(.embed) .submitbar.more-open .bar-more-btn{color:var(--fg);border-color:var(--fg-3)}
	.bar-more .check{font-size:14.5px;color:var(--fg-2)}
	.bar-more .asub-toggle{justify-content:space-between;width:100%;font-size:14.5px;color:var(--fg-2);padding:4px 0}
	.bar-more .asub-toggle.on{color:var(--fg)}
	.bar-more .bar-discard{text-align:left;padding:4px 0;color:var(--danger)}
	.bar-more .btn{justify-content:center}

	/* Dropdown menus: width/height caps are a no-JS floor. 70vh from a
	   mid-page trigger (Move stage + admin skips) still ran off the
	   bottom, under the tab bar — menuFit pins to the remaining
	   viewport and stops above .mb-tabbar. */
	.menu{max-width:calc(100vw - 24px);max-height:min(70dvh,calc(100dvh - 70px - env(safe-area-inset-bottom)));overflow-y:auto;overscroll-behavior:contain;z-index:90}

	/* Header search results: the title (and description snippet) is the
	   payload — give the body its own full-width line under the key/status
	   instead of letting a long status tag ellipsize it down to a word. */
	.hr-item{flex-wrap:wrap;row-gap:5px}
	.hr-item .hr-body{order:3;flex-basis:100%}
	.hr-item .hr-title{white-space:normal;line-height:1.4}
	.hr-item .hr-snip{white-space:normal}
	.hr-item .stage-tag{margin-left:auto;font-size:12px}

	/* ── Dashboard ── */
	.page-head{padding:20px 0 4px}
	/* Views fold: two view chips (plus the active one, wherever it sits)
	   and a More ▾ button; expanding reveals the remaining views and Add view.
	   The Show-fields toggle and Only-mine stay visible so those filters
	   are one tap away after a list ↔ grid switch. */
	.vs-more-btn{display:inline-flex}
	body:not(.vs-open) .views-row .view-chip ~ .view-chip ~ .view-chip:not(.on){display:none}
	body:not(.vs-open) .views-row>.btn:not(.vs-more-btn){display:none}
	.statband{grid-template-columns:1fr 1fr;gap:10px;margin:16px 0}
	.stat{padding:13px 15px}
	.stat .n{font-size:24px;margin-top:6px}
	.qhint{display:none}
	.qbar{flex-wrap:wrap}
	.qbar input{flex:1 1 150px}
	/* Ticket rows wrap: key/avatar/stage on the first line, then the title
	   full-width so it can breathe instead of ellipsizing at ~15 chars. The
	   stage rail becomes a left border (a stretched flex rail can't span
	   wrapped lines). */
	.trow{flex-wrap:wrap;gap:8px 10px;padding:13px 14px;border-left:3px solid var(--stage,var(--line))}
	.trow .rail{display:none}
	.trow .row-who{order:2;margin-left:auto}
	.trow .who-name{max-width:110px}
	.trow .stage-tag{order:3}
	.trow .tmain{order:4;flex-basis:100%;min-width:100%}
	.trow .ttitle{white-space:normal;font-size:16px;line-height:1.4}
	.yc-when{display:none}

	/* Field pickers (assignee, components, districts…): JS anchors them to
	   the trigger with inline left/top, which on a phone can land half
	   off-screen or under the keyboard — pin them as a top sheet instead.
	   !important is needed to beat those inline coordinates. */
	.field-picker.fp-sheet{left:12px!important;right:12px;top:12px!important;width:auto;max-width:none}
	.field-picker.fp-sheet .field-picker-list{max-height:55vh}

	/* ── Ticket page ── */
	.thead{flex-wrap:wrap;gap:10px;padding:18px 0 6px}
	.thead h1{order:5;flex-basis:100%;font-size:20px}
	.thead-actions{order:6;flex-basis:100%;margin-left:0;flex-wrap:wrap;gap:8px}
	.thead-actions .menu{left:0;right:auto;min-width:0}
	.thead-actions .menu-item{flex-wrap:wrap}
	.thead-actions .menu-item span{white-space:normal}
	/* Spine: seven uppercase labels can't fit a phone — show only the active
	   one (the track above and the status sentence below carry the rest). */
	.spine{padding:14px 14px 12px}
	.spine-labels{display:flex}
	.spine-labels span{display:none}
	.spine-labels span.active{display:block}
	.spine-foot .t-micro{margin-left:0;flex-basis:100%}
	.card-hd{padding:12px 14px;flex-wrap:wrap;row-gap:6px}
	/* Host actions stay a right-aligned group if the header has to wrap. */
	.int-host-actions{flex-wrap:wrap;justify-content:flex-end}
	.card-bd{padding:14px}
	.meta-row{grid-template-columns:76px 1fr;padding:9px 14px}
	.composer-foot{flex-wrap:wrap;row-gap:8px}
	/* Segmented controls (Activity filter, session view toggle) wrap instead
	   of forcing their container wide. */
	.seg{flex-wrap:wrap}

	/* ── Session workspace: chat-first app shell (standalone page only) ──
	   The chat owns the whole viewport. The sessions rail and the
	   Changes/Activity pane keep their desktop MARKUP but re-home as bottom
	   sheets, opened from the phone-only status strip above the composer /
	   the session title. Embedded sessions (issue-page tabs) keep the old
	   stacked layout further down. */
	.rail-toggle{display:none}
	#ws-rail .menu{left:auto;right:0}
	/* A saved collapsed-rail preference has no meaning here — undo the
	   collapsed styles so lanes stay readable. */
	.build.rail-collapsed #ws-rail .rail-title{display:inline}
	.build.rail-collapsed #ws-rail .menu-wrap{display:block}
	.build.rail-collapsed #ws-rail .lane-name{display:block}
	.build.rail-collapsed #ws-rail .lane-rename{display:inline-block}
	.build.rail-collapsed #ws-rail .lane-top .t-micro{display:inline}
	.build.rail-collapsed #ws-rail .lane-sub{display:flex}
	.build.rail-collapsed #ws-rail .ws-budget{display:block}
	.build.rail-collapsed #ws-rail .bcol-hd{justify-content:flex-start;padding:13px 15px}
	.build.rail-collapsed #ws-rail .lane{padding:14px 16px}
	.build.rail-collapsed #ws-rail .lane-top{justify-content:flex-start;gap:10px}
	.build.rail-collapsed #ws-rail .rail-issue-list .lane{justify-content:flex-start;gap:8px;padding:12px 16px}
	/* Lock the app to the viewport again (the ≤1100px block above unlocked it
	   for stacked tablet scrolling) — only the chat transcript scrolls. */
	body.session-body:not(.embed){height:100vh;height:100dvh;overflow:hidden;display:flex;flex-direction:column}
	body.session-body:not(.embed) .shell{flex:1 1 auto;min-height:0;height:auto;display:flex;flex-direction:column;overflow:hidden;width:100%;max-width:none;padding-bottom:0}
	body.session-body:not(.embed) .build{flex:1 1 auto;min-height:0;height:auto;display:flex;flex-direction:column}
	body.session-body:not(.embed) .build>.bcol:not(:first-of-type){border-top:0}
	body.session-body:not(.embed) #ws-chat{flex:1 1 auto;min-height:0}
	/* Compact wrapped header: chips on the first row, the title full-width
	   below — smaller than before, since vertical space is transcript space
	   now that the viewport is locked. */
	.ws-head{flex-wrap:wrap;gap:6px 8px;padding:10px 0 8px}
	.ws-head .ws-title{order:5;flex-basis:100%;max-width:none;white-space:normal;font-size:16px;line-height:1.35}
	/* The ticket title is context, not workspace — ← lands on the issue page
	   that shows it in full, and the session name sits right below. Hiding it
	   makes the whole header one chip row. */
	body.session-body:not(.embed) .ws-head .ws-title{display:none}
	/* The sandbox chip keeps only its state dot (the strip + provisioning card
	   narrate the words) so the chip row fits one line. */
	body.session-body:not(.embed) .ws-head .sandbox-chip{font-size:0;gap:0}
	/* Full-window expand is a desktop affordance — the phone shell IS full
	   window — and the header search has the back button for wayfinding here.
	   Both hidden to buy the transcript more rows. */
	body.session-body:not(.embed) .col-max-btn{display:none}
	body.session-body:not(.embed) #ws-chat .bcol-hd > .ha-sep:last-of-type{display:none}
	body.session-body:not(.embed) .topsearch{display:none}
	/* The whole topbar goes: on an admin phone it wraps to three rows of nav
	   before any chat shows. This is a focused app screen — ← returns to the
	   issue page, which keeps the full topbar. */
	body.session-body:not(.embed) .topbar{display:none}
	/* Chat header: ONE truncating row, never a wrap. The session name and the
	   Site-debug button (whose label becomes the picked site list, e.g.
	   "asdnh/dev, asdnh/dev_trunk") both ellipsize instead of stacking. The ✎
	   is redundant here — every lane in the sessions sheet has its own ✎. */
	body.session-body:not(.embed) #ws-chat .bcol-hd{flex-wrap:nowrap;gap:8px;overflow-x:auto;scrollbar-width:none;-webkit-overflow-scrolling:touch;padding-left:0}
	body.session-body:not(.embed) #ws-chat .bcol-hd::-webkit-scrollbar{display:none}
	/* The ☰ chats door pins while the rest of the header scrolls sideways —
	   width 44 = 32px button + a 12px surface-painted border standing in for
	   the header padding it replaced (so scrolled content can't peek left). */
	body.session-body:not(.embed) #ws-chat .bcol-hd .ws-chats-btn{position:sticky;left:0;z-index:2;width:44px;border-left:12px solid var(--surface)}
	body.session-body:not(.embed) #ws-chat .bcol-hd > *{flex-shrink:0}
	body.session-body:not(.embed) #ws-chat .bcol-hd #session-title{flex:0 1 auto;min-width:72px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
	/* The pipeline stage repeats what the issue page already says — on a phone
	   it costs a whole header row, so it goes. */
	body.session-body:not(.embed) .ws-stage{display:none}
	body.session-body:not(.embed) #ws-chat .bcol-hd .title-edit{display:none}
	body.session-body:not(.embed) #ws-chat .bcol-hd .btn{white-space:nowrap}
	body.session-body:not(.embed) #ws-chat .bcol-hd .district-pick{max-width:26vw;overflow:hidden;text-overflow:ellipsis}
	/* Conflict-resolution bar (rebase/unmerge): keep it visible but never let
	   it squeeze the chat out of the locked viewport. */
	body.session-body:not(.embed) .rebase-bar{flex:none;max-height:34dvh;overflow-y:auto}
	/* Tapping the session name opens the sessions sheet (rename keeps the ✎). */
	body.session-body:not(.embed) #session-title::after{content:" ▾";color:var(--fg-3);font-size:12px}
	/* ── The two bottom sheets: #ws-rail (sessions) and #ws-bcol (workspace).
	   Same markup as desktop — position:fixed pulls them out of the flow, a
	   body class slides them up. transform creates a stacking context, so
	   their internal menus/accordions layer correctly inside. */
	body.session-body:not(.embed) #ws-rail,
	body.session-body:not(.embed) #ws-bcol{position:fixed;left:0;right:0;bottom:0;top:auto;z-index:96;background:var(--surface);border:1px solid var(--line);border-bottom:0;border-radius:16px 16px 0 0;box-shadow:0 -18px 50px -20px rgba(0,0,0,.6);transform:translateY(103%);visibility:hidden;transition:transform .22s ease,visibility .22s;display:flex;flex-direction:column}
	body.session-body:not(.embed) #ws-rail{max-height:72vh;max-height:72dvh}
	/* The workspace is a full SCREEN, not a peeking sheet — four-plus tabs and
	   a terminal earn the whole viewport; ✕ (or Esc) is the way back. */
	body.session-body:not(.embed) #ws-bcol{height:100vh;height:100dvh;border:0;border-radius:0}
	body.session-body:not(.embed) #ws-bcol::before{display:none}
	body.session-body:not(.embed) #ws-bcol .bcol-hd{padding-top:calc(12px + env(safe-area-inset-top))}
	body.session-body.ws-rail-open:not(.embed) #ws-rail,
	body.session-body.ws-sheet-open:not(.embed) #ws-bcol{transform:none;visibility:visible}
	body.session-body:not(.embed) #ws-rail::before,
	body.session-body:not(.embed) #ws-bcol::before{content:"";flex:none;width:38px;height:4px;border-radius:2px;background:var(--line);margin:8px auto 2px}
	body.session-body:not(.embed) #ws-rail .bcol-bd{flex:1 1 auto;min-height:0;overflow-y:auto}
	/* The + New menu can't hang off its trigger inside the sheet (it's wider
	   than the space left of the button) — pin it as a full-width panel above
	   the bottom edge instead. The sheet's transform is none while open, so
	   fixed positioning anchors to the viewport. */
	body.session-body:not(.embed) #ws-rail .menu{position:fixed;left:10px;right:10px;top:auto;bottom:calc(10px + env(safe-area-inset-bottom));width:auto;min-width:0;max-width:none;max-height:78vh;max-height:78dvh;overflow-y:auto;z-index:97}
	body.session-body:not(.embed) #ws-rail .menu-actions .btn{flex-wrap:wrap}
	body.session-body:not(.embed) #ws-bcol .diff-view,
	body.session-body:not(.embed) #ws-bcol .activity-view,
	body.session-body:not(.embed) #ws-bcol .preview-empty{flex:1 1 auto;min-height:0;overflow-y:auto}
	/* xterm scrolls itself — just let the terminal pane fill the column. */
	body.session-body:not(.embed) #ws-bcol .term-view{flex:1 1 auto;min-height:0}
	/* The submit bar rides INSIDE the workspace sheet on phones (session.php
	   moves the node there) — commit lives next to the diff it commits. */
	body.session-body:not(.embed) #ws-bcol .submitbar{flex:none;border:0;border-top:1px solid var(--line);border-radius:0;box-shadow:none;margin:0;padding:11px 14px calc(12px + env(safe-area-inset-bottom));gap:10px}
	/* Scrim behind an open sheet — tap to dismiss. */
	body.session-body:not(.embed) .ws-scrim{display:block;position:fixed;inset:0;z-index:94;background:color-mix(in srgb,#000 55%,transparent);opacity:0;visibility:hidden;transition:opacity .2s ease,visibility .2s}
	body.session-body.ws-rail-open:not(.embed) .ws-scrim,
	body.session-body.ws-sheet-open:not(.embed) .ws-scrim{opacity:1;visibility:visible}
	/* Chat header ☰ — the visible door to the chat-list sheet on phones. */
	body.session-body:not(.embed) .ws-chats-btn{display:grid;place-items:center;width:32px;height:32px;flex:none;border:1px solid var(--line);border-radius:8px;background:var(--surface);color:var(--fg-2);font-size:14px;cursor:pointer}
	/* Sheet close ✕ (top-right of each sheet header) + the ⋯ actions toggle. */
	body.session-body:not(.embed) .ws-sheet-x{display:grid;place-items:center;width:32px;height:32px;flex:none;margin-left:auto;border:1px solid var(--line);border-radius:8px;background:var(--surface);color:var(--fg-2);font-size:14px;cursor:pointer}
	body.session-body:not(.embed) .ws-acts-btn ~ .ws-sheet-x{margin-left:0}
	/* Workspace sheet header: ONE row — tabs · ⋯ · ✕. The head-actions
	   (Refresh diff / Merge cmd / Open site) fold behind the ⋯ as a popover
	   under the tab row; only the active view's action group shows (the
	   view-switch JS already manages their hidden attributes). */
	body.session-body:not(.embed) #ws-bcol .bcol-hd{flex-wrap:nowrap;position:relative}
	body.session-body:not(.embed) #ws-bcol .bcol-hd .spacer{display:block;flex:0 0 6px}
	/* Undo the desktop-narrow order/max-width so ⋯ and ✕ keep the phone row. */
	body.session-body:not(.embed) #ws-bcol .bcol-hd > .seg,
	body.session-body:not(.embed) #ws-bcol .bcol-hd > .right-toggle,
	body.session-body:not(.embed) #ws-bcol .bcol-hd > .head-actions{order:0}
	body.session-body:not(.embed) #ws-bcol .bcol-hd > .seg{max-width:none}
	/* The tab strip owns the row and scrolls sideways when tabs outgrow it
	   (Changes · Activity · Site · Terminal · whatever comes next) — never a
	   second line. */
	body.session-body:not(.embed) #ws-bcol .seg{flex:1 1 auto;min-width:0;flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none;gap:1px}
	body.session-body:not(.embed) #ws-bcol .seg::-webkit-scrollbar{display:none}
	body.session-body:not(.embed) #ws-bcol .seg .seg-btn{padding:6px 9px;font-size:12px;letter-spacing:0;gap:4px;white-space:nowrap;flex:none}
	/* Pre-move flash guard: action groups still sitting in the header row are
	   hidden until the shell JS re-homes them into the ⋯ popover. */
	body.session-body:not(.embed) #ws-bcol .bcol-hd>.head-actions{display:none}
	/* The ⋯ popover: a Views jump list (Changes/Activity/Site/Terminal — so
	   Terminal is findable without discovering the tab-strip scroll), then
	   the active view's action group. */
	body.session-body:not(.embed) .ws-acts-pop{position:absolute;top:calc(100% + 6px);right:8px;z-index:40;display:none;flex-direction:column;gap:2px;min-width:200px;padding:8px;background:var(--raised);border:1px solid var(--line);border-radius:var(--r-lg);box-shadow:var(--shadow)}
	body.session-body:not(.embed) #ws-bcol .bcol-hd.acts-open .ws-acts-pop{display:flex}
	body.session-body:not(.embed) .ws-acts-views{display:flex;flex-direction:column;gap:2px;border-bottom:1px solid var(--line-soft);padding-bottom:6px;margin-bottom:4px}
	body.session-body:not(.embed) .ws-acts-pop .tool-link{display:block;width:100%;text-align:left;padding:10px 10px;font-size:14.5px;color:var(--fg);background:none;border:0;border-radius:7px;cursor:pointer}
	body.session-body:not(.embed) .ws-acts-pop .head-actions{display:flex;flex-direction:column;gap:2px}
	body.session-body:not(.embed) .ws-acts-pop .head-actions .btn{margin:4px 10px}
	body.session-body:not(.embed) .ws-acts-pop .ha-sep{display:none}
	body.session-body:not(.embed) #ws-bcol .bcol-hd .ws-acts-btn[aria-expanded="true"]{color:var(--fg);border-color:var(--fg-3)}
	/* ── Status strip: turn state + uncommitted diff stat, docked above the
	   composer. Tapping it opens the workspace sheet. */
	body.session-body:not(.embed) .ws-strip{display:flex;align-items:center;gap:8px;flex:none;margin:8px 12px;padding:10px 13px;border:1px solid var(--line);border-radius:var(--r-lg);background:var(--raised);font-family:var(--mono);font-size:12.5px;color:var(--fg-2);text-align:left;cursor:pointer}
	.ws-strip .ws-strip-turn{flex:none;color:var(--fg-3)}
	.ws-strip .ws-strip-turn.running{color:var(--s-autotest)}
	.ws-strip .ws-strip-turn.done{color:var(--s-merge)}
	.ws-strip .ws-strip-turn.error{color:var(--danger)}
	.ws-strip .ws-strip-diff{flex:1 1 auto;min-width:0;text-align:right;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
	.ws-strip .ws-strip-chev{flex:none;color:var(--fg-3)}
	/* ── Embedded sessions (issue-page tabs) keep the pre-existing stacked
	   layout: horizontal session strip + bounded chat/diff panes. */
	.embed #ws-rail .bcol-bd{display:flex;overflow-x:auto;scrollbar-width:thin}
	.embed #ws-rail .lane{flex:0 0 230px;border-bottom:0;border-right:1px solid var(--line-soft)}
	.embed #ws-rail .lane[aria-current="true"]{box-shadow:inset 0 3px 0 var(--fg)}
	.embed #ws-chat{height:72vh;height:72dvh;min-height:420px}
	.embed #ws-bcol{height:60vh;height:60dvh;min-height:300px}
	.msg{padding:12px 13px}
	.chat-input{padding:10px 12px}
	.bcol-hd{flex-wrap:wrap;row-gap:6px}
	.submitbar{padding:12px 14px;gap:10px}
	.submitbar.slim{gap:10px}

	/* ── Shared phone bottom tab bar (issue page, code browser) ── */
	.mb-tabbar{display:flex;position:fixed;left:0;right:0;bottom:0;z-index:80;border-top:1px solid var(--line);background:var(--surface);padding:6px 8px calc(8px + env(safe-area-inset-bottom))}
	.mb-tabbar button{flex:1;border:0;background:none;color:var(--fg-3);font-family:var(--sans);font-size:11.5px;font-weight:600;letter-spacing:.03em;padding:6px 2px;border-radius:9px;display:flex;flex-direction:column;align-items:center;gap:3px;cursor:pointer}
	.mb-tabbar button.on{color:var(--fg);background:var(--raised)}
	.mb-tabbar .ic{font-size:17px;line-height:1}
	.mb-tabbar .icwrap{position:relative}
	.mb-tabbar .tbadge{position:absolute;transform:translate(11px,-4px);min-width:16px;height:16px;padding:0 4px;border-radius:9px;background:var(--nav);color:#fff;font-size:10.5px;font-weight:700;line-height:16px}
	body.ticket-body,body.code-body{padding-bottom:76px}

	/* ── Issue page: bottom-tab shell. Issue (main col) is the default screen;
	   Details and Build re-home the other two columns; Review reuses the
	   existing view switch. Desktop ignores all of this — the bar is hidden
	   and the tk-* body classes only matter inside this media query. */
	body.ticket-body .views{display:none}
	/* Desktop tabs are the bottom bar on phones; keep the assignee visible
	   on Review as a single compact line (no extra card). */
	body.ticket-body:has(#view-review:not([hidden])) .views{display:flex}
	body.ticket-body:has(#view-review:not([hidden])) .views>[role="tab"]{display:none}
	body.ticket-body .cols>.col-rail,
	body.ticket-body .cols>.col-sessions{display:none}
	body.ticket-body.tk-details .cols>.col-rail{display:block}
	body.ticket-body.tk-details .cols>.col-main{display:none}
	body.ticket-body.tk-build .cols>.col-sessions{display:block}
	body.ticket-body.tk-build .cols>.col-main{display:none}

	/* ── Code browser: Files / Code tabs. The toolbar and tree are the Files
	   screen; the editor gets the whole viewport on Code. Crumbs and the
	   merge-cmd copy are desktop niceties — dropped for the row. */
	body.code-body .code-split{display:block}
	body.code-body:not(.cb-code) .code-split>.code-main{display:none}
	body.code-body.cb-code .code-split>:not(.code-main){display:none}
	body.code-body.cb-code .code-toolbar{display:none}
	body.code-body .code-tree{max-height:none}
	body.code-body #cb-crumbs,body.code-body #merge-cmd-copy{display:none}
	/* Code line numbers: the desktop 68px gutter (54 + 14 padding) is a fifth
	   of a phone row — compact to ~40px. Fits 4-digit files; a 10k-line file
	   just nudges its rows. Font stays ≥11px, and the EDIT gutter keeps its
	   21.45px line-height so numbers stay locked to the textarea rows. */
	.code-pre .cl::before{width:32px;padding-right:8px;font-size:11px}
	.code-pre.blame .cl-blame{width:100px}
	.cv-editwrap.cv-has-gutter{padding-left:38px}
	.cv-editwrap.cv-has-gutter .cv-hl{left:38px}
	.cv-editwrap .cv-gutter{width:38px}
	.cv-editwrap .cv-gutter .cl{padding-right:6px;font-size:11px}
	/* File header: one row — filename · ⋯ · ✎ Edit. History/Blame/Why (and
	   the site actions) fold behind the ⋯; the rev/size micro-text goes. */
	body.code-body #cb-filehead{flex-wrap:nowrap;position:relative}
	body.code-body #cb-filehead #cb-filename{flex:1 1 auto;min-width:0}
	body.code-body #cb-filemeta{display:none}
	body.code-body .cb-acts-btn{display:inline-flex}
	body.code-body .cb-fileacts{display:none}
	body.code-body #cb-filehead.acts-open .cb-fileacts{display:flex;position:absolute;top:calc(100% + 6px);right:8px;z-index:40;flex-direction:column;align-items:stretch;gap:8px;padding:10px;background:var(--raised);border:1px solid var(--line);border-radius:var(--r-lg);box-shadow:var(--shadow)}
	body.code-body #cb-filehead .cb-acts-btn[aria-expanded="true"]{color:var(--fg);border-color:var(--fg-3)}

	/* ── Easy wins elsewhere ── */
	.code-toolbar{flex-wrap:wrap;gap:8px}
	.run-batch-hd .run-when{margin-left:0;flex-basis:100%}
	.admin-table{display:block;overflow-x:auto}
	.ns-overlay{padding:0;align-items:flex-end}
	.ns-dialog{width:100%;max-height:min(92dvh,100%);overflow-y:auto;border-radius:14px 14px 0 0;padding-bottom:env(safe-area-inset-bottom)}
	.ns-dialog-hd{padding:14px 16px}
	.ns-dialog .create{padding:16px;gap:12px}
	.create input.ns-title,.create .ns-box textarea{font-size:16px}
	.ns-box{padding:12px}
	.ns-box-foot{gap:8px}
	.ns-pick{max-width:none;flex:1 1 140px}
	.ns-kbd{display:none}
	.create-foot{margin-top:4px;gap:8px}
	.create-foot .btn-primary,.create-foot #ns-file,.create-foot #ns-build{flex:1 1 100%;justify-content:center;min-height:44px}
	.create-foot .ns-meta{flex:1 1 calc(50% - 8px);min-width:0}
}

/* Reduced motion: the session sheets snap open/closed instead of sliding. */
@media (max-width:720px) and (prefers-reduced-motion:reduce){
	body.session-body:not(.embed) #ws-rail,
	body.session-body:not(.embed) #ws-bcol,
	body.session-body:not(.embed) .ws-scrim{transition:none}
}

/* Slash dropdown (composer): a drop-up .menu anchored above the input while
   the message starts with "/". .sel is the keyboard-highlighted row. */
.slash-menu{left:0;right:0;top:auto;bottom:calc(100% + 6px);max-height:300px;overflow-y:auto}
/* The @ picker stacks three groups (fields / comments / chats) — the slash menu's 300px cap showed ~3 rows. */
#mention-hint{max-height:min(60vh, 560px)}
.slash-menu .menu-item.sel{background:var(--raised)}
.slash-menu .menu-item span:first-child{font-family:var(--mono);font-size:13px}
/* @ picker: the comment and chat groups share one list, so each group header is a
   banded divider (not just muted caps) and every row leads with a kind tag. */
#mention-hint .menu-hd{color:var(--fg);background:var(--sunken);border-top:1px solid var(--line-soft);border-bottom:1px solid var(--line-soft);margin:4px -5px 2px;padding:7px 15px 6px}
#mention-hint .menu-hd:first-child{margin-top:-5px;border-top:0;border-radius:var(--r-lg) var(--r-lg) 0 0}
#mention-hint .menu-item span:first-child{display:flex;align-items:center;gap:8px;min-width:0}
.mi-kind{flex:none;font:600 10px/1 var(--sans);letter-spacing:.06em;text-transform:uppercase;padding:3px 5px;border-radius:4px;background:var(--raised);border:1px solid var(--line-soft);color:var(--fg-2)}
.mi-kind.is-comment{color:var(--s-testing);border-color:color-mix(in srgb, var(--s-testing) 45%, transparent)}
.mi-kind.is-field{color:var(--s-merge);border-color:color-mix(in srgb, var(--s-merge) 45%, transparent)}
.mi-kind.is-chat{color:var(--s-review);border-color:color-mix(in srgb, var(--s-review) 45%, transparent)}

/* ── Table page (table.php): the spreadsheet view of issues ── */
.tt-toolbar{display:flex;align-items:center;gap:10px;margin:18px 0 10px}
.tt-toolbar .rule{flex:0 1 60px;height:1px;background:var(--line)}
.tt-scroll{overflow-x:auto;border:1px solid var(--line);border-radius:var(--r-lg);background:var(--surface)}
.tickets-table{width:100%;border-collapse:collapse;font-size:var(--fs-ui)}
.tickets-table th{position:relative;text-align:left;font-family:var(--sans);font-size:var(--fs-label);font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--fg-3);padding:11px 12px;border-bottom:1px solid var(--line);white-space:nowrap}
.tickets-table th a{color:inherit;text-decoration:none;display:inline-flex;align-items:center;gap:5px}
.tickets-table th a:hover{color:var(--fg)}
.tickets-table .tt-dir{font-size:10px;color:var(--nav)}
.tickets-table td{padding:10px 12px;border-bottom:1px solid var(--line-soft);vertical-align:middle;color:var(--fg)}
.tickets-table tr:last-child td{border-bottom:0}
.tickets-table tbody tr:hover td{background:color-mix(in srgb,var(--raised) 55%,transparent)}
.tt-nw{white-space:nowrap}
.tt-key{white-space:nowrap}
.tt-key a{font-family:var(--mono);font-size:var(--fs-meta);color:var(--fg-2);text-decoration:none}
.tt-key a:hover{color:var(--nav)}
.tt-title-cell{min-width:240px;max-width:420px}
.tt-title-cell a{color:var(--fg);text-decoration:none;font-weight:550;display:inline-block;max-width:calc(100% - 30px);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:middle}
/* User-sized columns (drag the header edge). Fixed layout so a wider Title
   keeps its width and the grid scrolls sideways instead of squashing neighbors.
   The default max-width caps are only for the unsized auto layout. */
.tickets-table.tt-sized{table-layout:fixed}
.tickets-table.tt-sized .tt-title-cell,
.tickets-table.tt-sized .tt-long{min-width:0;max-width:none}
.tickets-table.tt-sized td{overflow:hidden;text-overflow:ellipsis}
.tt-resize{appearance:none;-webkit-appearance:none;position:absolute;top:0;right:0;z-index:2;width:14px;height:100%;min-width:0;min-height:0;margin:0;padding:0;border:0;background:transparent;cursor:col-resize;touch-action:none}
.tt-resize::after{content:"";position:absolute;top:8px;bottom:8px;right:0;width:2px;border-radius:1px;background:transparent}
.tickets-table th:hover > .tt-resize::after,
.tt-resize:hover::after,
.tt-resize:focus-visible::after,
.tt-resize.is-active::after{background:var(--fg-3)}
.tt-resize:hover::after,
.tt-resize.is-active::after{background:var(--fg)}
body.tt-col-drag{cursor:col-resize;user-select:none}
body.tt-col-drag *{cursor:col-resize !important}
.tt-title-cell a:hover{color:var(--nav)}
.tt-long{min-width:200px;max-width:320px}
.tt-none{color:var(--fg-3)}
.tt-val{display:inline-block;max-width:100%}
/* Click-to-edit cells: quiet until hovered, then a clear editable affordance.
   Negative margins keep the visual row height while growing the hit target. */
.tt-edit{display:inline-block;max-width:100%;background:none;border:0;color:inherit;font:inherit;text-align:left;padding:8px 8px;margin:-8px -8px;border-radius:var(--r);cursor:pointer}
.tt-edit:hover{background:var(--raised);box-shadow:inset 0 0 0 1px var(--line)}
.tt-status{display:inline-flex;align-items:center;gap:7px;font-family:var(--sans);font-size:var(--fs-label);font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--stage)}
.tt-status .d{width:7px;height:7px;border-radius:50%;background:var(--stage);flex:none}
/* Clipped long-text cells: one line in the grid, the whole thing on hover. */
.tt-clip,.tt-clip .tt-snip{display:inline-block;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:middle}
.tt-pop{position:fixed;z-index:300;max-width:min(560px,calc(100vw - 16px));max-height:min(440px,60vh);overflow:auto;padding:12px 14px;background:var(--surface);color:var(--fg);border:1px solid var(--line);border-radius:var(--r-lg);box-shadow:0 18px 50px -18px rgba(0,0,0,.55),0 2px 6px rgba(0,0,0,.28);font-size:var(--fs-ui);line-height:1.6;white-space:pre-wrap;pointer-events:none}
.tt-pencil{background:none;border:0;color:var(--fg-3);font-size:13px;padding:6px;margin-left:2px;border-radius:var(--r);cursor:pointer;opacity:0;vertical-align:middle}
.tt-row:hover .tt-pencil{opacity:1}
.tt-pencil:hover{color:var(--fg);background:var(--raised)}
/* Column picker rows: checkbox toggle + move-left/right arrows for order. */
.tt-cols-pop{width:300px}
.tt-col-row{display:flex;align-items:center;gap:2px}
.tt-col-row .fp-opt{flex:1;min-width:0}
.tt-col-move{flex:none;width:30px;height:30px;background:none;border:0;border-radius:var(--r);color:var(--fg-2);cursor:pointer;font-size:13px}
.tt-col-move:hover{background:var(--raised);color:var(--fg)}
.tt-col-move:disabled{opacity:.3;cursor:default;background:none}
.tt-cols-pop .fp-foot{display:flex;border-top:1px solid var(--line)}
.tt-cols-pop .fp-foot .fp-opt{flex:1;text-align:center;border-radius:0;margin:0}

/* ===== BISECT BOARD (grouped by culprit) =====
   One header row per culprit merge with the specs it broke beneath it. The
   header carries the group's tint as a left rail (same palette as the
   revision chip) so a folded group still reads as "that merge". Folding is
   a class, filtering is the hidden attribute — the two never fight. */
.bz-table td:first-child{width:28px;padding-right:0}
.bz-table tr.bz-group td{background:color-mix(in srgb,var(--raised) 70%,var(--sunken));border-bottom:1px solid var(--line-soft)}
.bz-table tr.bz-group td:first-child{border-left:3px solid var(--bz-tint,transparent);padding-left:9px}
.bz-table tr.bz-child td:first-child{border-left:3px solid transparent;padding-left:9px}
.bz-table tr.bz-child.bz-folded{display:none}
.bz-table tr.bz-idle td{opacity:.65}
.bz-culprit-line{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.bz-culprit-key{font-weight:600;color:var(--fg)}
.bz-bucket-title{font-weight:600;color:var(--fg)}
.bz-culprit-msg{font-size:13px;color:var(--fg-2);margin-top:2px;max-width:520px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.bz-count{font-family:var(--cond);font-weight:600;font-size:15px;font-variant-numeric:tabular-nums}
.bz-actions{white-space:nowrap;text-align:right}
.bz-fold{display:inline-grid;place-items:center;width:22px;height:22px;border-radius:50%}
.bz-fold:hover{background:var(--raised)}
.bz-fold:focus-visible{outline:2px solid var(--nav);outline-offset:1px}
.bz-fold svg{width:14px;height:14px;transition:transform .15s ease}
tr.bz-group.bz-folded .bz-fold svg{transform:rotate(-90deg)}
@media (prefers-reduced-motion: reduce){ .bz-fold svg{transition:none} }
.bz-coverage{font-size:12.5px;color:var(--fg-2);margin-top:4px;display:flex;flex-wrap:wrap;gap:4px 8px;align-items:center}
.bz-suite{display:inline-block;font-family:var(--mono);font-size:11.5px;padding:0 6px;border:1px solid var(--line);border-radius:999px;color:var(--fg-2);background:var(--raised)}
.bz-suite.is-hit{color:var(--s-merge);border-color:color-mix(in srgb,var(--s-merge) 45%,var(--line))}
.bz-suite.is-miss{color:var(--danger);border-color:color-mix(in srgb,var(--danger) 45%,var(--line));background:color-mix(in srgb,var(--danger) 8%,var(--raised))}
.bz-missed{color:var(--danger)}
.bz-spec-path{font-size:11.5px;color:var(--fg-3);margin-top:3px;display:flex;flex-wrap:wrap;gap:4px 8px;align-items:center;overflow-wrap:anywhere}
.bz-table td.mono a{color:var(--fg)}
.bz-table td.mono a:hover{color:var(--nav)}

/* Unmerge overlap: what a waiting unmerge conflicts WITH (issue page spine foot + session conflict panel). */
.spine-foot .um-overlaps { flex-basis: 100%; }
.spine-foot .um-overlaps .t-micro { margin-left: 0; }
.um-overlaps { display: flex; flex-direction: column; gap: 8px; margin-top: 4px; padding: 10px 12px; border: 1px solid var(--line); border-radius: 8px; background: var(--bg-2, transparent); font-size: 13.5px; }
.um-overlap-head { font-size: 12px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; color: var(--fg-3); }
.um-overlap-issue { display: grid; grid-template-columns: auto 1fr auto; column-gap: 12px; align-items: start; }
.um-overlap-key { padding-top: 1px; }
.um-overlap-key a { color: var(--fg); text-decoration: none; border-bottom: 1px dashed var(--line); }
.um-overlap-key a:hover { border-bottom-color: var(--fg); }
.um-overlap-body { min-width: 0; }
.um-overlap-title { color: var(--fg); line-height: 1.35; }
.um-overlap-meta { margin-top: 2px; font-size: 12px; }
.um-overlap-who { color: var(--fg-2); }
/* Bystander: changed a conflicted file without colliding (dry-run narrowing) — listed, dimmed, never chained. */
.um-overlap-issue.is-bystander { opacity: .6; }
.um-bystander { margin-left: 6px; font-size: 11.5px; padding: 0 6px; border: 1px solid var(--line); border-radius: 999px; color: var(--fg-3); white-space: nowrap; }
.um-overlap-targets { display: flex; flex-wrap: wrap; gap: 4px; justify-content: flex-end; max-width: 280px; }
.um-chip { font-family: var(--mono); font-size: 12px; padding: 1px 7px; border: 1px solid var(--line); border-radius: 999px; color: var(--fg-2); white-space: nowrap; }
.um-overlap-note { color: var(--fg-3); font-size: 12.5px; }
.um-overlap-verdict { color: var(--fg-2); font-size: 12.5px; padding-top: 6px; border-top: 1px dashed var(--line-soft, var(--line)); }
.um-overlap-verdict.is-clean { color: var(--s-open); }
.um-overlap-acts { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.um-overlap-or { color: var(--fg-3); font-size: 12.5px; }
.um-overlaps.um-keep { flex-direction: row; flex-wrap: wrap; align-items: center; }
@media (max-width: 900px) { .um-overlap-issue { grid-template-columns: auto 1fr; } .um-overlap-targets { grid-column: 2; justify-content: flex-start; max-width: none; } }
.rb-state.rb-overlap { align-items: flex-start; }
.rb-state.rb-overlap .rb-btn { white-space: nowrap; color: var(--danger); }
.rb-overlap-acts { display: flex; flex-direction: column; gap: 6px; margin-left: auto; }
.rb-state.rb-overlap .rb-btn.rb-keep { color: var(--fg-2); }
/* Back-merge attribution block on the branch rail (lib/BackmergeOverlap.php):
   the rail is ~320px wide, so the unmerge block's three-column grid collapses
   to two and the target chips wrap under the body. */
.branch-sub .bm-overlaps { width: 100%; box-sizing: border-box; font-size: 12.5px; }
.bm-overlaps .um-overlap-issue { grid-template-columns: auto 1fr; }
.bm-overlaps .um-overlap-targets { grid-column: 2; justify-content: flex-start; max-width: none; }
.bm-overlap-badges { margin-top: 3px; display: flex; flex-wrap: wrap; gap: 4px; }
.bm-badge { font-size: 11.5px; padding: 1px 7px; border-radius: 999px; border: 1px solid var(--line); color: var(--fg-2); white-space: nowrap; }
.bm-badge-ok { color: var(--s-merge); border-color: var(--s-merge); }
.bm-badge-warn { color: var(--danger); border-color: var(--danger); }
.bm-badge-off { color: var(--fg-3); }
.bm-paved { color: var(--s-open); }
