/* =====================================================================
   SHASHVAT ONE — shared stylesheet
   =====================================================================
   Every colour in the application comes from a variable defined below.
   A theme is nothing more than a different set of those values, so adding
   one means adding a block here and a line to THEMES in app.js — no other
   file changes.

   The active theme is written to <html data-theme="..."> by boot.js before
   anything renders, so switching never flashes the wrong colours.
   ===================================================================== */

/* ---------------- LIGHT (default) ---------------- */
:root,
[data-theme="light"]{
  --side:#101c34; --side-2:#18294a; --side-3:#22375e;   /* sidebar, hero */
  --amber:#f0a02a; --amber-soft:#fdf3e3;
  --ink:#131a24; --muted:#697588; --faint:#9aa5b5;
  --line:#e4e8ee; --bg:#f4f6f9; --card:#fff;
  --panel:#f7f9fb;                                       /* toolbars */
  --input-bg:#fff; --input-line:#e4e8ee;
  --ok:#12794a; --ok-soft:#e6f5ed;
  --red:#a8232a; --red-soft:#fdecec;
  --warn:#8a5a00; --warn-soft:#fdf4e2;
  --blue:#1b5fa8; --blue-soft:#e9f1fb; --blue-line:#cddff2;
  /* The action accent. Was used in four places and DEFINED IN NONE — the
     party window's active tab underline, the role-toggle highlight, the
     Reference Lists active entry and the editing-cell ring were all
     silently invisible (found by the static audit, 28 July 2026). Rooted
     to --blue once, here in :root: var() resolves at use, so each theme's
     own --blue carries it — no per-theme copy to forget. */
  --accent:var(--blue);
  --purple:#6b3fa0; --teal:#0f7a86;
  --ghost-ink:#101c34; --ghost-line:#101c34; --danger-line:#e8b9bb;
  --accent-ink:#fff;      /* on --accent. Light theme: accent is dark blue. */
  --shadow:0 1px 2px rgba(16,28,52,.05);
  --shadow-lg:0 24px 60px rgba(0,0,0,.3);
  /* grid */
  --grid-head:#e7ecf3; --grid-head-ink:#3d4a5c; --grid-head-hi:rgba(255,255,255,.65);
  --grid-row-line:#dfe4ec;     /* between rows */
  --grid-col-line:#dde3eb;     /* between columns */
  --grid-odd:#eef2f7; --grid-hover:#dfeafb;
  --r:12px;
  color-scheme:light;
}

/* ---------------- CLASSIC ----------------
   Prejit, 28 July 2026: a royal-blue theme called Classic.

   Royal blue carries the chrome — sidebar, accents, grid headings — with an
   antique gold as the action colour rather than the orange amber the other
   light themes use, because gold beside royal blue is the pairing the name is
   asking for and orange fights it.

   Every colour here was MEASURED, not chosen by eye: the pairs the project has
   been bitten by before (ghost button, alerts, the filled chip, muted text,
   grid heading ink) are all checked at WCAG AA or better. --blue is kept dark
   enough that white ink sits on it, so --accent-ink stays #fff.
   ------------------------------------------------------------------------ */
[data-theme="classic"]{
  --side:#16307a; --side-2:#1e3f96; --side-3:#2a51b0;   /* sidebar, hero */
  --amber:#daa520; --amber-soft:#fbf3df;                /* antique gold */
  --ink:#14203a; --muted:#57647f; --faint:#8391ac;
  --line:#dbe2f0; --bg:#f2f5fb; --card:#fff;
  --panel:#f6f8fd;                                       /* toolbars */
  --input-bg:#fff; --input-line:#dbe2f0;
  --ok:#10714a; --ok-soft:#e4f4ec;
  --red:#a02028; --red-soft:#fceceb;
  --warn:#845400; --warn-soft:#fdf3de;
  --blue:#23459e; --blue-soft:#e8edfb; --blue-line:#c6d3f2;
  --purple:#5a3fa0; --teal:#0f6f86;
  --ghost-ink:#16307a; --ghost-line:#16307a; --danger-line:#e6b6b8;
  --accent-ink:#fff;      /* --blue is dark royal, so white ink sits on it */
  --shadow:0 1px 2px rgba(22,48,122,.08);
  --shadow-lg:0 24px 60px rgba(10,24,60,.32);
  /* grid */
  --grid-head:#e3eaf8; --grid-head-ink:#33405c; --grid-head-hi:rgba(255,255,255,.7);
  --grid-row-line:#dae1f0;     /* between rows */
  --grid-col-line:#d8e0f0;     /* between columns */
  --grid-odd:#edf1fa; --grid-hover:#d9e4fb;
  color-scheme:light;
}

/* ---------------- DARK ---------------- */
[data-theme="dark"]{
  --side:#0b1017; --side-2:#151d2a; --side-3:#1d2937;
  --amber:#f2ac45; --amber-soft:#2c2415;
  --ink:#e6ebf2; --muted:#96a2b4; --faint:#6c7889;
  --line:#28323f; --bg:#0f141c; --card:#161d27;
  --panel:#1b2330;
  --input-bg:#111823; --input-line:#2c3644;
  --ok:#4ec98a; --ok-soft:#14291f;
  --red:#ef7078; --red-soft:#301a1d;
  --warn:#e3ad52; --warn-soft:#2e2616;
  --blue:#63a4de; --blue-soft:#16283b; --blue-line:#27455f;
  --purple:#a888e0; --teal:#3fb6bf;
  --ghost-ink:#e6ebf2; --ghost-line:#3a4757; --danger-line:#5d2f34;
  --accent-ink:#0b1017;   /* dark theme: accent is a LIGHT blue, so dark ink */
  --shadow:0 1px 2px rgba(0,0,0,.4);
  --shadow-lg:0 24px 60px rgba(0,0,0,.6);
  --grid-head:#2c3a4f; --grid-head-ink:#cfdcec; --grid-head-hi:rgba(255,255,255,.09);
  --grid-row-line:#2c3746;
  --grid-col-line:#2c3746;
  --grid-odd:#1c2531; --grid-hover:#22344a;
  color-scheme:dark;
}

/* ---------------- MIDNIGHT — near black, for dim rooms ---------------- */
[data-theme="midnight"]{
  --side:#000; --side-2:#0a0d12; --side-3:#131922;
  --amber:#ffb347; --amber-soft:#2a2110;
  --ink:#eef2f7; --muted:#8d99aa; --faint:#5f6b7c;
  --line:#1d232c; --bg:#000205; --card:#0b0e14;
  --panel:#11151d;
  --input-bg:#080b10; --input-line:#232a35;
  --ok:#5ad79a; --ok-soft:#0d2318;
  --red:#ff7a82; --red-soft:#2a1216;
  --warn:#efb75c; --warn-soft:#2a2210;
  --blue:#71b0ea; --blue-soft:#0e2033; --blue-line:#22415c;
  --purple:#b394ee; --teal:#46c3cc;
  --ghost-ink:#eef2f7; --ghost-line:#333d4b; --danger-line:#5f2b32;
  --accent-ink:#000205;   /* midnight: same reason */
  --shadow:0 1px 2px rgba(0,0,0,.6);
  --shadow-lg:0 24px 60px rgba(0,0,0,.8);
  --grid-head:#1e2836; --grid-head-ink:#c8d6e6; --grid-head-hi:rgba(255,255,255,.07);
  --grid-row-line:#232a35;
  --grid-col-line:#232a35;
  --grid-odd:#12171f; --grid-hover:#182a3d;
  color-scheme:dark;
}

