/* Settings.
   A settings screen earns trust by explaining itself. The rail says what
   exists, the pane says what each table is for and what reads it, every field
   carries a sentence of help, and every change shows itself before it lands.
   Quieter and roomier than the data grids on purpose -- this is a place people
   come to think, not to scan 255,000 rows. */

.settings { overflow: hidden; }
.setwrap { display: flex; height: 100%; overflow: hidden; }

/* The rail: what is in this group. Its width is set once, further down, with
   the rest of the vertical-navigation shell that replaced the first version of
   this screen. The 262px that used to sit here never reached the page. */
.setrail { flex: none; overflow-y: auto; padding: 10px 8px 24px;
  border-right: 1px solid var(--line); background: var(--panel); }
.setitem { display: block; width: 100%; text-align: left; border: 0; cursor: pointer;
  background: 0; padding: 9px 11px; border-radius: var(--r-md); margin-bottom: 2px;
  color: var(--ink); transition: background .12s; }
.setitem:hover { background: var(--row-hover); }
/* the frame's own "you are here": the tint and the ink, no stripe (18 Sep 2026) */
.setitem.on { background: var(--accent-soft); }
.setitem-title { display: block; font-weight: 600; font-size: var(--t-base); }
.setitem.on .setitem-title { color: var(--accent); }
.setitem-sub { display: block; font-size: var(--t-sm); color: var(--muted); margin-top: 2px; }
.setitem-sub .dot { margin: 0 5px; }

/* The pane. Its padding, and the banner's whole box, are set further down with
   the rest of the shell that replaced the first version of this screen; the
   22px 26px 60px and the 760px-wide heading block once stated here were both
   overridden before anyone ever saw them. */
.setpane { flex: 1; overflow-y: auto; }
.sethead h2 { margin: 0 0 5px; font-size: var(--t-2xl); letter-spacing: -.01em; }
.setdesc { margin: 0; color: var(--ink-2); font-size: var(--t-base); line-height: 1.55; }
.setused { margin: 9px 0 0; font-size: var(--t-md); color: var(--muted); }
.setused-lab { text-transform: uppercase; letter-spacing: .06em; font-size: var(--t-xs);
  font-weight: 700; margin-right: 8px; color: var(--muted); }

.setbar { display: flex; align-items: center; gap: 9px; margin: 0 0 12px; flex-wrap: wrap; }
.setbar input[type=search] { padding: 6px 11px; border: 1px solid var(--line);
  border-radius: var(--r-sm); background: var(--bg); color: var(--ink); min-width: 240px; }
/* The group filter in People & Access was a bare <select>: raw OS chrome
   standing between a styled search box and a .btn, at a different height and
   a different corner. Same well, hairline and radius as every other field on
   a bar. Scoped to .setbar on purpose -- the selects in dense lists are
   deliberately tighter and must not inherit this padding: the per-cell
   pickers (select.lvl, select.gpick) live in table cells, and .presetrow
   select repeats once per section per hub in the Groups dialog, where eight
   extra pixels a row would add hundreds to a dialog that already scrolls. */
.setbar select { padding: 6px 11px; border: 1px solid var(--line);
  border-radius: var(--r-sm); background: var(--bg); color: var(--ink);
  font: inherit; }
.setcount { font-size: var(--t-md); color: var(--muted); }
.robadge { font-size: var(--t-sm); color: var(--warn); background: var(--warn-bg);
  border: 1px solid var(--warn-edge); padding: 3px 10px; border-radius: var(--r-pill); }
/* Stated three times, the way app.css states its whole palette: the media
   query alone follows the OS, not the person -- someone whose Windows is
   light but who chose Dark in Appearance would get a cream pill on a dark
   page, and the dark-theme --warn is unreadable on cream. The guard keeps
   the media query out of a chosen Light theme; the attribute block makes a
   chosen Dark theme win on a light OS. */

/* the rows */
.settable { border: 1px solid var(--line); border-radius: var(--r-md); overflow: auto;
  background: var(--panel); }
table.setgrid { width: 100%; border-collapse: collapse; font-size: var(--t-md); }
table.setgrid th { text-align: center; background: var(--header); font-weight: 700;
  font-size: var(--t-sm); text-transform: uppercase; letter-spacing: .04em;
  color: var(--ink-2); padding: 9px 12px; border-bottom: 1px solid var(--grid);
  white-space: nowrap; position: sticky; top: 0; z-index: 1; }
