/* =====================================================================
   Keyanna Release Management - design system
   Extends the NivFlow Monitor token set (localhost:8088/app.css) with the
   components a tracker needs: data grids, filter rows, chips, timelines,
   progress meters and avatars.
   Themes: keyanna (default, navy/orange), nivtrix (purple/pink),
           keyanna-light (the light variant proposed in the analysis).
   ===================================================================== */

/* ---- semantic colours, shared by every theme ---- */
:root {
  --ok:#3fb950; --err:#f85149; --warn:#f0b429; --net:#4c8dff; --viol:#a371f7;
  --p1:#f85149; --p2:#f0883e; --p3:#f0b429; --p4:#9aa3b4;
}

/* ---- Keyanna (default): navy surfaces + orange/magenta brand ---- */
:root, :root[data-theme="keyanna"] {
  color-scheme:dark;
  --bg:#0e1119; --panel:#141824; --panel2:#1c2130; --panelDeep:#0f131d;
  --line:#2b3242; --lineSoft:#222839; --ink:#eef1f6; --inkDim:#c8cedb;
  --muted:#9aa3b4; --accent:#f95d1a; --brand2:#cc3366; --bgGlow:#2a1a12;
  --rowHover:rgba(249,93,26,.07); --shadow:0 18px 44px -22px rgba(0,0,0,.85);
}

/* ---- Nivtrix: purple surfaces + pink/violet brand ---- */
:root[data-theme="nivtrix"] {
  color-scheme:dark;
  --bg:#0e0b18; --panel:#160f22; --panel2:#1e162e; --panelDeep:#140c22;
  --line:#2c2440; --lineSoft:#241d36; --ink:#f4f0fa; --inkDim:#d8d0e4;
  --muted:#b0a8c0; --accent:#ff0088; --brand2:#9b51e0; --bgGlow:#241536;
  --rowHover:rgba(255,0,136,.07); --shadow:0 18px 44px -22px rgba(0,0,0,.85);
}

/* ---- Keyanna light: echoes the grey of the system it replaces ---- */
:root[data-theme="keyanna-light"] {
  color-scheme:light;
  --bg:#eef0f3; --panel:#ffffff; --panel2:#f4f6f9; --panelDeep:#e7eaef;
  --line:#d5dbe4; --lineSoft:#e4e8ee; --ink:#171b23; --inkDim:#333a47;
  --muted:#5c6673; --accent:#d2490b; --brand2:#ac2853; --bgGlow:#f6ece6;
  --rowHover:rgba(210,73,11,.06); --shadow:0 14px 34px -20px rgba(23,27,35,.3);
  --ok:#1a7f37; --err:#cf222e; --warn:#8f6100; --net:#0969da; --viol:#8250df;
  --p1:#cf222e; --p2:#bc4c00; --p3:#8f6100; --p4:#5c6673;
}

* { box-sizing:border-box; }

html, body {
  margin:0; height:100%;
  font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  background:var(--bg); color:var(--ink);
  font-size:14px;
}
body { display:flex; flex-direction:column; }
a { color:var(--accent); text-decoration:none; }
a:hover { text-decoration:underline; }
:focus-visible { outline:2px solid var(--accent); outline-offset:2px; border-radius:4px; }

/* =============================== login ============================= */

/* A class, not an id: this rule makes an element a full-screen overlay, and
   an id selector will happily apply that to any element that shares the name. */
.loginGate {
  position:fixed; inset:0; z-index:1000;
  display:flex; flex-direction:column; align-items:center; justify-content:center; gap:16px;
  background:radial-gradient(1200px 600px at 50% -10%, var(--bgGlow), var(--bg));
}
.loginCard {
  width:360px; max-width:90vw; background:var(--panel); border:1px solid var(--line);
  border-radius:16px; padding:28px 26px; display:flex; flex-direction:column;
  box-shadow:0 20px 60px rgba(0,0,0,.45);
}
.loginLogo { height:36px; width:auto; align-self:center; margin-bottom:14px; }
.loginTitle { text-align:center; font-size:21px; font-weight:700; letter-spacing:.3px; }
.loginTitle b {
  background:linear-gradient(90deg,var(--accent),var(--brand2));
  -webkit-background-clip:text; background-clip:text; -webkit-text-fill-color:transparent;
}
.loginSub { text-align:center; font-size:12px; color:var(--muted); margin:4px 0 18px; }
.llabel { font-size:10px; text-transform:uppercase; letter-spacing:.6px; color:var(--muted); margin-bottom:5px; }
.loginCard input[type=text], .loginCard input[type=password] {
  background:var(--panel2); border:1px solid var(--line); color:var(--ink);
  border-radius:8px; padding:10px 12px; font-size:14px; outline:none; margin-bottom:14px; width:100%;
}
.loginCard input:focus { border-color:var(--accent); }
.loginBtn {
  margin-top:4px; border:none; border-radius:9px; padding:11px; font-size:14px;
  font-weight:650; color:#fff; cursor:pointer;
  background:linear-gradient(90deg,var(--accent),var(--brand2));
}
.loginBtn:hover { filter:brightness(1.08); }
.loginErr { min-height:16px; color:var(--err); font-size:12px; margin-bottom:8px; }
.loginOk { min-height:16px; color:var(--ok); font-size:12px; margin-bottom:8px; }
.loginFoot { font-size:11px; color:var(--muted); }
.loginHint {
  font-size:11px; color:var(--muted); text-align:center; margin-top:14px;
  padding-top:12px; border-top:1px solid var(--line); line-height:1.7;
}
.loginHint code {
  background:var(--panel2); border:1px solid var(--line); border-radius:4px;
  padding:1px 5px; color:var(--inkDim); font-size:11px;
}
.rememberRow { display:flex; align-items:center; gap:8px; font-size:12.5px; color:var(--muted); margin-bottom:14px; }

/* =============================== shell ============================= */

#appShell { flex:1; display:flex; min-height:0; }