/* ---------------- SEPIA — warm, easier over a long shift ---------------- */
[data-theme="sepia"]{
  --side:#3a3226; --side-2:#4a4033; --side-3:#5c5142;
  --amber:#b57a1e; --amber-soft:#f6ecd8;
  --ink:#2f2718; --muted:#7a6d59; --faint:#a2937c;
  --line:#e0d5c2; --bg:#f4eee2; --card:#fdfaf3;
  --panel:#f7f1e5;
  --input-bg:#fffdf8; --input-line:#e0d5c2;
  --ok:#3d6b3f; --ok-soft:#e7f0e2;
  --red:#95322c; --red-soft:#f8e6e1;
  --warn:#8a5a00; --warn-soft:#f8eeda;
  --blue:#2c5f8a; --blue-soft:#e6eff6; --blue-line:#c9dcea;
  --purple:#6d4a86; --teal:#1f6f70;
  --ghost-ink:#3a3226; --ghost-line:#3a3226; --danger-line:#dcbab3;
  --accent-ink:#fff;
  --shadow:0 1px 2px rgba(74,64,51,.08);
  --shadow-lg:0 24px 60px rgba(58,50,38,.35);
  --grid-head:#e8dcc4; --grid-head-ink:#5c4f3a; --grid-head-hi:rgba(255,255,255,.6);
  --grid-row-line:#ddd0b9;
  --grid-col-line:#ddd0b9;
  --grid-odd:#eee5d3; --grid-hover:#e9dcc2;
  color-scheme:light;
}

/* ---------------- HIGH CONTRAST — maximum legibility ---------------- */
[data-theme="contrast"]{
  --side:#000; --side-2:#111; --side-3:#1c1c1c;
  --amber:#ffc000; --amber-soft:#332800;
  --ink:#000; --muted:#333; --faint:#555;
  --line:#000; --bg:#fff; --card:#fff;
  --panel:#f0f0f0;
  --input-bg:#fff; --input-line:#000;
  --ok:#005c2e; --ok-soft:#d8f0e3;
  --red:#8c0009; --red-soft:#ffe0e1;
  --warn:#6b4400; --warn-soft:#fff0d0;
  --blue:#00408f; --blue-soft:#dde8fa; --blue-line:#00408f;
  --purple:#4a1d80; --teal:#00575c;
  --ghost-ink:#000; --ghost-line:#000; --danger-line:#8c0009;
  --accent-ink:#fff;
  --shadow:none; --shadow-lg:0 10px 30px rgba(0,0,0,.5);
  --grid-head:#d9d9d9; --grid-head-ink:#000; --grid-head-hi:transparent;
  --grid-row-line:#000;
  --grid-col-line:#000;
  --grid-odd:#e6e6e6; --grid-hover:#ffe08a;
  --r:6px;
  color-scheme:light;
}
[data-theme="contrast"] .card,
[data-theme="contrast"] .gridbox,
[data-theme="contrast"] .stat{border-width:2px}

*{box-sizing:border-box}
html,body{margin:0;padding:0;height:100%}
/* One number sizes the whole application. */
html{font-size:17.5px}
body{
  font:1rem/1.55 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  background:var(--bg); color:var(--ink); -webkit-text-size-adjust:100%;
}
[x-cloak]{display:none!important}
h1,h2,h3,h4{margin:0 0 .4rem;line-height:1.25}
h1{font-size:1.3rem} h2{font-size:1.05rem} h3{font-size:.92rem} h4{font-size:.8rem}
p{margin:.3rem 0}
a{color:var(--blue)}
svg{flex:none}

/* ================= LOGIN ================= */
#login{min-height:100%;display:flex;align-items:center;justify-content:center;padding:1.5rem;
  background:linear-gradient(160deg,var(--side) 0%,var(--side-3) 100%)}
#login .box{background:var(--card);border-radius:16px;padding:2rem 1.6rem;width:100%;max-width:370px;
  box-shadow:var(--shadow-lg)}
#login .mark{width:46px;height:46px;border-radius:11px;background:var(--side);display:flex;
  align-items:center;justify-content:center;margin:0 auto .9rem;color:var(--amber);
  font-weight:700;font-size:1.2rem}
#login h1{text-align:center;font-size:1.25rem;margin-bottom:.15rem}
#login .sub{text-align:center;color:var(--muted);font-size:.78rem;margin-bottom:1.5rem}
#login .field{margin-bottom:.75rem}
#login button{width:100%;margin-top:.6rem}

/* Show-password toggle (31 July 2026). The eye sits INSIDE the password
   box at its right edge; the input gains right padding so typed characters
   never run under the icon. currentColor drives the icon, so it follows
   the theme's own text colours — nothing hardcoded (the colour rule).
   The #login .pweye line exists because `#login button` above sets every
   button in the login card to full width; the ID selector outweighs a
   class, so the eye must be excepted at the same strength. */
.pwbox{position:relative}
.pwbox input{padding-right:2.4rem}
.pweye{position:absolute;top:0;right:0;height:100%;display:flex;align-items:center;
  justify-content:center;background:none;border:0;color:var(--muted);cursor:pointer;
  border-radius:0 8px 8px 0}
#login .pweye{width:2.2rem;margin-top:0}
.pweye:hover{color:var(--ink)}
.pweye:focus-visible{outline:2px solid var(--blue-soft)}
.pweye svg{width:18px;height:18px}

/* ================= SHELL ================= */
.shell{display:flex;min-height:100%}
aside{width:236px;flex:none;background:var(--side);color:#fff;display:flex;flex-direction:column;
  position:fixed;inset:0 auto 0 0;z-index:40;transform:translateX(-100%);transition:transform .22s ease}
aside.open{transform:none}
@media(min-width:940px){ aside{position:sticky;top:0;height:100vh;transform:none} }

.brandbar{padding:1.1rem 1rem;border-bottom:1px solid rgba(255,255,255,.09);
  display:flex;gap:.6rem;align-items:center}
.brandbar .mark{width:36px;height:36px;border-radius:9px;background:var(--amber);color:var(--side);
  display:flex;align-items:center;justify-content:center;font-weight:800;font-size:.95rem;flex:none}
.brandbar .n1{font-weight:600;font-size:.92rem}
.brandbar .n2{font-size:.62rem;color:var(--amber);letter-spacing:.14em;font-weight:600}
/* The running build's date (31 July 2026) — quiet support detail, not
   branding. Hidden with the rest of .txt when the sidebar is mini. */
.brandbar .n3{font-size:.6rem;color:rgba(255,255,255,.38);margin-top:.15rem;
  white-space:nowrap}

.navwrap{flex:1;overflow-y:auto;overflow-x:hidden;padding:.7rem 0 1.2rem}
.navlabel{font-size:.6rem;letter-spacing:.16em;color:rgba(255,255,255,.36);
  padding:.9rem 1rem .35rem;font-weight:700;white-space:nowrap}
nav a{width:100%;display:flex;align-items:center;gap:.7rem;color:rgba(255,255,255,.78);
  padding:.42rem .8rem;font-size:.86rem;text-decoration:none;border-left:3px solid transparent}