table.setgrid th.mid, table.setgrid td.mid { text-align: center; }
table.setgrid td { padding: 8px 12px; border-bottom: 1px solid var(--line);
  vertical-align: top; }
table.setgrid td.num { text-align: right; font-variant-numeric: tabular-nums; }
table.setgrid td.code { font-family: var(--mono); font-size: var(--t-md); }
/* a long-text cell: shown whole, and a line break in the value is a line
   break on the screen -- one fact per line (DESIGN.md, 17 Sep 2026) */
table.setgrid td.long { white-space: pre-line; }
table.setgrid tbody tr { cursor: pointer; }
table.setgrid tbody tr:hover td { background: var(--row-hover); }
table.setgrid tbody tr:last-child td { border-bottom: 0; }
.fhint { display: inline-block; margin-left: 5px; width: 13px; height: 13px;
  line-height: 13px; text-align: center; border-radius: var(--r-round); font-size: var(--t-xs);
  background: var(--muted); color: var(--panel); font-weight: 700; }
/* The badge was --panel on --grid: 1.51:1 in light and 1.39:1 in dark, which
   is a blank circle where the "?" should be -- people were clicking a dot
   with nothing in it. --muted is the quietest ink in the palette that still
   carries a glyph (5.37:1 light, 5.63:1 dark), which is the right weight for
   a help mark: present, not shouting. */
.yes { color: var(--good); font-weight: 600; }
.ok { color: var(--ink-2); }
.no { color: var(--muted); }

/* the form */
.setedit { position: fixed; top: 0; right: 0; bottom: 0; width: min(520px, 96vw);
  background: var(--panel); border-left: 1px solid var(--line); z-index: 120;
  display: flex; flex-direction: column;
  box-shadow: -16px 0 40px rgba(0,0,0,.12); animation: slidein .16s ease-out; }
.setscrim { z-index: 119; }
.setedit > header { flex: none; padding: 18px 22px 14px;
  border-bottom: 1px solid var(--line); position: relative; }
.setedit > header h3 { margin: 0; font-size: var(--t-xl); }
.setkey { font-family: var(--mono); font-size: var(--t-sm); color: var(--muted); margin-top: 3px; }
.setedit .close { position: absolute; top: 12px; right: 14px; background: 0; border: 0;
  font-size: var(--t-2xl); line-height: 1; color: var(--muted); cursor: pointer; }
.setedit .close:hover { color: var(--ink); }
.setform { flex: 1; overflow-y: auto; padding: 18px 22px; }
.setedit > footer { flex: none; display: flex; align-items: center; gap: 8px;
  padding: 13px 22px; border-top: 1px solid var(--line); background: var(--bg); }

.sfield { display: block; margin-bottom: 17px; }
.sfield.ro { opacity: .6; }
.slabel { display: block; font-size: var(--t-md); font-weight: 600; margin-bottom: 5px; }
.slabel .req { color: var(--bad); margin-left: 3px; }
.sfield input[type=text], .sfield input[type=number], .sfield input[type=date],
.sfield input[type=email], .sfield select, .sfield textarea {
  width: 100%; padding: 7px 10px; border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--bg); color: var(--ink); font: inherit; }
.sfield input:focus, .sfield select:focus, .sfield textarea:focus {
  outline: 2px solid var(--cursor); outline-offset: -1px; border-color: transparent; }
.sfield input.mono { font-family: var(--mono); }
.sfield textarea { resize: vertical; line-height: 1.5; }
.shelp { display: block; font-size: var(--t-sm); color: var(--muted); margin-top: 5px;
  line-height: 1.5; }

/* a real switch, because a tick box for "is this rule live" reads as trivia */
.switch { position: relative; display: inline-block; width: 42px; height: 23px;
  vertical-align: middle; }
.switch input { opacity: 0; width: 0; height: 0; position: absolute; }
.slider { position: absolute; inset: 0; background: var(--grid); border-radius: var(--r-pill);
  transition: background .16s; cursor: pointer; }