#sidebar {
  width:216px; flex-shrink:0;
  background:linear-gradient(180deg,var(--panel),var(--panelDeep));
  border-right:1px solid var(--line);
  display:flex; flex-direction:column; transition:width .15s ease; overflow:hidden;
}
#appShell.collapsed #sidebar { width:58px; }
.sbTop {
  display:flex; align-items:flex-start; justify-content:space-between; gap:8px;
  padding:16px 14px 14px; border-bottom:1px solid var(--line); min-height:74px;
}
.sbBrand { display:flex; flex-direction:column; gap:6px; overflow:hidden; }
.sbLogoFull { height:26px; width:auto; display:block; }
.sbLogoMini { height:28px; width:28px; display:none; }
.sbProd {
  font-size:15px; font-weight:800; letter-spacing:.4px; line-height:1; white-space:nowrap;
  background:linear-gradient(90deg,var(--accent),var(--brand2));
  -webkit-background-clip:text; background-clip:text; -webkit-text-fill-color:transparent;
}
#appShell.collapsed .sbLogoFull, #appShell.collapsed .sbProd { display:none; }
#appShell.collapsed .sbLogoMini { display:block; }
#appShell.collapsed .sbTop { flex-direction:column; align-items:center; }
.sbToggle { background:none; border:none; color:var(--muted); cursor:pointer; padding:4px; border-radius:7px; display:flex; }
.sbToggle svg { width:20px; height:20px; }
.sbToggle:hover { color:var(--ink); background:var(--panel2); }
.sbNav { display:flex; flex-direction:column; padding:10px 8px; gap:3px; flex:1; overflow-y:auto; }
.sbBottom { padding:10px 8px; border-top:1px solid var(--line); display:flex; flex-direction:column; gap:3px; }
.sbSection {
  font-size:9.5px; text-transform:uppercase; letter-spacing:.11em; color:var(--muted);
  padding:12px 12px 5px; font-weight:600; white-space:nowrap;
}
#appShell.collapsed .sbSection { display:none; }
.sbItem {
  display:flex; align-items:center; gap:11px; width:100%; background:none; border:none;
  color:var(--ink); padding:9px 12px; border-radius:9px; cursor:pointer; font-size:13px;
  text-align:left; white-space:nowrap; text-decoration:none;
}
.sbItem:hover { background:var(--panel2); text-decoration:none; }
.sbItem.active {
  background:linear-gradient(90deg,
    color-mix(in srgb, var(--accent) 20%, transparent),
    color-mix(in srgb, var(--brand2) 6%, transparent));
  font-weight:600;
}
.sbIco { width:18px; height:18px; flex-shrink:0; stroke-width:1.8; }
.sbItem.active .sbIco { color:var(--accent); }
#appShell.collapsed .sbLbl { display:none; }
#appShell.collapsed .sbItem { justify-content:center; padding:9px 0; }

#mainCol { flex:1; display:flex; flex-direction:column; min-height:0; }

/* =============================== topbar ============================ */

header.topbar {
  padding:0 20px; min-height:56px; flex-shrink:0;
  background:linear-gradient(90deg,var(--panel),var(--panelDeep));
  border-bottom:1px solid var(--line);
  display:flex; gap:16px; align-items:center;
}
.crumbs { display:flex; align-items:center; gap:8px; font-size:13px; color:var(--muted); min-width:0; }
.crumbs a { color:var(--inkDim); }
.crumbs .sep { color:var(--line); }
.crumbs .cur { color:var(--ink); font-weight:600; }
.topSpacer { flex:1; }
.topSearch {
  background:var(--panel2); border:1px solid var(--line); color:var(--ink);
  border-radius:8px; padding:7px 11px; font-size:13px; min-width:220px; outline:none;
}
.topSearch:focus { border-color:var(--accent); }
.userChip { display:flex; align-items:center; gap:9px; font-size:13px; color:var(--inkDim); }

/* =============================== content =========================== */

main.content { flex:1; min-height:0; overflow:auto; padding:20px 22px 44px; }
.pageHead {
  display:flex; align-items:center; gap:14px; flex-wrap:wrap; margin-bottom:18px;
}
.pageHead h1 { margin:0; font-size:21px; font-weight:700; letter-spacing:-.2px; }
.pageHead .spacer { flex:1; }
.pageSub { color:var(--muted); font-size:13px; margin:-10px 0 18px; }

.card {
  background:var(--panel); border:1px solid var(--line); border-radius:10px;
  overflow:hidden; margin-bottom:18px;
}
.cardHead {
  padding:12px 16px; border-bottom:1px solid var(--line); background:var(--panel2);
  display:flex; align-items:center; gap:12px;
}
.cardHead h2 { margin:0; font-size:14px; font-weight:650; }
.cardHead .spacer { flex:1; }
.cardBody { padding:16px; }
.grid2 { display:grid; grid-template-columns:repeat(auto-fit,minmax(300px,1fr)); gap:18px; }
.grid3 { display:grid; grid-template-columns:repeat(auto-fit,minmax(230px,1fr)); gap:14px; }
/* Full-width panels, one under the next. */
.stack { display:grid; grid-template-columns:1fr; gap:18px; }

/* =============================== buttons =========================== */

.btn {
  border:1px solid var(--line); background:var(--panel2); color:var(--ink);
  border-radius:8px; padding:8px 14px; font-size:13px; cursor:pointer;
  display:inline-flex; align-items:center; gap:7px; text-decoration:none; font-weight:500;
}
.btn:hover { border-color:var(--accent); text-decoration:none; }
.btn svg { width:15px; height:15px; }
.btn.primary {
  background:linear-gradient(90deg,var(--accent),var(--brand2));
  border-color:transparent; color:#fff; font-weight:600;
}
.btn.primary:hover { filter:brightness(1.09); }
.btn.danger:hover { border-color:var(--err); color:var(--err); }
.btn.sm { padding:5px 10px; font-size:12px; border-radius:7px; }
.btn:disabled { opacity:.45; cursor:not-allowed; }
.btnRow { display:flex; gap:9px; flex-wrap:wrap; align-items:center; }

/* =============================== forms ============================= */