nav a:hover{background:rgba(255,255,255,.06);color:#fff}
nav a.on{background:var(--side-2);color:#fff;border-left-color:var(--amber);font-weight:600}
/* Pale chip: white laid over the module colour. The sidebar is dark in every
   theme, and most emoji are dark glyphs, so a tinted chip leaves them
   invisible — 👥 and 💱 worst of all. This keeps the colour coding and the
   contrast at the same time. */
nav a .ic{width:30px;height:30px;border-radius:9px;flex:none;font-size:16px;line-height:1;
  display:flex;align-items:center;justify-content:center;
  background:linear-gradient(0deg,rgba(255,255,255,.84),rgba(255,255,255,.84)),var(--c);
  box-shadow:inset 0 0 0 1px rgba(0,0,0,.06);
  transition:background .15s,box-shadow .15s}
nav a:hover .ic{background:linear-gradient(0deg,rgba(255,255,255,.92),rgba(255,255,255,.92)),var(--c)}
nav a.on .ic{
  background:linear-gradient(0deg,rgba(255,255,255,.95),rgba(255,255,255,.95)),var(--c);
  box-shadow:0 0 0 2px rgba(255,255,255,.28), inset 0 0 0 1px rgba(0,0,0,.06)}
nav a .lb{white-space:nowrap;overflow:hidden}

@media(min-width:940px){
  aside.mini{width:70px}
  aside.mini .brandbar{padding:1.1rem .7rem;justify-content:center}
  aside.mini .brandbar .txt{display:none}
  aside.mini .navlabel{opacity:0;height:.9rem;padding:.5rem 0 0}
  aside.mini nav a{justify-content:center;padding:.42rem .5rem;gap:0}
  aside.mini nav a .lb{display:none}
}
/* .sidefoot is GONE (31 July 2026, Prejit). The signed-in name lived in
   small print at the foot of the sidebar while the avatar sat top right —
   the two halves of "who is signed in" in opposite corners. The name now
   sits beside the avatar in the top bar (.who, below) and the green dot
   moved onto the avatar's corner. git holds the old markup. */
.scrim{position:fixed;inset:0;background:rgba(10,16,28,.5);z-index:35;display:none}
.scrim.on{display:block}
@media(min-width:940px){ .scrim{display:none!important} }

.main{flex:1;min-width:0;display:flex;flex-direction:column}
.topbar{background:var(--card);border-bottom:1px solid var(--line);padding:.4rem .8rem;display:flex;
  align-items:center;gap:.6rem;position:sticky;top:0;z-index:30;flex-wrap:wrap}
.burger{background:var(--card);border:1px solid var(--line);border-radius:9px;padding:.42rem .5rem;
  cursor:pointer;display:flex;align-items:center;color:var(--side)}
.burger:hover{background:var(--blue-soft);border-color:var(--blue-line)}
.crumb{font-size:.82rem;color:var(--muted);margin-right:auto;font-weight:500}
.crumb b{color:var(--ink)}
.branchpick{display:flex;align-items:center;gap:.4rem;background:var(--blue-soft);
  border:1px solid var(--blue-line);border-radius:9px;padding:.28rem .5rem}
.branchpick svg{color:var(--blue)}
.branchpick select{border:0;background:none;font:inherit;font-size:.84rem;font-weight:600;
  color:var(--blue);cursor:pointer;padding:.15rem .1rem;max-width:180px}
.branchpick select:focus{outline:none}
/* Who is signed in — name and avatar together, top right (31 July 2026).
   The name is quiet weight so the branch picker stays the loudest thing in
   the bar, and it hides on narrow screens where the bar has no room; the
   avatar (with the green dot) remains, so small screens still show who. */
.who{display:flex;align-items:center;gap:.5rem;min-width:0}
.who .name{font-size:.8rem;font-weight:600;color:var(--ink);max-width:18ch;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
@media (max-width:720px){.who .name{display:none}}
.avatar{width:30px;height:30px;border-radius:50%;background:var(--side);color:#fff;display:flex;
  align-items:center;justify-content:center;font-size:.72rem;font-weight:700;flex:none;
  position:relative}
/* The green "signed in" dot, moved from the old sidebar footer. Ringed in
   the bar's own background so it reads on every theme. */
.avatar .dot{position:absolute;right:-2px;bottom:-2px;width:10px;height:10px;
  border-radius:50%;background:#3ddc84;border:2px solid var(--card)}
.content{padding:.6rem .75rem 2.2rem;width:100%} /* full-width: no max-width cap (2026-07-27);
   padding tightened 27 Jul 2026 - Prejit, twice: less dead space above the data */
@media(min-width:700px){ .content{padding:1.3rem 1.4rem 4rem} }

/* ================= HERO / STATS ================= */
.hero{background:linear-gradient(120deg,var(--side) 0%,var(--side-3) 100%);color:#fff;
  border-radius:16px;padding:1.5rem 1.3rem;margin-bottom:1.2rem;position:relative;overflow:hidden}
.hero::after{content:'';position:absolute;right:-70px;top:-70px;width:240px;height:240px;
  border-radius:50%;background:radial-gradient(circle,rgba(240,160,42,.24),transparent 68%)}
.hero .kicker{display:flex;align-items:center;gap:.5rem;font-size:.62rem;letter-spacing:.16em;
  color:var(--amber);font-weight:700;margin-bottom:.7rem}
.hero .kicker i{width:22px;height:2px;background:var(--amber);display:block}
.hero h1{font-size:1.55rem;font-weight:700}
.hero h1 span{color:var(--amber)}
.hero p{color:rgba(255,255,255,.76);font-size:.86rem;max-width:56ch;margin-top:.5rem}
.hero .tagline{display:inline-block;margin-top:1rem;background:rgba(255,255,255,.1);
  border:1px solid rgba(255,255,255,.16);border-radius:999px;padding:.35rem .8rem;font-size:.73rem}
.sectitle{display:flex;align-items:center;gap:.5rem;font-size:.63rem;letter-spacing:.15em;
  color:var(--muted);font-weight:700;margin:1.4rem 0 .7rem}
.sectitle i{width:18px;height:2px;background:var(--ok);display:block}
.sectitle .live{width:7px;height:7px;border-radius:50%;background:#25c168}
.stats{display:grid;grid-template-columns:repeat(2,1fr);gap:.65rem}
@media(min-width:640px){ .stats{grid-template-columns:repeat(3,1fr)} }
@media(min-width:960px){ .stats{grid-template-columns:repeat(6,1fr)} }
.stat{background:var(--card);border:1px solid var(--line);border-left:4px solid var(--blue);
  border-radius:11px;padding:.8rem .75rem}
.stat .n{font-size:1.5rem;font-weight:700;line-height:1;margin-top:.45rem}
.stat .l{font-size:.72rem;color:var(--muted);margin-top:.25rem}
.stat.b1{border-left-color:var(--blue)}   .stat.b2{border-left-color:var(--ok)}
.stat.b3{border-left-color:var(--amber)}  .stat.b4{border-left-color:var(--red)}
.stat.b5{border-left-color:var(--purple)} .stat.b6{border-left-color:var(--teal)}

/* ================= CARDS / FORMS ================= */
.card{background:var(--card);border:1px solid var(--line);border-radius:var(--r);box-shadow:var(--shadow);
  padding:.65rem .75rem;margin-bottom:.55rem}
.card-h{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap;margin-bottom:.45rem}
.card-h .t{font-weight:650;font-size:.92rem}
/* A card whose only job is to hold a grid does not need a paragraph of air
   under its heading. */
.card > .muted:first-of-type{margin:.15rem 0 .45rem}
.card-h .sp{margin-left:auto}
.code{font:700 .68rem/1 ui-monospace,SFMono-Regular,Menlo,monospace;background:var(--side);
  color:var(--amber);padding:.3rem .45rem;border-radius:5px;letter-spacing:.05em}
.grid{display:grid;grid-template-columns:1fr;gap:.65rem}
@media(min-width:620px){ .grid.two{grid-template-columns:1fr 1fr}
  .grid.three{grid-template-columns:repeat(3,1fr)} }
label{display:block;font-size:.71rem;color:var(--muted);margin-bottom:.22rem;font-weight:600}
input,select,textarea{width:100%;padding:.58rem .55rem;font:inherit;font-size:.88rem;
  max-width:100%}
/* A textarea's drag handle could stretch it OUT OF ITS CARD — the browser
   default is resize:both, and width has no cap on a grid child (Prejit,
   29 July, the party Note box). Vertical growth is the useful axis; sideways
   only ever breaks the layout. Applies to every textarea in the system. */
textarea{resize:vertical}
input,select,textarea{
  border:1px solid var(--line);border-radius:8px;background:var(--input-bg);color:var(--ink)}
input:focus,select:focus{outline:2px solid var(--blue-soft);border-color:var(--blue)}
input:disabled,select:disabled{background:var(--panel);color:var(--muted)}
/* The base rule above stretches EVERY input to full width with padding —
   right for text boxes, absurd for a tick or a radio, which became giant
   padded blocks (the Parties retail box, found 28 July after three failed
   layout fixes that restyled the row while the BOX was the problem). Sized
   here once; .check/.s1tick/.colpanel refine it later in the file. */
input[type="checkbox"],input[type="radio"]{width:17px;height:17px;padding:0;
  flex:none;accent-color:var(--blue)}
.check{display:flex;align-items:center;gap:.5rem;font-size:.84rem;padding:.32rem 0}
.check input{width:17px;height:17px;flex:none}
.check label{margin:0;font-size:.84rem;color:var(--ink);font-weight:400}
.btn{appearance:none;border:1px solid var(--side);background:var(--side);color:#fff;
  padding:.52rem .85rem;border-radius:8px;font:inherit;font-size:.83rem;font-weight:600;cursor:pointer}
.btn:hover{background:var(--side-2)}
.btn.amber{background:var(--amber);border-color:var(--amber);color:var(--side)}
/* Ghost and danger buttons sit ON a card, so their ink and border must come
   from the card's own scale, never from --side (the sidebar colour, which is
   near-black in every theme and therefore invisible on a dark card). */
.btn.ghost{background:var(--card);color:var(--ghost-ink);border-color:var(--ghost-line)}
.btn.ghost:hover{background:var(--panel)}
.btn.danger{background:var(--card);color:var(--red);border-color:var(--danger-line)}
.btn.danger:hover{background:var(--red-soft)}
.btn.sm{padding:.34rem .6rem;font-size:.76rem}
.btn:disabled{opacity:.45;cursor:not-allowed}
.acts{display:flex;gap:.4rem;flex-wrap:wrap;margin-top:.75rem}
.pill{display:inline-block;font-size:.67rem;padding:.2rem .45rem;border-radius:999px;font-weight:700}
.pill.on{background:var(--ok-soft);color:var(--ok)}
.pill.off{background:var(--red-soft);color:var(--red)}
.pill.w{background:var(--warn-soft);color:var(--warn)}
.pill.n{background:var(--panel);color:var(--muted)}
.muted{color:var(--muted);font-size:.79rem}
.preview{font:700 1.02rem/1 ui-monospace,SFMono-Regular,Menlo,monospace;background:var(--side);
  color:#6fe3a4;padding:.7rem .6rem;border-radius:9px;text-align:center;word-break:break-all}
/* A NEWER BUILD ON THE SERVER (31 July 2026). Bottom left, below the
   sign-out countdown in urgency and in z-order: z-index 60 floats over
   content and grids but under a window (.modal-bg is 80) — an update can
   wait; whatever the window is doing cannot. */
.updpop{position:fixed;left:.9rem;bottom:.9rem;z-index:60;display:flex;
  align-items:center;gap:.65rem;background:var(--card);color:var(--ink);
  border:1px solid var(--line);border-radius:12px;padding:.6rem .8rem;
  font-size:.82rem;box-shadow:0 10px 32px rgba(8,13,22,.35);
  max-width:min(420px,calc(100vw - 1.8rem))}
.updpop .x{border:0;background:transparent;color:var(--muted);cursor:pointer;
  font-size:1.05rem;line-height:1;padding:0 .1rem;font-family:inherit}
.updpop .x:hover{color:var(--ink)}

/* THE SIGN-OUT COUNTDOWN, PINNED TO THE WINDOW (31 July 2026, Prejit).
   The warning used to be painted at the top of the page content, so anyone
   scrolled to the foot of a long grid never saw it — the countdown ran
   off-screen and the sign-out looked like a crash. It is now fixed to the
   viewport: top centre, just below the top bar, wherever you are scrolled.
   z-index 95: above a window (.modal-bg is 80) because the timeout does not
   care what you have open, below a toast (100). It floats over the content
   rather than hiding it — the point is to let you save what you were doing. */
.idlefix{position:fixed;top:3.1rem;left:50%;transform:translateX(-50%);z-index:95;
  width:min(560px,calc(100vw - 1.2rem))}
.idlefix .alert{margin:0;box-shadow:0 10px 32px rgba(8,13,22,.35)}
.alert{border-radius:10px;padding:.7rem .8rem;font-size:.82rem;margin-bottom:.7rem;
  display:flex;gap:.6rem;align-items:flex-start}
/* Alerts held light-theme ink and borders as fixed values while their
   backgrounds were theme variables, so in dark and midnight they were dark
   text on a dark panel — and an alert is how a failed screen explains itself
   (rule 22). Ink now comes from the same variables the pills use, which are
   already tuned per theme against their -soft backgrounds. The second, softer
   border declaration is ignored by browsers too old for color-mix, which then
   simply keep the full-strength border above it. */
.alert.w{background:var(--warn-soft);border:1px solid var(--warn);color:var(--warn)}
.alert.r{background:var(--red-soft);border:1px solid var(--red);color:var(--red)}
.alert.i{background:var(--blue-soft);border:1px solid var(--blue);color:var(--blue)}
.alert.w{border-color:color-mix(in srgb,var(--warn) 38%,var(--card))}
.alert.r{border-color:color-mix(in srgb,var(--red)  38%,var(--card))}
.alert.i{border-color:var(--blue-line)}
.alert b{display:block;margin-bottom:.1rem}
.empty{text-align:center;padding:2.2rem 1rem;color:var(--muted);font-size:.85rem}
.loading{text-align:center;padding:3.5rem 1rem;color:var(--muted)}
.toast{position:fixed;left:50%;transform:translateX(-50%);bottom:1.1rem;max-width:92%;
  padding:.7rem .9rem;border-radius:9px;font-size:.84rem;z-index:100;
  box-shadow:0 8px 30px rgba(0,0,0,.2);font-weight:500}
.toast.ok{background:var(--ok);color:#fff}
.toast.err{background:var(--red);color:#fff}
/* Neither good news nor bad — "your typing is still here". Added 28 July
   2026 with S.win; without it that toast had no background at all and read
   as a rendering fault. Takes --blue like the alerts, so it follows every
   theme rather than carrying a colour of its own (rule 27). */
.toast.i{background:var(--blue);color:#fff}

/* THE ROW WHOSE CHILDREN ARE SHOWING.
   Third form (28 July 2026, all three the same day). The first was a heavy
   tint plus bold, which swallowed the separator lines Prejit wants kept.
   The second was a caret in the # column, which he found unreliable and
   disliked. This one highlights the whole row but keeps every separator:

   - a LIGHT wash, mixed from the theme's own blue into the card colour, so
     it reads as "current" without hiding the row line drawn beneath it —
     and it follows every theme rather than carrying a colour of its own;
   - its own bottom line in a stronger blue mix, so the separator under the
     highlighted row is MORE visible than an ordinary one, not less — the
     exact opposite of the first attempt's fault;
   - a 3px accent bar on the left, the same device the sidebar uses for the
     open module, so it already means "you are here" in this application;
   - no bold, no colour change on the text: the data is not different, only
     where you are. */
.s1grid .ag-row.s1-row-current{
  background:color-mix(in srgb, var(--blue) 18%, var(--card));
  border-bottom:1px solid color-mix(in srgb, var(--blue) 45%, var(--grid-row-line))}
/* The vertical bar, as its own element rather than an inset box-shadow.
   The shadow sat UNDER the first cell's own background and vanished on any
   row whose cells paint — which is why Prejit saw it "sometimes". A
   positioned child with a z-index sits above the cells unconditionally.
   The row itself is already positioned by AG Grid, so this anchors to it
   without touching the row's own `position` (see the warning above). */
.s1grid .ag-row.s1-row-current::before{
  content:'';position:absolute;left:0;top:0;bottom:0;width:4px;
  background:var(--blue);z-index:10;pointer-events:none}
.s1grid .ag-row.s1-row-current.ag-row-hover{
  background:color-mix(in srgb, var(--blue) 24%, var(--card)) !important}

/* Our own tick box (28 July 2026) — a native input, centred in its cell,
   sized to be hit with a finger on the shop floor. accent-color keeps it on
   theme without repainting the control by hand. The CELL is the click
   target, not just the box, so it advertises that with a pointer. */
.s1grid .s1tickcell{display:flex;align-items:center;justify-content:center;
  cursor:pointer}
.s1grid .s1tick{width:16px;height:16px;margin:0;cursor:pointer;
  accent-color:var(--blue)}
/* The select-all box, centred in its header cell. */
.s1grid .s1tickhead .ag-header-cell-comp-wrapper{justify-content:center}

/* A BOOLEAN CELL STAYS CENTRED WHILE BEING EDITED. Clicking Active swapped
   the renderer for AG Grid's checkbox editor, whose wrapper is left-aligned
   by default — so the tick jumped left on click and back on blur, which
   reads as the column moving (Prejit, 28 July 2026). The editor is centred
   like the display and the jump is gone. */
.s1grid .ag-cell-inline-editing .ag-cell-edit-wrapper,
.s1grid .ag-cell-inline-editing .ag-checkbox-edit{justify-content:center}

/* =====================================================================
   GRID — compact chrome.
   The toolbar lives INSIDE the grid box, directly above the column
   headers, so it costs one thin strip instead of a whole row plus a gap.
   The per-column filter row is hidden until asked for.
   ===================================================================== */
.gridbox{border:1px solid var(--line);border-radius:12px;overflow:hidden;background:var(--card);
  box-shadow:var(--shadow)}
.gridtools{display:flex;align-items:center;gap:.35rem;padding:.35rem .45rem;
  background:var(--panel);border-bottom:1px solid var(--line)}
.gridtools .srch{position:relative;flex:1;max-width:290px}
.gridtools .srch input{padding:.34rem .5rem .34rem 1.75rem;font-size:.82rem;border-radius:7px;
  background:var(--input-bg) url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='13' height='13' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2.4' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='M21 21l-4.2-4.2'/%3E%3C/svg%3E") no-repeat .5rem center}
.gridtools select{width:auto;padding:.3rem .4rem;font-size:.78rem;border-radius:7px}
.gridtools .gap{margin-left:auto}
.tbtn{border:1px solid var(--line);background:var(--card);color:var(--muted);border-radius:7px;
  padding:.28rem .4rem;cursor:pointer;display:inline-flex;align-items:center;gap:.28rem;
  font:inherit;font-size:.74rem;font-weight:600;line-height:1}
.tbtn:hover{background:var(--blue-soft);border-color:var(--blue-line);color:var(--blue)}
.tbtn.on{background:var(--blue);border-color:var(--blue);color:#fff}
.tbtn .lbl{display:none}
@media(min-width:820px){ .tbtn .lbl{display:inline} }
.colpanel{padding:.6rem .55rem;background:var(--panel);border-bottom:1px solid var(--line);
  display:flex;flex-wrap:wrap;gap:.15rem .9rem}
.colpanel label{display:inline-flex;align-items:center;gap:.32rem;font-size:.79rem;
  color:var(--ink);font-weight:400;margin:0}
.colpanel input{width:15px;height:15px}

/* =====================================================================
   MODAL — used wherever a record is created or a decision confirmed.
   Rule: a screen shows the existing records first. Creating a new one
   happens in here, not in a form occupying the top of the page.
   ===================================================================== */
.modal-bg{
  position:fixed;inset:0;background:rgba(8,13,22,.55);z-index:80;
  display:flex;align-items:flex-start;justify-content:center;
  padding:4vh 1rem 2rem;overflow-y:auto;backdrop-filter:blur(2px);
}
.modal{
  background:var(--card);border:1px solid var(--line);border-radius:14px;
  width:100%;max-width:640px;box-shadow:0 24px 70px rgba(0,0,0,.45);
}
.modal.narrow{max-width:460px}
.modal-h{
  display:flex;align-items:center;gap:.6rem;padding:.9rem 1rem;
  border-bottom:1px solid var(--line);
  /* The header is the window's handle (Prejit, 28 July 2026): grab it
     anywhere that is not a button and drag. touch-action:none lets the
     same grab work with a finger on the shop floor; user-select stops the
     title being highlighted mid-drag. */
  cursor:move;user-select:none;touch-action:none;
}
.modal-h .t{font-weight:650;font-size:1rem}
.modal-h .x{
  margin-left:auto;background:none;border:0;cursor:pointer;color:var(--muted);
  font-size:1.3rem;line-height:1;padding:.1rem .35rem;border-radius:6px;
}
.modal-h .x:hover{background:var(--panel);color:var(--ink)}
.modal-b{padding:1rem}
.modal-f{
  display:flex;gap:.5rem;justify-content:flex-end;padding:.8rem 1rem;
  border-top:1px solid var(--line);background:var(--panel);
  border-radius:0 0 14px 14px;flex-wrap:wrap;
}
.modal-f .left{margin-right:auto}

/* ---- theme picker: an icon in the bar, names only once opened ---- */
.themepick{position:relative}
.themepick > button{
  background:var(--card);border:1px solid var(--line);border-radius:9px;
  padding:.42rem .5rem;cursor:pointer;display:flex;align-items:center;color:var(--muted);
}
.themepick > button:hover{background:var(--blue-soft);border-color:var(--blue-line);color:var(--blue)}
.thememenu{
  position:absolute;right:0;top:calc(100% + .4rem);z-index:60;min-width:190px;
  background:var(--card);border:1px solid var(--line);border-radius:11px;
  box-shadow:0 12px 34px rgba(0,0,0,.18);padding:.3rem;
}
.thememenu button{
  width:100%;display:flex;align-items:center;gap:.55rem;background:none;border:0;
  padding:.42rem .5rem;border-radius:7px;cursor:pointer;font:inherit;font-size:.84rem;
  color:var(--ink);text-align:left;
}
.thememenu button:hover{background:var(--blue-soft)}
.thememenu button.on{background:var(--blue-soft);color:var(--blue);font-weight:650}
.thememenu .sw{width:18px;height:18px;border-radius:6px;flex:none;
  border:1px solid rgba(128,128,128,.35);box-shadow:inset -7px 0 0 rgba(0,0,0,.001)}
/* each swatch shows that theme's page and sidebar colours side by side */
.thememenu .sw[data-t="auto"]{background:linear-gradient(135deg,#f4f6f9 50%,#0f141c 50%)}
.thememenu .sw[data-t="light"]{background:linear-gradient(135deg,#f4f6f9 50%,#101c34 50%)}
/* Classic departs from the page+sidebar convention on purpose: its page and
   sidebar are so close to Light that at 18px the two swatches were the same
   square. Royal blue against gold is what actually distinguishes the theme,
   and it is what the name promises. */
.thememenu .sw[data-t="classic"]{background:linear-gradient(135deg,#16307a 50%,#daa520 50%)}
.thememenu .sw[data-t="dark"]{background:linear-gradient(135deg,#0f141c 50%,#63a4de 50%)}
.thememenu .sw[data-t="midnight"]{background:linear-gradient(135deg,#000205 50%,#ffb347 50%)}
.thememenu .sw[data-t="sepia"]{background:linear-gradient(135deg,#f4eee2 50%,#3a3226 50%)}
.thememenu .sw[data-t="contrast"]{background:linear-gradient(135deg,#fff 50%,#000 50%)}
.thememenu .tick{margin-left:auto;color:var(--blue);font-weight:800}

/* ---- AG Grid, themed to match the application ----
   NOTE TO SELF, learned the hard way twice: AG Grid's CSS variables for row
   and column borders do not reliably apply under the quartz theme. Both are
   written as explicit rules below. Trust the rule, not the variable.

   SECOND NOTE: never set `position` on .ag-row. AG Grid places every row
   absolutely and moves it with a transform; overriding position breaks the
   layout and rows visibly shift apart. Hover effects must be paint-only —
   background and inset shadow — never anything that affects layout. */
/* Two classes on the same element, deliberately. `.ag-theme-quartz` alone has
   the same specificity as `.s1grid`, so whichever stylesheet loaded last would
   win. This guarantees ours does, whatever the load order. */
.ag-theme-quartz.s1grid,
.s1grid{
  --ag-font-family:inherit;
  /* Compact by design. These four numbers set the density of every grid in
     the application — change them here, nowhere else. */
  --ag-font-size:.8rem;
  --ag-grid-size:3px;
  --ag-row-height:28px;
  --ag-header-height:30px;
  --ag-list-item-height:24px;
  --ag-cell-horizontal-padding:8px;

  --ag-background-color:var(--card);
  --ag-foreground-color:var(--ink);
  --ag-data-color:var(--ink);
  --ag-secondary-foreground-color:var(--muted);
  --ag-disabled-foreground-color:var(--faint);

  --ag-header-background-color:var(--grid-head);
  --ag-header-foreground-color:var(--grid-head-ink);
  --ag-odd-row-background-color:var(--grid-odd);
  --ag-row-hover-color:var(--grid-hover);
  --ag-selected-row-background-color:var(--blue-soft);

  --ag-border-color:var(--line);
  --ag-secondary-border-color:var(--grid-col-line);
  --ag-header-column-separator-display:block;
  --ag-header-column-separator-height:100%;
  --ag-header-column-separator-width:1px;
  --ag-header-column-separator-color:var(--grid-col-line);
  --ag-header-column-resize-handle-display:block;
  --ag-header-column-resize-handle-height:60%;
  --ag-header-column-resize-handle-width:2px;
  --ag-header-column-resize-handle-color:var(--blue-line);

  --ag-input-background-color:var(--input-bg);
  --ag-input-border-color:var(--input-line);
  --ag-input-focus-border-color:var(--blue);
  --ag-checkbox-checked-color:var(--blue);
  --ag-menu-background-color:var(--card);
  --ag-menu-foreground-color:var(--ink);
  --ag-control-panel-background-color:var(--panel);
  --ag-wrapper-border-radius:0;
  --ag-borders:none;
}

/* ================= THE LINES, stated explicitly ================= */

/* horizontal — between every row */
.s1grid .ag-row{
  border-bottom:1px solid var(--grid-row-line);
  transition:background-color .1s;
}
/* vertical — between every column, header included */
.s1grid .ag-cell{border-right:1px solid var(--grid-col-line)}
.s1grid .ag-cell:last-child{border-right:0}
.s1grid .ag-header-cell,
.s1grid .ag-header-group-cell{border-right:1px solid var(--grid-col-line)}
.s1grid .ag-header-cell:last-child{border-right:0}

/* ================= depth ================= */
/* Only the header and the outer box carry depth. Rows stay flat, because
   anything that lifts a row has to touch stacking, and that breaks it. */
.s1grid{box-shadow:inset 0 0 0 1px var(--grid-col-line)}
/* The header must read as a distinct band above the rows in EVERY theme.
   It was previously five shades away from the card colour in Dark, which
   made it invisible. The top highlight is a variable because a white sheen
   works on a light header and ruins a dark one. */
.s1grid .ag-header{
  background:var(--grid-head);
  border-bottom:2px solid var(--line);
  box-shadow:0 2px 4px rgba(0,0,0,.14), inset 0 1px 0 var(--grid-head-hi);
}
/* Written out, not left to --ag-header-foreground-color. That variable was
   being overridden by the theme stylesheet and the text disappeared in the
   dark themes. */
.s1grid .ag-header-cell,
.s1grid .ag-header-group-cell,
.s1grid .ag-header-cell-text,
.s1grid .ag-header-cell-label{color:var(--grid-head-ink)}
.s1grid .ag-header-icon,
.s1grid .ag-header-cell-menu-button{color:var(--grid-head-ink);opacity:.75}
.s1grid .ag-header-cell-text{
  font-size:.66rem;text-transform:uppercase;letter-spacing:.04em;font-weight:700;
}
.s1grid .ag-header-cell,
.s1grid .ag-header-group-cell{padding-left:8px;padding-right:8px}
.s1grid .ag-header-cell:hover{background:rgba(125,125,125,.10)}
.s1grid .ag-header-cell.ag-header-cell-sorted-asc,
.s1grid .ag-header-cell.ag-header-cell-sorted-desc{
  background:var(--blue-soft);color:var(--blue);
  box-shadow:inset 0 -2px 0 var(--blue);
}

/* hover and selection are paint-only — no position, no z-index, no margin */
.s1grid .ag-row-hover{background-color:var(--grid-hover)!important}
.s1grid .ag-row-selected{box-shadow:inset 3px 0 0 var(--blue)}

.s1grid .ag-cell{display:flex;align-items:center;line-height:1.2;color:var(--ink)}
.s1grid .ag-row{color:var(--ink)}
/* Buttons and pills inside cells must not force the row taller than the
   row height, or the compact setting is undone one cell at a time. */
.s1grid .ag-cell .btn{padding:.08rem .42rem;font-size:.68rem;line-height:1.25}
.s1grid .ag-cell .pill{font-size:.62rem;padding:.08rem .38rem;line-height:1.25}
.s1grid .ag-cell .code{font-size:.62rem;padding:.14rem .34rem}
.s1grid .ag-cell:first-child{font-weight:500}
/* the running-number column — present, not prominent */
.s1grid .ag-cell.s1seq{
  justify-content:flex-end;color:var(--faint);font-weight:400;
  font-variant-numeric:tabular-nums;background:var(--grid-head);
}
.s1grid .ag-header-cell.s1seq .ag-header-cell-label{justify-content:flex-end}

.s1grid .ag-floating-filter{height:24px}
.s1grid .ag-floating-filter-input .ag-input-field-input{
  font-size:.72rem;height:19px;border-radius:4px;padding:0 .3rem;
}
.s1grid .ag-paging-panel{
  border-top:1px solid var(--line);background:var(--panel);
  color:var(--muted);font-size:.72rem;height:30px;
  box-shadow:inset 0 1px 0 var(--grid-head-hi);
}
.s1grid .ag-paging-panel .ag-paging-button{margin:0 2px}
.s1grid .ag-overlay-no-rows-center .s1empty,.s1grid .s1empty{
  color:var(--faint);font-size:.85rem;
}
/* the outer box carries the raised look */
.gridbox{box-shadow:0 1px 3px rgba(16,28,52,.10), 0 6px 16px rgba(16,28,52,.06)}
[data-theme="dark"] .gridbox,
[data-theme="midnight"] .gridbox{box-shadow:0 2px 6px rgba(0,0,0,.5)}

/* =====================================================================
   ICON EMOJI SIZE — one number
   =====================================================================
   APPENDED. The rules above are untouched; these come later in the file
   and so win on equal specificity.

   The coloured chip and the emoji inside it are two different sizes. This
   sets the EMOJI only, everywhere it appears — the sidebar menu and the
   card headers — from a single value. Change the one number below.

   Was: 16px in the sidebar, and 55% of the chip (15px at a 28px chip) in
   the card headers, so the two never quite matched.

   NOTE ON FIT: the sidebar chip is 30px and the card chips are 28px, so a
   26px glyph fills them almost completely and may sit a shade proud of
   the tinted square on some fonts. If that reads badly, the fix is to
   grow the chips to match — say so and it is one more line here.
   ===================================================================== */
:root{ --ic-emoji:24px }

nav a .ic{ font-size:var(--ic-emoji) }

/* =====================================================================
   NAV SECTIONS — added 27 July 2026 with the Parties module.
   The sidebar was one flat list of eight; the masters would have made it a
   wall. Sections roll up, and the state is remembered per browser.
   ===================================================================== */
.navgroup + .navgroup{margin-top:.15rem}
.navlabel{display:flex;align-items:center;justify-content:space-between;
  cursor:pointer;user-select:none;gap:.4rem;transition:color .15s}
.navlabel:hover{color:rgba(255,255,255,.68)}
.navlabel .chev{flex:0 0 auto;opacity:.55;transition:transform .18s}
.navlabel.shut .chev{transform:rotate(-90deg)}
/* Collapsed sidebar: the heading is already hidden, so the chevron would be
   a stray glyph floating over the icons. */
aside.mini .navlabel .chev{display:none}

/* =====================================================================
   EDITABLE GRIDS
   Three states, and each has to survive a repaint, so they are driven from
   the ROW rather than from a class the grid might rebuild away.
     s1cell_dirty  changed, not yet saved
     s1cell_new    a row that does not exist in the database yet
     s1cell_bad    a required box left empty
   Colours come from the theme variables, never literals — the Branches
   defect of 27 July was hardcoded colours going invisible in Dark and
   Midnight, and this is the same trap one screen further on.
   ===================================================================== */
.s1grid .s1cell_dirty{background:var(--warn-soft);
  box-shadow:inset 2px 0 0 var(--warn)}
.s1grid .s1cell_new{background:var(--blue-soft)}
.s1grid .s1cell_bad{background:var(--red-soft);
  box-shadow:inset 0 0 0 1.5px var(--red)}
.s1grid .ag-cell-inline-editing{box-shadow:inset 0 0 0 2px var(--accent)}
.s1grid .swatch{display:inline-block;width:12px;height:12px;border-radius:3px;
  margin-right:.45rem;vertical-align:-1px;box-shadow:inset 0 0 0 1px rgba(0,0,0,.2)}

/* The unsaved-changes bar. Sticky, because on a 200-row grid the Save button
   must not be somewhere you have to scroll to find. */
.editbar{position:sticky;top:0;z-index:6;display:flex;align-items:center;
  gap:.6rem;flex-wrap:wrap;padding:.35rem .6rem;margin-bottom:.4rem;
  border-radius:8px;background:var(--warn-soft);color:var(--warn);
  border:1px solid var(--warn);font-size:.85rem;font-weight:600}
.editbar .sp{flex:1 1 auto}
.editbar.clean{background:var(--card);color:var(--muted);border-color:var(--line);
  font-weight:500}

/* The collapse-all caret. One glyph rotated, never two icons that could
   disagree about which state they mean. */
.gridtools .tbtn[data-gcollapse] svg{transition:transform .14s ease}
.gridtools .tbtn[data-gcollapse].shut svg{transform:rotate(-90deg)}

/* =====================================================================
   SEGMENTED TOGGLE (31 July 2026)
   ---------------------------------------------------------------------
   Two or three states of ONE setting, in one control. Prejit asked for
   the rights screen's By-role / Compare-roles pair to stop being two
   buttons: two buttons side by side read as two things you can DO, and
   what this actually is, is one thing that is currently set one way.

   The ink on the filled segment comes from --accent-ink, which flips per
   theme — --accent is dark in Light, Classic, Sepia and Contrast and
   LIGHT in Dark and Midnight, and three separate defects this week came
   from a hardcoded colour vanishing in two of six themes.
   ===================================================================== */
.seg{display:inline-flex;align-items:center;gap:2px;padding:2px;
  background:var(--panel);border:1px solid var(--line);border-radius:999px}
.seg button{appearance:none;border:0;background:transparent;color:var(--muted);
  font:inherit;font-size:.78rem;font-weight:600;white-space:nowrap;
  padding:.3rem .75rem;border-radius:999px;cursor:pointer;
  transition:background .14s ease,color .14s ease}
.seg button:hover{color:var(--ink)}
.seg button.on{background:var(--accent);color:var(--accent-ink)}
.seg button.on:hover{color:var(--accent-ink)}
.seg button:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.seg button:disabled{opacity:.45;cursor:not-allowed}

/* =====================================================================
   THE RIGHTS GRID (31 July 2026)
   ---------------------------------------------------------------------
   Three states in one column, and the third is the one every rights
   screen we have seen gets wrong.

     a tick box            this row has this action; it is on or off
     .s1cell_na            this row HAS NO SUCH ACTION — a dash, no box

   Diatech's Menu Rights offers six identical boxes on a row with one
   real action, so an empty box means "denied" on one line and "means
   nothing here" on the next, with no way to tell them apart. A dash
   costs one CSS rule and removes the ambiguity entirely.

   The checkbox is hidden rather than not rendered: the cell is still an
   AG Grid boolean cell, so nothing about the column's behaviour has to
   change per row. Pointer events go with it — an invisible box you can
   still click would be worse than a visible one.
   ===================================================================== */
.s1grid .s1cell_na{position:relative;pointer-events:none}
.s1grid .s1cell_na .ag-checkbox,
.s1grid .s1cell_na .ag-cell-wrapper,
.s1grid .s1cell_na input[type=checkbox]{visibility:hidden}
.s1grid .s1cell_na::after{content:'\2013';position:absolute;inset:0;
  display:flex;align-items:center;justify-content:center;
  color:var(--faint);font-weight:600}

/* The menu-group heading, drawn as a row because AG Grid Community has
   no row grouping. It has to read as a heading and not as a record, so:
   panel background, no separator above, and its own cells carry nothing. */
.s1grid .ag-row.s1-row-grp{background:var(--panel);font-weight:700}
.s1grid .ag-row.s1-row-grp .ag-cell{border-right-color:transparent}
.s1grid .s1cell_grp{background:var(--panel)}
.rgrp{display:inline-flex;align-items:center;gap:.4rem;cursor:pointer;
  user-select:none;letter-spacing:.02em}
.rgrp .cv{display:inline-block;width:.7rem;color:var(--muted);
  transition:transform .12s ease}
.rgrp .cv.shut{transform:rotate(-90deg)}
/* A right that nothing in the database reads yet. It must be grantable —
   you set a role up before the module lands — but it must not look as
   though it did something. */
.pill.soon{background:var(--panel);color:var(--muted);
  box-shadow:inset 0 0 0 1px var(--line)}

/* The master picker down the left of Reference Lists.
   HEIGHT MATCHED TO THE ENTRY TABLE (31 July 2026, second pass — Prejit:
   "make the height of side menu to match the entry table bottom"; this
   replaces the same morning's viewport-cap sticky). The grid row's height
   is set by the RIGHT column alone: the left cell stretches with the row
   and the list absolute-fills it, so the menu's bottom edge IS the entry
   card's bottom — never taller, never shorter, and the page can never
   grow because of the menu. A list longer than that scrolls INSIDE the
   box; the search box is sticky INSIDE the scrolling box, so it stays
   put while the list moves under it. overscroll-behavior stops a
   finished list scroll from spilling into the page. On one column
   (≤900px) the layout is stacked: normal flow, capped, no absolutes. */
.mastercols{display:grid;grid-template-columns:230px minmax(0,1fr);gap:1rem}
@media (max-width:900px){.mastercols{grid-template-columns:1fr}}
.masterside{position:relative;min-height:280px}
.masterlist{position:absolute;inset:0;border:1px solid var(--line);
  border-radius:10px;background:var(--card);
  overflow-y:auto;overflow-x:hidden;overscroll-behavior:contain}
@media (max-width:900px){
  .masterside{position:static;min-height:0}
  .masterlist{position:static;max-height:340px}}
.msearch{position:sticky;top:0;z-index:2;background:var(--card);
  padding:.45rem;border-bottom:1px solid var(--line)}
.msearch input{width:100%;font:inherit;font-size:.82rem;padding:.35rem .55rem;
  border:1px solid var(--line);border-radius:8px;background:var(--bg);
  color:var(--ink)}
.msearch input:focus{outline:none;border-color:var(--accent)}
.masterlist button{display:block;width:100%;text-align:left;border:0;
  background:transparent;color:var(--ink);padding:.5rem .75rem;font-size:.85rem;
  cursor:pointer;border-left:3px solid transparent;font-family:inherit}
.masterlist button:hover{background:var(--bg)}
.masterlist button.on{background:var(--bg);border-left-color:var(--accent);
  font-weight:650}
.masterlist button small{display:block;color:var(--muted);font-size:.72rem;
  font-weight:400;margin-top:.1rem;line-height:1.25}

/* =====================================================================
   TABS inside a window — added with the Parties module.
   A party is thirty fields across five sections; one long scroll makes
   people miss half of it.
   ===================================================================== */
.tabs{display:flex;gap:.15rem;flex-wrap:wrap;border-bottom:1px solid var(--line);
  margin:-.2rem 0 .7rem}
.tabs .tab{border:0;background:transparent;color:var(--muted);font-family:inherit;
  font-size:.85rem;padding:.42rem .7rem;cursor:pointer;border-bottom:2px solid transparent;
  margin-bottom:-1px;border-radius:6px 6px 0 0}
.tabs .tab:hover{color:var(--ink);background:var(--bg)}
.tabs .tab.on{color:var(--ink);font-weight:650;border-bottom-color:var(--accent)}

/* A compact table of editable rows. NOT the AG Grid abstraction: these lists
   hold two emails and one address, and six grid instances inside a modal that
   opens and closes all day would cost far more than they return. The tabular
   grid is for bulk entry; this is not bulk entry.
   Named `rowtable`, not `mini` — `mini` already means the collapsed sidebar,
   and a second meaning is how a stylesheet comes to fight itself. */
.rowtable{width:100%;border-collapse:collapse;font-size:.85rem}
.rowtable th{text-align:left;font-weight:600;color:var(--muted);font-size:.75rem;
  padding:.25rem .35rem;border-bottom:1px solid var(--line);white-space:nowrap}
.rowtable td{padding:.18rem .35rem;vertical-align:middle}
.rowtable input,.rowtable select{width:100%;margin:0}
/* ...but not the Primary radios/ticks, which that rule stretched to the
   full cell. Higher specificity, so position here is not load-bearing. */
.rowtable input[type="radio"],.rowtable input[type="checkbox"]{
  width:16px;height:16px;margin:0}
.rowtable tr:hover td{background:var(--bg)}
@media (max-width:760px){
  .rowtable,.rowtable thead,.rowtable tbody,.rowtable tr,.rowtable td{display:block;width:100%}
  .rowtable thead{display:none}
  .rowtable tr{border:1px solid var(--line);border-radius:8px;padding:.4rem;margin-bottom:.4rem}
}

/* =====================================================================
   THE TIME-ZONE PICKER (0075) — a search box over an offset-ordered
   list. Every colour is a variable, so all six themes get it for free;
   the option under the pointer and the one currently held both use the
   ordinary hover surface, never a hardcoded colour (the lesson three
   defects taught in one week).
   ===================================================================== */
.tzwrap{position:relative}
.tzdrop{position:absolute;left:0;right:0;top:calc(100% + 2px);z-index:60;
  max-height:16rem;overflow:auto;background:var(--card);
  border:1px solid var(--line);border-radius:8px;
  box-shadow:0 8px 24px rgba(0,0,0,.18)}
.tzopt{padding:.32rem .6rem;font-size:.85rem;cursor:pointer;white-space:nowrap}
.tzopt:hover{background:var(--bg)}
.tzopt.on{font-weight:650}

/* =====================================================================
   FULL-SCREEN RECORD EDITOR — Parties, 28 July 2026.
   Prejit: "customer module having many field so the popup size is small it
   cant utilize the full screen." A party is ~60 fields across five tabs; a
   modal is the wrong container however wide it is made, because it can never
   use the height and it floats over a list nobody is looking at. The editor
   replaces the list in place instead. The list is hidden, not destroyed, so
   Back returns to the same page, filters and column layout (rule 25).
   ===================================================================== */
/* top:0 was WRONG here: the topbar above is itself sticky at z-index 30, so
   the editor bar stuck BEHIND it and appeared to scroll away — it was
   sticking, just invisibly (Prejit, 29 July: "when scrolling down also fix
   the party name displaying row"). It now rests just below a one-line
   topbar; the tab strip stacks below both. */
.editorbar{position:sticky;top:2.55rem;z-index:20;display:flex;align-items:center;
  gap:.5rem;flex-wrap:wrap;padding:.45rem .6rem;margin-bottom:.5rem}
.editorbar .t{font-weight:650;font-size:.95rem}
/* The actions sit here rather than in a footer, so Save is reachable from any
   tab without scrolling past sixty fields to find it. */
@media (max-width:700px){
  .editorbar{gap:.35rem}
  .editorbar .t{width:100%;order:-1}
}

/* Tabs stay put while the body scrolls — Prejit, 28 July: "when i scroll down
   the header tab should be fixed no scroll". Sits below the editor bar, so the
   two stack rather than overlap. */
.tabs.sticky{position:sticky;top:5.15rem;z-index:6;background:var(--card);
  margin:-.2rem -.75rem .7rem;padding:.25rem .75rem 0}

/* =====================================================================
   PICK CHIPS — roles, and the branches a party is visible to.
   Prejit, 28 July: "roles and visible to make more highlited for selected,
   so can easily identified."

   Selected is FILLED, not merely outlined: at a glance the eye reads solid
   blocks against outlines without having to compare border colours. The tick
   is there so the state does not rest on colour alone — colour-blind users,
   and anyone printing a screen, still see which are on.

   The ink on the filled chip comes from --accent-ink, which flips per theme.
   --accent is a DARK blue in Light, Sepia and High contrast but a LIGHT blue
   in Dark and Midnight, so a hardcoded white would have been invisible in two
   of the six — the same defect the Branches buttons had on 27 July.
   ===================================================================== */
.chip{appearance:none;font-family:inherit;font-size:.83rem;cursor:pointer;
  display:inline-flex;align-items:center;gap:.35rem;
  padding:.34rem .7rem;border-radius:999px;
  background:var(--card);color:var(--ghost-ink);
  border:1.5px solid var(--ghost-line);opacity:.75;
  transition:background .12s,color .12s,opacity .12s,box-shadow .12s}
.chip:hover{opacity:1;background:var(--panel)}
.chip .mk{font-weight:800;width:.75rem;display:inline-block;text-align:center}
.chip.on{background:var(--accent);color:var(--accent-ink);
  border-color:var(--accent);opacity:1;font-weight:650;
  box-shadow:0 1px 3px rgba(0,0,0,.18)}
.chip.on:hover{background:var(--accent);opacity:.92}
.chip:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
/* The row of them, with a count so "none chosen" is obvious. */
.chiprow{display:flex;flex-wrap:wrap;gap:.4rem;margin:.15rem 0 .2rem}