.slider::before { content: ""; position: absolute; width: 17px; height: 17px;
  left: 3px; top: 3px; background: var(--knob); border-radius: var(--r-round);
  transition: transform .16s;
  /* The knob is white in both themes (--knob, deliberately constant) and the
     OFF track is --grid, which in light is 1.51:1 -- an off switch read as an
     empty pill and could not be told from a disabled one. --shadow-1 is a
     soft drop shadow, not an edge, so it does not rescue it. A hairline ring
     in --muted is 3.57:1 on the off track in light and 4.06:1 in dark. It is
     drawn as a spread shadow rather than a border so the knob keeps its 17px
     and does not jump when the switch flips, and it all but disappears on the
     green ON track (1.2:1), which is right: the on state never needed it. */
  box-shadow: 0 0 0 1px var(--muted), var(--shadow-1); }
.switch input:checked + .slider { background: var(--good); }
.switch input:checked + .slider::before { transform: translateX(19px); }
.switch input:disabled + .slider { opacity: .5; cursor: default; }
.switch input:focus-visible + .slider { outline: 2px solid var(--cursor); outline-offset: 2px; }

/* what is about to change, before it changes */
.schanges { flex: none; padding: 0 22px; }
.schead { font-size: var(--t-xs); text-transform: uppercase; letter-spacing: .06em;
  font-weight: 700; color: var(--muted); margin: 14px 0 7px; }
.schange { display: grid; grid-template-columns: 1fr auto auto auto; gap: 8px;
  align-items: baseline; font-size: var(--t-md); padding: 5px 0;
  border-bottom: 1px dashed var(--line); }
.scfield { color: var(--ink-2); font-weight: 600; }
.scold { color: var(--muted); text-decoration: line-through; }
.scarrow { color: var(--muted); }
.scnew { color: var(--good); font-weight: 600; }
.smsg { flex: none; padding: 8px 22px 0; font-size: var(--t-md); min-height: 1.4em;
  color: var(--good); }
.smsg.bad { color: var(--bad); }
.btn.danger { color: var(--bad); border-color: var(--bad-edge); }
.btn.danger:hover { background: var(--bad-bg); }

/* the record */
.hcard { border: 1px solid var(--line); border-radius: var(--r-md); padding: 11px 13px;
  margin-bottom: 9px; background: var(--bg); }
/* The same fault as .sgnodata, on the page people come to precisely to read
   this: at .55 an undone change -- the audit record of something somebody
   took back -- became the hardest card on the page to read, its badge and
   diff both dimmed toward the ground. A dashed edge says "this no longer
   stands" as a shape, at full contrast, and the italic "Undone" line the card
   already carries (.hundone) says it in words. */