.field { display:flex; flex-direction:column; gap:5px; margin-bottom:14px; }
.field > label, .flabel {
  font-size:10px; text-transform:uppercase; letter-spacing:.6px; color:var(--muted); font-weight:600;
}
.field .req { color:var(--err); margin-left:2px; }
input[type=text], input[type=password], input[type=date], input[type=number],
input[type=email], select, textarea {
  background:var(--panel2); border:1px solid var(--line); color:var(--ink);
  border-radius:8px; padding:8px 11px; font-size:13.5px; outline:none;
  font-family:inherit; width:100%;
}
input:focus, select:focus, textarea:focus { border-color:var(--accent); }
textarea { min-height:130px; resize:vertical; line-height:1.6; }
select { cursor:pointer; }
/* The open dropdown is drawn by the operating system, not by this stylesheet,
   so styling the select itself does nothing for the list of options - they
   came out dark text on a dark popup and were unreadable. color-scheme is how
   a page tells the platform which palette to draw its native controls in, and
   it has to be declared per theme rather than once. */
option { background:var(--panel2); color:var(--ink); }
input[type=checkbox] { accent-color:var(--accent); width:15px; height:15px; }
.formGrid { display:grid; grid-template-columns:repeat(auto-fit,minmax(240px,1fr)); gap:0 18px; }
.checkLine { display:flex; align-items:center; gap:8px; font-size:13px; margin-bottom:12px; }
.hint { font-size:11.5px; color:var(--muted); }
.fieldError { color:var(--err); font-size:11.5px; }

/* =============================== tables ============================ */

.tableWrap { overflow-x:auto; }
table.data { border-collapse:collapse; width:100%; font-size:13px; }
table.data thead th {
  text-align:left; padding:9px 12px; color:var(--muted); font-weight:600;
  border-bottom:1px solid var(--line); background:var(--panel2);
  font-size:10.5px; text-transform:uppercase; letter-spacing:.07em; white-space:nowrap;
  position:sticky; top:0; z-index:2;
}
table.data thead th a { color:var(--muted); }
table.data thead th a:hover { color:var(--ink); }
table.data thead th.sorted a { color:var(--accent); }
table.data tbody td { padding:9px 12px; border-bottom:1px solid var(--lineSoft); vertical-align:middle; }
table.data tbody tr:hover td { background:var(--rowHover); }
table.data tbody tr.closed td .subj { text-decoration:line-through; opacity:.65; }
table.data td.num { text-align:right; font-variant-numeric:tabular-nums; white-space:nowrap; }
table.data td.id { font-variant-numeric:tabular-nums; white-space:nowrap; }
table.data tr.groupRow td {
  background:var(--panel2); font-weight:650; font-size:12.5px; padding:8px 12px;
  border-bottom:1px solid var(--line); border-top:1px solid var(--line);
}
table.data tr.totalRow td {
  background:var(--panel2); font-weight:650; border-top:2px solid var(--line);
  position:sticky; bottom:0;
}
.subj { color:var(--ink); }
.subj:hover { color:var(--accent); }
.tblEmpty { padding:44px; text-align:center; color:var(--muted); font-size:13.5px; }

/* =============================== chips ============================= */

.chip {
  display:inline-block; font-size:10.5px; font-weight:700; padding:3px 9px;
  border-radius:20px; white-space:nowrap; letter-spacing:.03em;
}
.chip.sq { border-radius:5px; }
.st-open     { background:color-mix(in srgb,var(--net) 16%,transparent);  color:var(--net); }
.st-progress { background:color-mix(in srgb,var(--p2) 17%,transparent);   color:var(--p2); }
.st-devdone  { background:color-mix(in srgb,var(--viol) 17%,transparent); color:var(--viol); }
.st-qa       { background:color-mix(in srgb,var(--warn) 18%,transparent); color:var(--warn); }
.st-pending  { background:color-mix(in srgb,var(--muted) 17%,transparent);color:var(--muted); }
.st-closed   { background:color-mix(in srgb,var(--ok) 16%,transparent);   color:var(--ok); }
.pr-P1 { background:color-mix(in srgb,var(--p1) 16%,transparent); color:var(--p1); }
.pr-P2 { background:color-mix(in srgb,var(--p2) 16%,transparent); color:var(--p2); }
.pr-P3 { background:color-mix(in srgb,var(--p3) 17%,transparent); color:var(--p3); }
.pr-P4 { background:color-mix(in srgb,var(--p4) 17%,transparent); color:var(--p4); }
.trk {
  display:inline-block; font-size:11px; font-weight:600; padding:2px 8px;
  border-radius:5px; border:1px solid var(--line); background:var(--panel2); color:var(--inkDim);
}
.badge-count {
  display:inline-block; min-width:20px; text-align:center; font-size:11px; font-weight:700;
  padding:1px 7px; border-radius:20px; background:var(--panel2); border:1px solid var(--line); color:var(--muted);
}

/* =============================== avatars =========================== */