.hcard.undone { border-style: dashed; }
.htop { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.hact { font-size: var(--t-xs); text-transform: uppercase; letter-spacing: .05em;
  font-weight: 700; padding: 2px 7px; border-radius: var(--r-xs); }
.hact.update { background: var(--blue-soft); color: var(--blue); }
.hact.insert { background: var(--good-bg); color: var(--good); }
.hact.delete { background: var(--bad-bg); color: var(--bad); }
.htbl { font-size: var(--t-sm); color: var(--ink-2); font-weight: 600; }
.hkey { font-family: var(--mono); font-size: var(--t-sm); color: var(--muted); }
.hwho { font-size: var(--t-sm); color: var(--muted); margin-top: 3px; }
.hdiff { margin-top: 8px; }
.hcard .btn { margin-top: 9px; }
.hundone { margin-top: 8px; font-size: var(--t-sm); color: var(--muted); font-style: italic; }

/* people & access */
.granta { display: flex; align-items: flex-start; gap: 12px; padding: 11px 0;
  border-bottom: 1px solid var(--line); }
.granta-lab { flex: 1; }
.granta-opts { flex: none; display: inline-flex; border: 1px solid var(--line);
  border-radius: var(--r-sm); overflow: hidden; }
/* The third size for one control: the toolbar's segmented group is --t-md and
   the detail panel's was --t-xs, and this one sat between them at --t-sm.
   --t-md, like every other button in the Hub. */
.seg { border: 0; background: var(--panel); color: var(--ink-2); font-size: var(--t-md);
  padding: 6px 11px; cursor: pointer; border-right: 1px solid var(--line); }
.seg:last-child { border-right: 0; }
.seg:hover { background: var(--row-hover); }
.seg.on { background: var(--ribbon); color: var(--on-ribbon); font-weight: 600; }
table.setgrid.people td { vertical-align: middle; }

/* The quiet confirmation at bottom centre is .toast, declared once, in app.css.
   It was stated here as well, and because this sheet loads second those values
   were silently overriding app.css's -- two definitions, one of them a ghost. */
.adminnote { font-size: var(--t-sm); color: var(--warn); background: var(--warn-bg);
  border: 1px solid var(--warn-edge); border-radius: var(--r-sm); padding: 8px 11px;
  margin: 0 0 10px; line-height: 1.5; }
.granta.muted { opacity: .45; }

/* ---------------------------------------------------- vertical navigation --
   Groups as headings, their tables beneath, read top to bottom. */
.setgroup { font-size: var(--t-xs); text-transform: uppercase; letter-spacing: .07em;
  font-weight: 700; color: var(--muted); padding: 16px 11px 6px;
  display: flex; align-items: center; gap: 7px; }
.setgroup:first-child { padding-top: 6px; }
/* a drawn icon now (icons.js), sized by .ic.sm; it takes the heading's muted ink */
.setgroup-icon { flex: none; }
.setrail { width: 244px; }

/* the banner: one clean block, not a wrapping toolbar */
.setpane { padding: 0 0 60px; }
.sethead { max-width: none; margin: 0 0 16px; padding: 20px 26px 16px;
  background: var(--panel); border-bottom: 1px solid var(--line); }
.setbar { padding: 0 26px; }
.settable { margin: 0 26px; }

/* STICKY HEADERS THAT COULD NEVER STICK. table.setgrid th has carried
   `position: sticky; top: 0` since this screen was written and it has never
   done anything. Sticky binds to the nearest ancestor that ACTUALLY scrolls,
   and .settable is `overflow: auto` with no height, so it is exactly as tall
   as its table and never overflows. What scrolls is .setpane -- and the header
   scrolled out of the pane along with everything else, which on a table of a
   thousand rows means no idea which column you are reading.
   Give the pane a column layout and let the table box keep the height that is
   left, so .settable finally becomes the scrollport its `overflow` already
   claims and `top: 0` has something to bind to. flex-basis stays auto with
   shrink allowed, so a three-row table is still three rows tall rather than a
   full-height empty panel; only a table taller than the pane shrinks and
   scrolls inside itself.
   :has(> .settable) is the scope, on purpose: the Tabs and Columns pages put
   .corder-list in this same pane and must keep flowing at their natural
   height. People & Access used to be excluded as well. Its thead is TWO
   rows, both sticky at top: 0, and switching the scrollport on pinned them
   on top of each other -- but leaving it out cost the same headers that
   this rule exists to keep, and put its horizontal scrollbar under eighty
   rows where nobody scrolling to the far right could find it. The two rows
   now stack by a declared band height (--hubband-h, below), so the table
   box is safe to become the scrollport here too. A browser without :has()
   keeps the old behaviour rather than breaking. */
.setpane:has(> .settable) {
  display: flex; flex-direction: column; overflow: hidden; padding-bottom: 0; }
.setpane:has(> .settable) > * { flex: none; }
.setpane:has(> .settable) > .settable {
  flex: 0 1 auto; min-height: 0; margin-bottom: 26px; }
/* People & Access is the one page that puts something tall above its table:
   the card of sign-ins waiting to be added, one row each. With the pane no
   longer scrolling, that card took its full height first and the table got
   what was left -- ten waiting sign-ins on a 900px window left the grid 114px
   tall, and a dozen would have hidden it altogether, on the page whose point
   is the grid. Cap the card at a quarter of the pane and let it scroll
   inside itself: the title still says how many are waiting, the New Users
   page carries the whole queue, and a short list keeps its natural height. */
.setpane:has(> .settable) > .card.pending { max-height: 25%; overflow-y: auto; }

/* every table fully ruled, like the workbook */
table.setgrid { border-collapse: collapse; }
table.setgrid th, table.setgrid td { border: 1px solid var(--grid); }
table.setgrid th { border-bottom-width: 2px; }
table.setgrid tbody tr:last-child td { border-bottom: 1px solid var(--grid); }

/* people: an area column says what it controls */
th.areacol { vertical-align: top; min-width: 120px; max-width: 180px;
  white-space: normal; }
.alabel { display: block; font-size: var(--t-sm); text-transform: none;
  letter-spacing: 0; color: var(--ink); }
.awhat { display: block; font-size: var(--t-xs); font-weight: 400; text-transform: none;
  letter-spacing: 0; color: var(--muted); line-height: 1.35; margin-top: 3px; }
th.pcol { min-width: 180px; }
.legend { display: inline-flex; gap: 6px; align-items: center; }
.pill { display: inline-block; font-size: var(--t-xs); font-weight: 600;
  padding: 2px 9px; border-radius: var(--r-pill); white-space: nowrap; }
.pill.w { background: var(--good-bg); color: var(--good); }
.pill.r { background: var(--neutral-bg); color: var(--neutral-ink); }
.pill.n { background: transparent; color: var(--muted); border: 1px dashed var(--grid); }
.pill.a { background: var(--ribbon); color: var(--on-ribbon); }

/* Belt and braces: even if this rail ends up inside a <nav> again, it stacks.
   The ribbon's global "nav { display:flex }" once laid all 33 items out in a
   row inside a 244px column, which reads as "Settings is missing everything". */
.setrail, nav.setrail {
  display: block !important;
  flex-direction: column;
  overflow-x: hidden !important;
  overflow-y: auto;
  gap: 0;
  align-items: stretch;
  scrollbar-width: thin;
}
.setrail > .setitem, .setrail > .setgroup { white-space: normal; }
.setrail::-webkit-scrollbar { display: block; width: 10px; }

/* Sign-ins that exist in Supabase and have never been given access here. */
.card.pending .natitle { font-size: var(--t-lg); font-weight: 600; margin-bottom: 6px; }
.card.pending .nabody { color: var(--muted); font-size: var(--t-md); line-height: 1.5; }
.card.pending { margin: 0 0 18px; padding: 18px 20px; }
.pendlist { display: flex; flex-direction: column; gap: 8px; margin-top: 12px; }
.pendrow { display: flex; align-items: center; gap: 12px; }
.pendmail { font-weight: 600; }
.pendrow .shelp { flex: 1; }

/* New Users draws its own pane instead of the rail-and-pane shell, so it has to
   carry the two things that shell was carrying for it. #view IS <main>, and
   main is overflow:hidden -- every page scrolls itself or it has no bottom,
   and a queue of sixty sign-ins had none. And the body is inset to the same
   26px .sethead already pads to; without that the list started flush left,
   26px adrift of the heading sitting directly above it. */
.nupane { height: 100%; overflow-y: auto; }
.nupane > .pendlist { margin: 12px 26px 0; }

/* Access carried over from the area grants, never set on this page. */
.inh { display: block; font-size: var(--t-xs); color: var(--muted); margin-top: 2px; }

/* people & access: the three hubs, blocked and ruled off ------------------
   The heavy rule is the whole point -- twenty-one columns in one undivided
   run is what made this screen hard to read. Which block a column sits in is
   decided by app.section_hub, never by a list here.
   It is an inset shadow, not a border, for the reason the pivot's TOTAL row
   gives in app.css: collapsed borders are painted by the table, not the cell,
   so a pinned header cell leaves its border behind at the row's layout
   position -- and now that this header pins (below), a 3px border on the
   band would vanish the moment anyone scrolled. The shadow paints with the
   cell, in place or in flight, and the body cells wear the same so the rule
   is one straight line from band to last row; the 1px grid line stays on the
   cell edge beside it. */
.setgrid.people th.hubstart, .setgrid.people td.hubstart {
  box-shadow: inset 3px 0 0 var(--ink-2); }
.setgrid.people thead th { position: sticky; top: 0; z-index: 2; }
/* TWO HEADER ROWS, ONE SCROLLPORT (the cdpivot precedent in app.css). Both
   rows were sticky at top: 0, so the moment the table box scrolled they
   pinned on top of each other, which is why the scroll-box rule above had to
   leave this grid out. State the band's height once and read the second
   row's offset from the same value, so the rows stack and the two numbers
   cannot disagree. A `height` on a cell is a minimum, and that is the safe
   direction: the band can never be SHORTER than the offset beneath it. The
   band's text is --t-sm at the page line-height, which does not follow the
   zoom the way the daily summary's does, so a constant is right here where
   it was wrong there; with no vertical padding the line sits well inside
   the token. border-box makes the declared height the drawn height rather
   than the height plus the rules; and the band row paints above the
   column-name row so that if an engine still adds a collapsed half-rule to
   the height, the seam is a hairline of overlap under the band, never a gap
   that body rows scroll through.
   The rule this replaces, th.hubhead at (0,1,1), lost its padding and its
   transparent ground to table.setgrid th at (0,1,2): the band was never
   transparent and never 4px 6px 3px, it wore the header ground at 9px 12px
   all along, and its other four declarations repeated the base. This one is
   scoped to win, and says the opaque ground out loud, because a sticky row
   that is not opaque has rows scrolling through it. */
.setgrid.people { --hubband-h: var(--s-7); }
.setgrid.people thead tr:first-child th { z-index: 3; }
/* THREE BANDS SINCE 9 OCTOBER 2026 (backlog 62): the business, the space, and
   the column. The rail has grouped this way since ADR-016 -- WDPL over Hub,
   Retail, Trading, Procurement and Management; BWY over Hub, CS and Retail --
   and the grid drew six flat blocks instead, so two WDPL columns both read
   "Settings" with nothing but "3 screens" against "1 screen" to tell them
   apart. Both bands are the same shape, so one rule sets them, and each row's
   offset is read from the one height above it -- the two-row note below still
   applies, with one more storey. */
.setgrid.people th.hubhead, .setgrid.people th.bizhead {
  height: var(--hubband-h); box-sizing: border-box;
  padding: 0 var(--s-3); background: var(--header); }
.setgrid.people thead tr:nth-child(2) th { top: var(--hubband-h); z-index: 2; }
.setgrid.people thead tr:nth-child(3) th { top: calc(var(--hubband-h) * 2); }
/* The business is the louder of the two: it is the button in the hub switch,
   and a space is a door inside it. */
.setgrid.people th.bizhead .hubname { font-weight: 700; }
.setgrid.people th.hubhead .hubname { font-weight: 500; color: var(--muted); }
/* A SPACE BOUNDARY IS THE LIGHTER RULE -- the heavy one (.hubstart, 3px of
   --ink-2) stays the business boundary, so the eye finds WDPL and BWY first
   and the spaces inside them second. Same inset-shadow device, same reason. */
.setgrid.people th.spacestart, .setgrid.people td.spacestart {
  box-shadow: inset 2px 0 0 var(--grid); }
/* THE HUB IN VIEW (22 Sep 2026, docs/PLAN-access-pulls-intraday.md 1).
   Thirty columns are five thousand pixels; a hub's name centred over its
   block sat off-screen and the columns read as one unlabelled run. Three
   answers: the name is a span that sticks to the left edge of the scroll
   box, just past the frozen columns, so it stays in view while its block
   scrolls under it; every column head carries its hub as a caption; and
   Person, Role and Group are frozen on the left. The offsets are the drawn
   widths of those three columns, measured after each paint (settings.js
   `measure`) and handed here as --pc1/2/3 on .settable. */
.setgrid.people th.hubhead, .setgrid.people th.bizhead { text-align: left; }
.setgrid.people th.hubhead .hubname, .setgrid.people th.bizhead .hubname {
  position: sticky; left: calc(var(--pc3, 0px) + var(--s-3)); display: inline-block; }
.setgrid.people th.areacol .ahub { display: block; font-size: var(--t-xs); font-weight: 400;
  text-transform: none; letter-spacing: 0; color: var(--muted); white-space: nowrap; }
.setgrid.people th.pcol, .setgrid.people tbody td:nth-child(-n+3) { position: sticky; background: var(--panel); }
.setgrid.people th.pcol { background: var(--header); }
.setgrid.people th.pcol:nth-child(1), .setgrid.people tbody td:nth-child(1) { left: 0; z-index: 2; }
.setgrid.people th.pcol:nth-child(2), .setgrid.people tbody td:nth-child(2) { left: var(--pc1, 0px); z-index: 2; }
.setgrid.people th.pcol:nth-child(3), .setgrid.people tbody td:nth-child(3) { left: var(--pc2, 0px); z-index: 2; }
/* above the column heads that scroll under them: (0,4,2) beats the
   nth-child rules' (0,4,1) above */
.setgrid.people thead th.pcol:nth-child(-n+3) { z-index: 4; }

/* One cell, one dropdown -- and the dropdown exists only while somebody is on
   the cell (backlog 25). The resting cell is .lvlpick, a span; it is styled
   with the select so that clicking one does not make the row twitch. */
.setgrid.people select.lvl,
.setgrid.people .lvlpick { font-size: var(--t-sm); padding: 2px 4px; border-radius: var(--r-sm);
  border: 1px solid var(--grid); background: transparent; color: var(--muted);
  max-width: 100%; }
.setgrid.people .lvlpick { display: inline-block; cursor: pointer;
  /* the select's own arrow gutter, so the text does not shift on the swap */
  padding-right: 18px; white-space: nowrap; }
.setgrid.people td.locked .lvlpick { cursor: default; opacity: .5; }
.setgrid.people select.lvl.lvl-read,
.setgrid.people .lvlpick.lvl-read  { background: var(--neutral-bg); color: var(--neutral-ink);
  border-color: transparent; font-weight: 600; }
.setgrid.people select.lvl.lvl-write,
.setgrid.people .lvlpick.lvl-write { background: var(--good-bg); color: var(--good);
  border-color: transparent; font-weight: 600; }
.setgrid.people select.lvl:disabled { opacity: .5; }
.setgrid.people select.gpick { font-size: var(--t-sm); padding: 2px 4px; max-width: 130px; }

.peoplefilt { gap: 8px; }
.peoplefilt input[type=search] { min-width: 220px; }

/* PICKED, NOT YET SAVED. A cell that Save would change wears the warning
   ground the view-only badge and the administrator note already wear:
   --warn is state, and "not saved yet" is a state, not decoration. The tint
   is on the cell rather than the dropdown, so the read/write colour the
   dropdown carries stays legible inside it, and a pick of "none" (whose
   dropdown has no ground of its own) still shows. Stated at four classes so
   it beats the row-hover ground -- a hovered row must not hide what is
   pending -- and the hub rule is restated on the cell that carries it,
   because a second box-shadow replaces the first rather than adding to it. */
.setgrid.people td.pend { background: var(--warn-bg);
  box-shadow: inset 0 0 0 1px var(--warn-edge); }
.setgrid.people td.pend.hubstart { box-shadow: inset 3px 0 0 var(--ink-2),
  inset 0 0 0 1px var(--warn-edge); }
/* ON A GROUP. The cell is read, not written: the dropdown is disabled (the
   .5 it already wears when disabled) and the cell says why on hover. */
.setgrid.people td.locked { cursor: not-allowed; }
/* the count between Discard and Save, in the same ground as the cells */
.pill.unsaved { background: var(--warn-bg); color: var(--warn);
  border: 1px solid var(--warn-edge); }
/* a row the server named as one it could not save: a keel in --bad on the
   name, like the hub rule, so the eye finds it in eighty rows */
.setgrid.people tr.failed td:first-child { box-shadow: inset 3px 0 0 var(--bad);
  background: var(--bad-bg); }
/* the line beside Save in the group editor, saying whom it will rewrite */
.setedit > footer .savenote { flex: 1; font-size: var(--t-sm); color: var(--muted);
  line-height: 1.4; }

/* groups */
.grouplist { display: flex; flex-direction: column; gap: 6px; }
.grouprow { display: flex; align-items: center; gap: 8px;
  border: 1px solid var(--grid); border-radius: var(--r-md); padding: 8px 10px; }
.grouprow > div:first-child { flex: 1; }
.presethub { margin: 12px 0 4px; font-size: var(--t-sm); font-weight: 700;
  letter-spacing: .04em; text-transform: uppercase; color: var(--ink-2);
  border-bottom: 2px solid var(--ink-2); padding-bottom: 3px; }
.presetrow { display: flex; align-items: center; justify-content: space-between;
  gap: 10px; padding: 3px 0; }
.presetrow select { min-width: 120px; }

/* ------------------------------------------------------- sections board --
   Settings > Tabs since sql/171 (5 Sep): the three Tabs pages open on the
   board in public/sections.js, which keeps this file's rail-and-pane shell
   and adds one thing above it -- a band that says what is unsaved and holds
   the one Save. The band is on --panel with --shadow-1 because it is the one
   thing on the screen that floats over what scrolls beneath it; everything
   else separates with a hairline, as the rest of Settings does. Tokens only:
   every colour here is a palette token, so both themes and all three hub
   liveries come for free. The drag look is .corder's (app.css): the same
   opacity while dragging, the same --accent rule where a row will land, and
   one addition -- .dropinto, a whole row lit in --accent-soft, because a tab
   landing IN a section is a different act from a row landing BEFORE one and
   the two must not read alike. */
.boardwrap { display: flex; flex-direction: column; height: 100%; min-height: 0; }
.boardwrap > .setwrap { flex: 1; min-height: 0; }
.boardband { flex: none; display: flex; align-items: center; gap: var(--s-4); flex-wrap: wrap;
  padding: var(--s-5) 26px; background: var(--panel); border-bottom: 1px solid var(--line);
  box-shadow: var(--shadow-1); position: relative; z-index: 1; }
.boardband h2 { margin: 0; font-size: var(--t-xl); letter-spacing: -.01em; }
.boardband .tally { font-size: var(--t-md); color: var(--muted); }
/* unsaved is a state, and it wears the state colour the People & Access
   pending cells and the view-only badge already wear */
.boardband .tally.dirty { color: var(--warn); font-weight: 600; }
.boardband .spacer { flex: 1; }
.boardband .bmsg { flex: 1 1 100%; font-size: var(--t-md); color: var(--bad); line-height: 1.5; }
.boardband .bmsg .btn { margin-left: var(--s-4); }

/* the rail needs room for a name, two counts and a control on one row */
.boardwrap .setrail { width: 330px; }
.secrow { display: flex; align-items: center; gap: var(--s-3); flex-wrap: wrap; width: 100%;
  border: 1px solid transparent; border-radius: var(--r-md); padding: var(--s-3) var(--s-4);
  margin-bottom: var(--s-1); cursor: pointer; background: 0; color: var(--ink); }
.secrow:hover { background: var(--row-hover); }
.secrow.on { background: var(--accent-soft); }
.secrow.dragging { opacity: .45; }
.secrow.dropmark { border-top: 2px solid var(--accent); }
.secrow.dropinto { border-color: var(--accent); background: var(--accent-soft); }
.secrow.retiring { opacity: .55; }
.secrow.retiring .seclabel { text-decoration: line-through; }
/* the name is an input that looks like text until it is pointed at, so the
   rail reads as a list and still renames in place */
.seclabel { flex: 1 1 120px; min-width: 0; font: inherit; font-size: var(--t-base); font-weight: 600;
  padding: 2px 6px; border: 1px solid transparent; border-radius: var(--r-sm);
  background: transparent; color: var(--ink); }
.seclabel:hover, .seclabel:focus { border-color: var(--line); background: var(--bg); outline: 0; }
.seclabel:focus { outline: 2px solid var(--cursor); outline-offset: -1px; border-color: transparent; }
.secrow.on .seclabel { color: var(--accent); }
.secsub { flex: 1 1 100%; display: flex; align-items: center; gap: var(--s-4); flex-wrap: wrap;
  font-size: var(--t-sm); color: var(--muted); padding-left: 30px; }
.secsub .btn { font-size: var(--t-sm); padding: 1px 7px; }
.secsub .retiring-note { color: var(--warn); font-weight: 600; }
.pill.new { background: var(--good-bg); color: var(--good); }

/* + Add section, at the foot of the rail */
.secadd { display: flex; flex-direction: column; gap: var(--s-3); margin-top: var(--s-6);
  padding: 0 var(--s-4) var(--s-4); border-top: 1px solid var(--line); }
.secadd .setgroup { padding-left: 0; padding-right: 0; }
.secadd input, .secadd select { width: 100%; padding: 5px 8px; font: inherit; font-size: var(--t-md);
  border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--bg); color: var(--ink); }
.secadd input:focus, .secadd select:focus { outline: 2px solid var(--cursor); outline-offset: -1px;
  border-color: transparent; }
.secadd .btn { align-self: flex-start; }
.secretired { display: block; padding: var(--s-4); font-size: var(--t-sm); color: var(--muted);
  line-height: 1.5; }
.secretired .setgroup { padding: 0 0 var(--s-1); }

/* the pane's rows reuse .corder-row; the label is text here, not an input,
   because names belong to the other page */
.corder-text { flex: 1; min-width: 0; font-size: var(--t-md); padding: 3px 8px; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.corder-moveto { flex: none; max-width: 190px; font-size: var(--t-sm); padding: 2px 4px;
  border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--bg); color: var(--ink); }
/* a tab in no section: dashed, like a pill for "none" */
.corder-row.stray { border-style: dashed; }

/* Settings > Tabs: the Phone tick (sql/173), listed in the phone drawer. The
   Tabs page is a laptop screen (a LAPTOP_KIND), so this is sized for a mouse;
   flex: none keeps the flex row from squeezing the box. */
.corder-phone { flex: none; width: 18px; height: 18px; margin: 0 4px; }