.av {
  width:26px; height:26px; border-radius:50%; flex-shrink:0;
  display:inline-flex; align-items:center; justify-content:center;
  font-size:10.5px; font-weight:700; color:#fff; letter-spacing:.02em;
}
.av.sm { width:20px; height:20px; font-size:9px; }
.av.lg { width:34px; height:34px; font-size:13px; }
.av-0 { background:linear-gradient(135deg,#f95d1a,#cc3366); }
.av-1 { background:linear-gradient(135deg,#4c8dff,#8957e5); }
.av-2 { background:linear-gradient(135deg,#3fb950,#1f6feb); }
.av-3 { background:linear-gradient(135deg,#a371f7,#cc3366); }
.av-4 { background:linear-gradient(135deg,#f0883e,#f85149); }
.av-5 { background:linear-gradient(135deg,#f0b429,#f95d1a); }
.av-6 { background:linear-gradient(135deg,#1f6feb,#3fb950); }
.av-7 { background:linear-gradient(135deg,#cc3366,#8957e5); }
.who { display:inline-flex; align-items:center; gap:7px; white-space:nowrap; }

/* =============================== filters =========================== */

.filterBar {
  background:var(--panel); border:1px solid var(--line); border-radius:10px;
  padding:14px 16px; margin-bottom:16px;
}
.filterRow { display:flex; gap:9px; align-items:center; margin-bottom:9px; flex-wrap:wrap; }
.filterRow select, .filterRow input { width:auto; }
.filterRow .fname { min-width:170px; }
.filterRow .fop { min-width:140px; }
.filterRow .fval { min-width:190px; }
.filterRow .rm {
  background:none; border:none; color:var(--muted); cursor:pointer; font-size:16px;
  line-height:1; padding:4px 7px; border-radius:6px;
}
.filterRow .rm:hover { color:var(--err); background:var(--panel2); }
.filterTools {
  display:flex; gap:9px; align-items:center; flex-wrap:wrap;
  padding-top:12px; border-top:1px solid var(--lineSoft); margin-top:4px;
}
.optToggle {
  font-size:12.5px; color:var(--muted); cursor:pointer; user-select:none;
  display:inline-flex; align-items:center; gap:6px;
}
.optToggle:hover { color:var(--ink); }
.optPanel {
  display:none; gap:20px; padding:14px 0 4px; border-top:1px solid var(--lineSoft);
  margin-top:10px; flex-wrap:wrap;
}
.optPanel.open { display:flex; }
.optCol { display:flex; flex-direction:column; gap:6px; min-width:180px; }
.colPicker { display:flex; gap:10px; align-items:center; }
.colPicker select[multiple] { height:160px; min-width:190px; }
.colPickerBtns { display:flex; flex-direction:column; gap:6px; }

.queryPills { display:flex; gap:7px; flex-wrap:wrap; margin-bottom:14px; }
.qp {
  border:1px solid var(--line); background:var(--panel2); color:var(--muted);
  border-radius:20px; padding:5px 13px; font-size:12.5px; cursor:pointer; text-decoration:none;
}
.qp:hover { color:var(--ink); border-color:var(--accent); text-decoration:none; }
.qp.active { background:var(--accent); border-color:var(--accent); color:#fff; font-weight:600; }

/* =============================== progress ========================== */

.meter {
  height:9px; border-radius:5px; background:var(--panel2); border:1px solid var(--line);
  overflow:hidden; min-width:90px; display:flex;
}
.meter .done { background:var(--ok); height:100%; }
.meter .part { background:var(--net); height:100%; }
.meterWrap { display:flex; align-items:center; gap:9px; font-size:12px; color:var(--muted); }
.meterWrap .pct { font-variant-numeric:tabular-nums; min-width:34px; text-align:right; }

/* =============================== issue page ======================== */

.issueHead {
  display:flex; align-items:flex-start; gap:14px; margin-bottom:6px; flex-wrap:wrap;
}
.issueHead h1 { margin:0; font-size:19px; font-weight:650; line-height:1.35; flex:1; min-width:260px; }
.issueMeta { font-size:12.5px; color:var(--muted); margin-bottom:18px; }
.attrGrid {
  display:grid; grid-template-columns:repeat(auto-fit,minmax(250px,1fr));
  gap:1px; background:var(--panel); border:1px solid var(--line);
  border-radius:10px; overflow:hidden;
}
/* display:grid is an author rule and [hidden] is only a browser default, so
   the author rule wins and a hidden grid stays on screen. The fold-away panel
   of empty fields was fully visible because of it. */
.attrGrid[hidden], .keyFacts[hidden] { display:none; }
/* The separators are drawn on the cells rather than by letting a line-coloured
   background show through the gaps. A grid rarely divides evenly into its
   columns, and the leftover space at the end of the last row was showing up as
   a stray coloured band with nothing in it. */
.attr {
  background:var(--panel); padding:10px 14px; display:flex; gap:10px;
  align-items:baseline; box-shadow:0 0 0 1px var(--line);
}
.attr .k { color:var(--muted); font-size:11.5px; min-width:112px; flex-shrink:0; }
.attr .v { font-size:13px; color:var(--ink); word-break:break-word; }
.attr .v.blank { color:var(--muted); }

/* ------------------------------------------------ issue approval */
/* A band across the top of an issue that is waiting on somebody, coloured by
   what it is waiting for. Above the facts because "this needs a decision"
   outranks every attribute underneath it. */
.approvalBar {
  display:flex; align-items:center; gap:12px; flex-wrap:wrap;
  padding:10px 14px; margin:0 0 14px;
  border:1px solid var(--line); border-radius:10px; background:var(--panel);
}
.approvalBar .approvalState { display:flex; flex-direction:column; gap:4px; }
.approvalBar .fk {
  font-size:10.5px; letter-spacing:.06em; text-transform:uppercase; color:var(--muted);
}
.approvalBar .fv { font-size:14px; font-weight:600; }
.approvalBar.awaiting { background:color-mix(in srgb,var(--warn,#f0b429) 10%,var(--panel)); }
.approvalBar.agreed   { background:color-mix(in srgb,#3fb950 10%,var(--panel)); }
.approvalBar.returned { background:color-mix(in srgb,var(--err) 10%,var(--panel)); }
.approvalDecide { display:flex; gap:6px; margin:0; }
.approvalDecide input { min-width:200px; }

/* ------------------------------------------- issue key facts */
/* The handful of attributes an issue is opened to check, given their own
   weight. They used to be five rows inside a grid of fifty-five, forty-five
   of which were empty custom fields reading as a dash - a large box saying
   almost nothing, which is what made the page look broken rather than sparse. */
.keyFacts {
  display:grid; grid-template-columns:repeat(auto-fit,minmax(160px,1fr));
  gap:1px; background:var(--line); border:1px solid var(--line);
  border-radius:10px; overflow:hidden; margin:0 0 18px;
}
.fact {
  background:var(--panel); padding:10px 14px;
  display:flex; flex-direction:column; gap:5px; align-items:flex-start;
}
.fact .fk {
  font-size:10.5px; letter-spacing:.06em; text-transform:uppercase; color:var(--muted);
}
.fact .fv { font-size:14px; font-weight:600; color:var(--ink); }
.fact .fv.blank { font-weight:400; color:var(--muted); }
/* Overdue is the one fact worth colouring: it is the only one that is a problem
   rather than a value. */
.fact.factAlert { background:color-mix(in srgb,var(--err) 9%,var(--panel)); }
.fact.factAlert .fv { color:var(--err); }

/* A heading for the details grid, so it reads as a section rather than as more
   of the thing above it. */
.detailHead { margin:22px 0 8px; padding:0; border:none; background:none; }
.detailHead h2 { font-size:13px; letter-spacing:.04em; text-transform:uppercase; color:var(--muted); }

.descBox {
  background:var(--panel); border:1px solid var(--line); border-radius:10px;
  padding:16px 18px; margin:16px 0; line-height:1.65; font-size:13.5px;
}
.descBox h1, .descBox h2, .descBox h3 { font-size:15px; margin:14px 0 6px; }
.descBox p { margin:0 0 10px; }
.descBox ul, .descBox ol { margin:0 0 10px; padding-left:22px; }
.descBox code {
  background:var(--panel2); border:1px solid var(--line); border-radius:4px;
  padding:1px 5px; font-family:ui-monospace,Menlo,Consolas,monospace; font-size:12px;
}
.descBox pre {
  background:var(--bg); border:1px solid var(--line); border-radius:8px; padding:12px;
  overflow:auto; font-size:12px; line-height:1.5;
}
.descBox pre code { background:none; border:none; padding:0; }
.descBox blockquote {
  margin:0 0 10px; padding-left:12px; border-left:3px solid var(--line); color:var(--muted);
}

/* history timeline */
.tl { display:flex; flex-direction:column; }
.tlItem { display:flex; gap:13px; padding-bottom:16px; position:relative; }
.tlNode { position:relative; flex-shrink:0; }
.tlItem:not(:last-child) .tlNode::after {
  content:""; position:absolute; left:50%; top:32px; bottom:-16px; width:1px;
  background:var(--line); transform:translateX(-50%);
}
.tlBody {
  flex:1; min-width:0; background:var(--panel); border:1px solid var(--line);
  border-radius:10px; padding:11px 15px;
}
.tlHead {
  display:flex; align-items:baseline; gap:9px; flex-wrap:wrap;
  font-size:12.5px; color:var(--muted); margin-bottom:4px;
}
.tlHead b { color:var(--ink); font-weight:600; font-size:13px; }
.tlHead .n { margin-left:auto; font-size:11.5px; color:var(--muted); }
.tlChanges { list-style:none; margin:6px 0 0; padding:0; display:flex; flex-direction:column; gap:3px; }
.tlChanges li { font-size:12.5px; color:var(--inkDim); }
.tlChanges .pk { color:var(--muted); }
.tlChanges .ov { color:var(--err); text-decoration:line-through; opacity:.8; }
.tlChanges .nv { color:var(--ok); }
.tlNote { margin-top:8px; font-size:13.5px; line-height:1.6; }
.tlNote p { margin:0 0 8px; }
.tlNote p:last-child { margin-bottom:0; }

/* =============================== misc ============================== */

.flash {
  padding:11px 16px; border-radius:9px; margin-bottom:16px; font-size:13.5px;
  border:1px solid transparent; display:flex; align-items:center; gap:10px;
}
.flash.ok  { background:color-mix(in srgb,var(--ok) 12%,transparent);  border-color:color-mix(in srgb,var(--ok) 35%,transparent);  color:var(--ok); }
.flash.err { background:color-mix(in srgb,var(--err) 12%,transparent); border-color:color-mix(in srgb,var(--err) 35%,transparent); color:var(--err); }

.pager { display:flex; gap:6px; align-items:center; padding:14px 2px; font-size:12.5px; color:var(--muted); flex-wrap:wrap; }
.pager a, .pager span.cur {
  padding:5px 10px; border-radius:7px; border:1px solid var(--line); background:var(--panel2);
  color:var(--inkDim); text-decoration:none; min-width:32px; text-align:center;
}
.pager a:hover { border-color:var(--accent); color:var(--accent); text-decoration:none; }
.pager span.cur { background:var(--accent); border-color:var(--accent); color:#fff; font-weight:600; }
.pager .info { margin-left:auto; }

/* The full-page empty state: an icon, a line of explanation, and room
   around it. Not to be confused with a blank single value, which uses
   .blank - the two shared a name once, and every blank field on the
   issue page came out 96px tall and centred because of it. */
div.empty { color:var(--muted); font-size:13.5px; padding:48px 20px; text-align:center; line-height:1.7; }
.empty .eico {
  width:52px; height:52px; margin:0 auto 14px; border-radius:50%;
  display:flex; align-items:center; justify-content:center;
  border:1px solid var(--line); background:var(--panel2); color:var(--muted);
}
.empty .eico svg { width:24px; height:24px; }
.empty .etitle { font-size:16px; font-weight:700; color:var(--ink); margin-bottom:6px; }

.kpiRow { display:grid; grid-template-columns:repeat(auto-fit,minmax(150px,1fr)); gap:12px; margin-bottom:20px; }
.kpi {
  background:var(--panel); border:1px solid var(--line); border-radius:10px;
  padding:14px 16px; display:flex; flex-direction:column; gap:3px;
}
.kpi .n { font-size:25px; font-weight:700; font-variant-numeric:tabular-nums; line-height:1.15; }
.kpi .l { font-size:10.5px; text-transform:uppercase; letter-spacing:.08em; color:var(--muted); font-weight:600; }
.kpi.accent { border-left:3px solid var(--accent); }

footer.appFoot {
  flex-shrink:0; background:linear-gradient(90deg,var(--panel),var(--panelDeep));
  border-top:1px solid var(--line); padding:11px 20px;
  display:flex; flex-wrap:wrap; gap:6px 18px; align-items:center; justify-content:space-between;
  font-size:11.5px; color:var(--muted);
}
footer.appFoot .fbrand { display:flex; align-items:center; gap:9px; }
footer.appFoot img { height:16px; width:auto; opacity:.9; }

.sideBox {
  background:var(--panel); border:1px solid var(--line); border-radius:10px;
  padding:13px 15px; margin-bottom:14px;
}
.sideBox h3 {
  margin:0 0 9px; font-size:10.5px; text-transform:uppercase;
  letter-spacing:.08em; color:var(--muted); font-weight:600;
}
.sideBox ul { list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:6px; font-size:13px; }
.withSide { display:grid; grid-template-columns:1fr 250px; gap:20px; align-items:start; }

@media (max-width:1000px) {
  .withSide { grid-template-columns:1fr; }
}
@media (max-width:760px) {
  #sidebar { position:fixed; z-index:60; height:100%; box-shadow:var(--shadow); }
  #appShell.collapsed #sidebar { width:0; border:none; }
  main.content { padding:16px 14px 40px; }
  .topSearch { min-width:0; width:130px; }
}
@media (prefers-reduced-motion:reduce) {
  * { transition:none !important; animation:none !important; }
}

/* ---- theme switch in the topbar ---- */
.themeBtn {
  background:var(--panel2); border:1px solid var(--line); color:var(--muted);
  border-radius:8px; padding:7px; cursor:pointer; display:flex; align-items:center;
}
.themeBtn:hover { color:var(--accent); border-color:var(--accent); }
.themeBtn svg { width:17px; height:17px; display:block; }

/* ---- administration ---- */
.adminTile {
  display:block; padding:18px 20px; text-decoration:none; color:inherit;
  transition:border-color .12s;
}
.adminTile:hover { border-color:var(--accent); text-decoration:none; }
.adminTile h2 { margin:0 0 6px; font-size:15px; font-weight:650; color:var(--ink); }
.adminTile p { margin:0; font-size:12.5px; color:var(--muted); line-height:1.6; }
.permGrid { display:grid; grid-template-columns:repeat(auto-fit,minmax(230px,1fr)); gap:10px 18px; }

/* ---- saved query pills ---- */
.qpWrap { display:inline-flex; align-items:center; }
.qp { display:inline-flex; align-items:center; gap:6px; }
.qpShared { color:var(--ok); font-size:8px; }
.qpDel {
  background:none; border:none; color:var(--muted); cursor:pointer;
  font-size:15px; line-height:1; padding:2px 6px; border-radius:6px; margin-left:-4px;
}
.qpDel:hover { color:var(--err); background:var(--panel2); }

/* ---- search hits ---- */
.hitRow { padding:12px 16px; border-bottom:1px solid var(--lineSoft); }
.hitRow:last-child { border-bottom:none; }
.hitRow:hover { background:var(--rowHover); }
.hitHead { display:flex; align-items:center; gap:9px; flex-wrap:wrap; margin-bottom:5px; }
.hitBody { font-size:13px; color:var(--inkDim); line-height:1.6; }
.hitMeta { font-size:11.5px; color:var(--muted); margin-top:5px; }

/* =============================== gantt ============================== */

.ganttWrap {
  display:flex; border:1px solid var(--line); border-radius:10px;
  background:var(--panel); overflow:hidden; margin-bottom:14px;
}
.ganttLabels {
  width:340px; flex-shrink:0; border-right:1px solid var(--line);
  background:var(--panel); overflow:hidden;
}
.ganttChart { flex:1; overflow-x:auto; overflow-y:hidden; position:relative; }

.ganttHead {
  height:34px; border-bottom:1px solid var(--line); background:var(--panel2);
  position:relative; flex-shrink:0;
}
.gTick {
  position:absolute; top:0; height:34px; border-left:1px solid var(--line);
  display:flex; align-items:center; padding-left:7px;
  font-size:11px; color:var(--muted); white-space:nowrap; overflow:hidden;
}
.gTick.major { border-left-color:var(--muted); }
.gTick.major span { color:var(--ink); font-weight:600; }

.ganttRow {
  height:28px; display:flex; align-items:center; gap:8px;
  border-bottom:1px solid var(--lineSoft); padding-right:10px; overflow:hidden;
}
.ganttRow.g-project { background:var(--panel2); }
.ganttRow.g-project .gLabel { font-weight:700; font-size:13px; }
.ganttRow.g-version .gLabel { font-weight:600; color:var(--inkDim); }
.ganttRow.g-closed .gLabel { opacity:.6; text-decoration:line-through; }
.gLabel {
  font-size:12.5px; color:var(--ink); white-space:nowrap;
  overflow:hidden; text-overflow:ellipsis; text-decoration:none; flex:1; min-width:0;
}
a.gLabel:hover { color:var(--accent); }
.gSub { font-size:10.5px; color:var(--muted); white-space:nowrap; flex-shrink:0; }

.ganttBody { position:relative; }
.gGrid { position:absolute; top:0; bottom:0; width:1px; background:var(--lineSoft); }
.gToday { position:absolute; top:0; bottom:0; width:2px; background:var(--err); opacity:.75; z-index:3; }
.gArrows { position:absolute; top:0; left:0; z-index:2; color:var(--muted); opacity:.8; pointer-events:none; }

.gBar {
  position:absolute; height:16px; border-radius:4px; overflow:hidden;
  background:var(--panel2); border:1px solid var(--line); z-index:1;
}
.gFill { display:block; height:100%; background:var(--net); opacity:.85; }
.gb-project { background:color-mix(in srgb,var(--accent) 22%,transparent); border-color:var(--accent); height:12px; }
.gb-project .gFill { background:var(--accent); }
.gb-version { background:color-mix(in srgb,var(--viol) 20%,transparent); border-color:var(--viol); height:14px; }
.gb-version .gFill { background:var(--viol); }
.gb-issue .gFill { background:var(--net); }
.gb-closed .gFill { background:var(--ok); }
.gb-late { border-color:var(--err); }
.gb-late .gFill { background:var(--err); }

.ganttKey {
  display:flex; gap:16px; flex-wrap:wrap; font-size:11.5px; color:var(--muted);
  align-items:center; padding:0 2px 8px;
}
.ganttKey span { display:inline-flex; align-items:center; gap:6px; }
.ganttKey i.k {
  width:20px; height:9px; border-radius:3px; display:inline-block;
  background:var(--panel2); border:1px solid var(--line);
}
.ganttKey i.gb-project { background:var(--accent); border-color:var(--accent); }
.ganttKey i.gb-version { background:var(--viol); border-color:var(--viol); }
.ganttKey i.gb-issue   { background:var(--net); border-color:var(--net); }
.ganttKey i.gb-late    { background:var(--err); border-color:var(--err); }
.ganttKey i.gb-closed  { background:var(--ok); border-color:var(--ok); }
.ganttKey i.kToday     { width:3px; background:var(--err); border-color:var(--err); }

@media print {
  #sidebar, header.topbar, footer.appFoot, .pageHead .btn, .pageHead form { display:none; }
  .ganttChart { overflow:visible; }
  .ganttWrap { border-color:#999; }
}

/* ============================== calendar ============================ */

.cal {
  border:1px solid var(--line); border-radius:10px; overflow:hidden;
  background:var(--panel); margin-bottom:14px;
}
.calHead { display:grid; grid-template-columns:repeat(7,1fr); background:var(--panel2); }
.calDayName {
  padding:9px 10px; font-size:10.5px; font-weight:600; letter-spacing:.08em;
  text-transform:uppercase; color:var(--muted); border-left:1px solid var(--line);
  border-bottom:1px solid var(--line);
}
.calDayName:first-child { border-left:none; }

.calWeek { display:grid; grid-template-columns:repeat(7,1fr); }
.calCell {
  min-height:112px; border-left:1px solid var(--lineSoft);
  border-top:1px solid var(--lineSoft); padding:6px 6px 8px;
  display:flex; flex-direction:column; gap:4px; overflow:hidden;
}
.calCell:first-child { border-left:none; }
.calCell.outside { background:var(--panelDeep); }
.calCell.outside .calDate { opacity:.4; }
.calCell.weekend:not(.outside) { background:color-mix(in srgb,var(--muted) 5%,transparent); }
.calCell.today { background:color-mix(in srgb,var(--accent) 9%,transparent); }

.calDate { font-size:12px; font-weight:600; color:var(--muted); padding:1px 2px; }
.calCell.today .calDate {
  color:#fff; background:var(--accent); border-radius:50%;
  width:21px; height:21px; display:flex; align-items:center; justify-content:center;
  font-size:11.5px;
}

.calItems { display:flex; flex-direction:column; gap:3px; min-width:0; }
.calItem {
  display:flex; align-items:center; gap:5px; min-width:0;
  font-size:11.5px; padding:2px 5px; border-radius:5px;
  background:var(--panel2); border:1px solid var(--lineSoft);
  color:var(--inkDim); text-decoration:none;
}
.calItem:hover { border-color:var(--accent); color:var(--ink); text-decoration:none; }
.ciText { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.ciMark { width:6px; height:6px; border-radius:50%; flex-shrink:0; background:var(--muted); }

.ci-start   .ciMark { background:var(--net); }
.ci-due     .ciMark { background:var(--warn); }
.ci-both    .ciMark { background:var(--viol); }
.ci-version .ciMark { background:var(--accent); border-radius:2px; width:7px; height:7px; }
.ci-version { font-weight:600; }
.ci-overdue .ciMark { background:var(--err); }
.ci-overdue { border-color:color-mix(in srgb,var(--err) 40%,transparent); }
.ci-closed .ciText { text-decoration:line-through; opacity:.6; }
.ci-closed .ciMark { background:var(--ok); }

.calMore { font-size:10.5px; color:var(--muted); padding:1px 6px; }

.ganttKey i.ck-start   { background:var(--net); border-color:var(--net); }
.ganttKey i.ck-due     { background:var(--warn); border-color:var(--warn); }
.ganttKey i.ck-both    { background:var(--viol); border-color:var(--viol); }
.ganttKey i.ck-version { background:var(--accent); border-color:var(--accent); }
.ganttKey i.ck-overdue { background:var(--err); border-color:var(--err); }
.ganttKey i.ck-closed  { background:var(--ok); border-color:var(--ok); }

@media (max-width:900px) {
  .calCell { min-height:88px; }
  .ciText { font-size:10.5px; }
}
@media print {
  .cal { border-color:#999; }
  .calCell { min-height:96px; }
}

/* ============================= attachments ========================== */

.fileInput {
  background:var(--panel2); border:1px dashed var(--line); color:var(--muted);
  border-radius:8px; padding:9px 11px; font-size:12.5px; width:100%; cursor:pointer;
}
.fileInput:hover { border-color:var(--accent); color:var(--ink); }
.fileInput::file-selector-button {
  background:var(--panel); border:1px solid var(--line); color:var(--ink);
  border-radius:6px; padding:5px 11px; font-size:12px; margin-right:11px;
  cursor:pointer; font-family:inherit;
}
.fileInput::file-selector-button:hover { border-color:var(--accent); color:var(--accent); }

.attList { display:flex; flex-direction:column; }
.att {
  display:flex; align-items:center; gap:13px; padding:11px 16px;
  border-bottom:1px solid var(--lineSoft);
}
.att:last-child { border-bottom:none; }
.att:hover { background:var(--rowHover); }

.attThumb {
  width:52px; height:40px; flex-shrink:0; border-radius:6px; overflow:hidden;
  border:1px solid var(--line); background:var(--panel2); display:block;
}
.attThumb img { width:100%; height:100%; object-fit:cover; display:block; }
.attIcon {
  width:52px; height:40px; flex-shrink:0; border-radius:6px;
  border:1px solid var(--line); background:var(--panel2); color:var(--muted);
  display:flex; align-items:center; justify-content:center;
}
.attIcon svg { width:20px; height:20px; }

.attMeta { flex:1; min-width:0; display:flex; flex-direction:column; gap:2px; }
.attName {
  font-size:13px; font-weight:600; color:var(--ink);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.attName:hover { color:var(--accent); }
.attSub { font-size:11.5px; color:var(--muted); }
.attActions { display:flex; gap:7px; flex-shrink:0; align-items:center; }

@media (max-width:640px) {
  .att { flex-wrap:wrap; }
  .attActions { width:100%; justify-content:flex-end; }
}

/* ============================ notifications ========================= */

.smsPreview {
  background:var(--panel2); border:1px solid var(--line); border-radius:12px;
  padding:13px 16px; font-size:13.5px; line-height:1.55; color:var(--ink);
  max-width:340px; position:relative;
}
.smsCount {
  display:block; margin-top:9px; padding-top:8px; border-top:1px solid var(--line);
  font-size:11px; color:var(--muted);
}

/* ---- workflow grid ---- */
table.wfGrid th { text-align:center; }
table.wfGrid th:first-child { text-align:left; }
table.wfGrid td { padding:7px 10px; }
table.wfGrid input[type=checkbox] { width:16px; height:16px; }

/* ---------------------------------------------------- product tree */
/* The expander sits in the same column as the name, so a leaf reserves the
   same width rather than letting its name slide left of its siblings'. */
.treeToggle {
    width: 20px;
    height: 20px;
    margin-right: 6px;
    padding: 0;
    line-height: 1;
    font-size: 14px;
    font-weight: 700;
    color: var(--muted);
    background: color-mix(in srgb, var(--fg) 6%, transparent);
    border: 1px solid var(--line);
    border-radius: 4px;
    cursor: pointer;
    vertical-align: middle;
}
.treeToggle:hover {
    color: var(--fg);
    border-color: var(--accent);
}
.treeSpacer {
    display: inline-block;
    width: 26px;
}

/* A multi-select is a list, not a one-line control: give it room and keep the
   indentation of the product tree readable inside it. */
select[multiple] {
    width: 100%;
    padding: 6px;
    font-family: inherit;
    white-space: pre;
}

/* A four-digit code is read back a digit at a time, so it is set wide and
   spaced rather than as ordinary prose. */
.otpInput {
  font-size:26px; letter-spacing:.5em; text-align:center;
  font-family:ui-monospace,Menlo,Consolas,monospace; padding:10px 0 10px .5em;
}

/* The role somebody holds now, beside the list of roles they could hold. A
   marked option in a scrolling multi-select is not readable as an answer. */
.roleChip {
    background: color-mix(in srgb, var(--accent) 16%, transparent);
    color: var(--accent);
    margin: 0 4px 4px 0;
}
/* Where the browser honours it, the currently held roles stand out in the list
   as well. Chromium and Firefox do; Safari ignores it, which is why the column
   above exists rather than this being the whole answer. */
select[multiple] option:checked {
    background: color-mix(in srgb, var(--accent) 28%, var(--panel2));
    color: var(--ink);
    font-weight: 600;
}

/* ------------------------------------------------------------------ dashboard
   Bars rather than a chart library. Every value here is a count on one axis, so
   a length is the whole of what a chart would say, and a length made of two
   divs reads correctly in both themes, prints, scales with the font, and
   survives having no JavaScript. */

.dashFilters {
  display:flex; flex-wrap:wrap; align-items:flex-end; gap:14px; padding:14px 16px;
}
.dashFilter { display:flex; flex-direction:column; gap:5px; min-width:190px; flex:1 1 190px; }
.dashFilter label {
  font-size:10.5px; text-transform:uppercase; letter-spacing:.08em;
  color:var(--muted); font-weight:600;
}
.dashFilterActions { display:flex; gap:8px; align-items:center; }

/* Two columns where there is room, one where there is not. The assignee chart
   spans both: it is the longest list and the one whose names wrap worst. */
.dashGrid { display:grid; grid-template-columns:repeat(auto-fit,minmax(340px,1fr)); gap:18px; }
.dashGrid > .card { margin-bottom:0; }
.dashWide { grid-column:1 / -1; }

/* The whole set in one bar, above the breakdown. */
.dashSplit {
  display:flex; height:10px; margin:16px 16px 10px; border-radius:999px;
  overflow:hidden; background:var(--panelDeep); border:1px solid var(--line);
}
.dashSplit .seg { display:block; height:100%; }
.dashSplit .seg.live { background:var(--accent); }
.dashSplit .seg.done { background:var(--ok); }

.dashLegend {
  display:flex; gap:18px; padding:0 16px 14px; font-size:12px; color:var(--muted);
  border-bottom:1px solid var(--lineSoft);
}
.dashLegend b { color:var(--ink); font-variant-numeric:tabular-nums; margin-left:4px; }
.dashLegend .sw {
  display:inline-block; width:9px; height:9px; border-radius:2px; margin-right:6px;
}
.dashLegend .sw.live { background:var(--accent); }
.dashLegend .sw.done { background:var(--ok); }

.dashBars { list-style:none; margin:0; padding:8px 8px 12px; }

/* The whole row is the link, not just the label: a target the width of the
   card is one people can hit, and the bar is the thing they are looking at
   when they decide to click. */
.dashBar {
  display:grid; grid-template-columns:minmax(96px,150px) 1fr 52px;
  align-items:center; gap:12px; padding:6px 8px; border-radius:7px;
  color:var(--ink); text-decoration:none; border:1px solid transparent;
}
.dashBar:hover { background:var(--rowHover); text-decoration:none; }
.dashBar:focus-visible { outline:2px solid var(--accent); outline-offset:1px; }
.dashBar.on { border-color:var(--accent); background:var(--rowHover); }

.dashBar .lbl {
  font-size:12.5px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.dashBar.on .lbl { font-weight:650; }
.dashBar .track {
  display:flex; height:14px; border-radius:4px; overflow:hidden;
  background:var(--panelDeep); box-shadow:inset 0 0 0 1px var(--lineSoft);
}
.dashBar .fill { display:block; height:100%; min-width:0; }
.dashBar .fill.live { background:var(--accent); }
.dashBar .fill.done { background:var(--ok); }
.dashBar .fill.none { background:var(--muted); }
.dashBar .val {
  font-size:12.5px; font-weight:650; text-align:right;
  font-variant-numeric:tabular-nums; color:var(--inkDim);
}

.dashNote { margin-top:14px; }

@media (max-width: 560px) {
  /* The label column stops earning its width before the bar does. */
  .dashBar { grid-template-columns:minmax(72px,110px) 1fr 44px; gap:8px; }
}

/* A nested nav item. Indented and slightly quieter, so Dashboard reads as
   part of My page rather than as a seventh thing at the same level.
   The indent is dropped when the sidebar collapses to icons, where there is
   no room for it and nothing left to indent under. */
.sbItem.sbSub { padding-left:30px; font-size:12.5px; color:var(--inkDim); }
.sbItem.sbSub .sbIco { width:15px; height:15px; }
#appShell.collapsed .sbItem.sbSub { padding-left:0; }

/* Forms inside a side box. The column is 250px wide, so fields stack and the
   controls fill it rather than sitting at their natural width and leaving a
   ragged edge. */
.sideBox form { display:flex; flex-direction:column; gap:9px; }
.sideBox .field { display:flex; flex-direction:column; gap:4px; }
.sideBox .field label {
  font-size:10.5px; text-transform:uppercase; letter-spacing:.06em;
  color:var(--muted); font-weight:600;
}
.sideBox select, .sideBox textarea { width:100%; }
.sideBox textarea { min-height:52px; resize:vertical; }
.sideBox .btn { align-self:flex-start; }

/* Pagers inside a card sit against its edges rather than the page's, and the
   dead arrow at either end stays put instead of the row jumping when it goes.
   Drawn as a disabled-looking button, not removed: a control that vanishes at
   the end of a list moves everything beside it. */
.card .pager { padding:12px 16px; border-top:1px solid var(--lineSoft); }
.card .pager .hint { margin:0 4px; }
.pager [aria-disabled="true"] { opacity:.4; cursor:default; }
