The deliberate mobile pass the original proposal never had. Driven page by page at 390px with mobile emulation (the media queries under test actually fire) by NEW tests/mobile_check.py, 24/24: - no page scrolls sideways - all seven (the creator joined at T9.5 when BL-001 died) - no visible control is clipped past the viewport (the probe learned frame_check's two lessons: an off-canvas drawer is PARKED, not clipped, and a row inside an overflow-x container is scrollable) - tap targets: the shared coarse-pointer block in wp-chrome.css puts every button, input, select, nav link and appbar control at a 44px minimum on phone widths and coarse pointers; checkboxes, radios and help-tip badges get the 24px WCAG floor with spacing doing the rest. Field View - the gloved-hands surface - measures 44px on EVERY control. Inline text links are exempt per WCAG 2.5.8's own exception. Even the deliberately unobtrusive dev toggle grew to the floor: subtle by opacity, not by size. - CR-007 attachments offline at 390px and T8.5 requests at 390px were already pinned by files_check and mreq_check; this pass cites rather than repeats. After-screenshots for all seven pages at 390px are committed in docs/reference/baseline/after-wave9, beside the wave 0 set, captured by the same baseline_shots.py fixture. Verification (each probe run alone): NEW tests/mobile_check.py 24/24. Regressions: form_structure_check 50/51 (BL-022's standing question), files_check 36/36. Items: C2 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
222 lines
17 KiB
CSS
222 lines
17 KiB
CSS
/* Shared styling for the suite's dense admin pages — the Admin Console and the
|
|
User Directory. Both are mostly tables and toolbars, which is a different job
|
|
from the wizard pages, so they carry this sheet instead of theme-light.css's
|
|
form-heavy one. The palette, the square corners and the type are still Carbon's,
|
|
so the pages read as one product with the rest of the suite.
|
|
|
|
Two scales do all the spacing and all the control sizing; nothing that uses this
|
|
sheet should invent its own. Page-specific rules (per-ID scroll boxes, column
|
|
exceptions) stay in the page that owns them.
|
|
|
|
══ TOKENS ══════════════════════════════════════════════════════════════════
|
|
Names only. Every value comes from theme-light.css, which every page loads
|
|
first — this sheet declares nothing of its own (T3.2 / S5 / C3). The names
|
|
stay because admin.js and users.js read 21 of them from JavaScript, where a
|
|
rename fails silently: no build error, no console warning, just an unstyled
|
|
element. See docs/reference/tokens.md section 9. */
|
|
:root{ --bg:var(--cds-background); --surface:var(--cds-layer); --border:var(--cds-border-subtle);
|
|
--border-strong:var(--cds-border-strong); --text:var(--cds-text-primary);
|
|
--muted:var(--cds-text-secondary); --dim:var(--cds-text-helper); --accent:var(--cds-interactive-01);
|
|
--accent-hover:var(--cds-hover-primary); --accent-soft:var(--cds-highlight);
|
|
--green:var(--cds-support-success); --green-bg:var(--wp-status-success-bg);
|
|
--red:var(--cds-support-error); --red-bg:var(--wp-status-error-bg);
|
|
--amber:var(--wp-status-warning-text); --amber-bg:var(--wp-status-warning-bg);
|
|
--head-bg:var(--cds-layer-accent);
|
|
/* --zebra is six points lighter than --head-bg, not equal to it: collapsing
|
|
the two erases the striping on a nine-column table, which is the one place
|
|
striping is load-bearing. --row-hover is deliberately NOT --accent-soft;
|
|
see the note above table.grid tbody tr:hover. Both are one-offs and both
|
|
are named in docs/reference/tokens.md section 8-A/8-B. */
|
|
--zebra:var(--wp-table-zebra); --row-hover:var(--wp-table-row-hover);
|
|
/* The narrow mono stack, kept as-is: widening it changes the rendered face on
|
|
any machine without IBM Plex Mono installed, and this sheet's two pages are
|
|
the ones a font change would show up on. T3.5 picks one stack (8-H). */
|
|
--mono:var(--wp-font-mono-2);
|
|
--s1:var(--wp-s1); --s2:var(--wp-s2); --s3:var(--wp-s3);
|
|
--s4:var(--wp-s4); --s5:var(--wp-s5); --s6:var(--wp-s6);
|
|
--ctl:var(--wp-ctl); /* every button / input / select that sits in a form row */
|
|
--ctl-sm:var(--wp-ctl-sm); } /* every control that sits inside a table cell */
|
|
*{ box-sizing:border-box; }
|
|
body{ margin:0; font-family:var(--wp-font-sans-2); background:var(--bg); color:var(--text); }
|
|
|
|
/* ══ PAGE ══════════════════════════════════════════════════════════════════════
|
|
1240px, not 860: the user table is nine columns wide and at 860 it spilled
|
|
straight out of its own white card. Wide enough for that table, still a
|
|
readable measure for the prose, which is capped separately. */
|
|
.wrap{ max-width:1240px; margin:0 auto; padding:var(--s6) var(--s5) 80px; }
|
|
h1{ font-size:20px; line-height:1.2; margin:0 0 2px; }
|
|
.sub{ color:var(--muted); font-size:13px; line-height:1.5; margin:0 0 var(--s3); max-width:96ch; }
|
|
a.home{ color:var(--accent); font-size:13px; text-decoration:none; white-space:nowrap; }
|
|
a.home:hover{ text-decoration:underline; }
|
|
|
|
/* ══ CARDS ═════════════════════════════════════════════════════════════════════ */
|
|
.card{ background:var(--surface); border:1px solid var(--border); border-radius:0;
|
|
padding:var(--s4) var(--s5) var(--s5); margin-bottom:var(--s4); }
|
|
/* One card header everywhere: small uppercase accent label on a hairline. The
|
|
scripts also emit h2 for sub-sections inside a card with an inline margin-top —
|
|
the same treatment reads correctly as a divider there, so both get it. */
|
|
.card h2{ font-size:12px; font-weight:600; letter-spacing:.08em; text-transform:uppercase;
|
|
color:var(--accent); margin:0 0 var(--s3); padding-bottom:var(--s2); border-bottom:1px solid var(--border); }
|
|
.wrap code{ font-family:var(--mono); font-size:.92em; background:var(--bg); padding:1px 4px; }
|
|
|
|
/* ══ CONTROLS ══════════════════════════════════════════════════════════════════
|
|
Every button, input and select in a form row is exactly --ctl tall, so a
|
|
toolbar is one clean band instead of a ragged one. */
|
|
button{ font:inherit; font-size:13px; font-weight:600; line-height:1; white-space:nowrap;
|
|
height:var(--ctl); padding:0 var(--s3); border-radius:0; cursor:pointer;
|
|
border:1px solid var(--wp-btn-secondary-border); background:var(--wp-btn-secondary-bg); color:var(--wp-btn-secondary-fg); }
|
|
button:hover{ border-color:var(--wp-btn-secondary-hover-fg); color:var(--wp-btn-secondary-hover-fg); }
|
|
/* S12: this was outline-offset:-3px — an INSET accent ring, which on button.primary
|
|
is a blue ring drawn inside a blue button and measures 1.00:1. Outside now, where
|
|
it lands on the card behind the toolbar. The filled variants are handled by the
|
|
rule in theme-light.css, which offsets further to clear their own fill. */
|
|
button:focus-visible{ outline:2px solid var(--accent); outline-offset:1px; }
|
|
button:disabled, button:disabled:hover{ color:var(--cds-text-disabled); border-color:var(--border); background:var(--surface); cursor:default; }
|
|
button.primary{ background:var(--wp-btn-primary-bg); border-color:var(--wp-btn-primary-bg); color:var(--wp-btn-primary-fg); }
|
|
button.primary:hover{ background:var(--wp-btn-primary-hover); border-color:var(--wp-btn-primary-hover); color:var(--wp-btn-primary-fg); }
|
|
button.danger{ border-color:var(--wp-btn-danger-border); color:var(--wp-btn-danger-fg); }
|
|
button.danger:hover{ background:var(--wp-btn-danger-soft-bg); border-color:var(--wp-btn-danger-border); color:var(--wp-btn-danger-fg); }
|
|
.row{ display:flex; gap:var(--s2); flex-wrap:wrap; align-items:center; }
|
|
/* The filter / search / button strip at the top of a card. */
|
|
.toolbar{ display:flex; gap:var(--s2); flex-wrap:wrap; align-items:center; margin:0 0 var(--s3); }
|
|
.toolbar + .banner{ margin-top:0; }
|
|
.urow{ display:flex; gap:var(--s2); flex-wrap:wrap; align-items:center; }
|
|
/* Checkboxes are excluded: they are drawn by the platform and want none of a
|
|
text field's height, padding or border. */
|
|
.toolbar input:not([type=checkbox]), .toolbar select,
|
|
.urow input:not([type=checkbox]), .urow select{
|
|
height:var(--ctl); padding:0 var(--s2); font:inherit; font-size:13px; line-height:normal;
|
|
border:1px solid var(--border-strong); border-radius:0; background:var(--surface); color:var(--text); }
|
|
.toolbar select, .urow select{ cursor:pointer; padding-right:var(--s1); }
|
|
.toolbar input:focus-visible, .toolbar select:focus-visible,
|
|
.urow input:focus-visible, .urow select:focus-visible{ outline:2px solid var(--accent); outline-offset:-2px; }
|
|
.toolbar > input{ flex:1 1 240px; min-width:150px; }
|
|
.urow input:not([type=checkbox]){ flex:1 1 140px; min-width:0; }
|
|
/* Inline checkbox + label, sized to sit on the same line as the buttons. */
|
|
.chk{ display:inline-flex; align-items:center; gap:var(--s2); height:var(--ctl); padding:0 var(--s1);
|
|
font-size:13px; color:var(--muted); white-space:nowrap; cursor:pointer; }
|
|
.chk input{ width:16px; height:16px; margin:0; accent-color:var(--accent); cursor:pointer; }
|
|
|
|
/* ══ FEEDBACK: banners, notes, console output, key/value ════════════════════════ */
|
|
.banner{ margin:var(--s3) 0 0; padding:9px var(--s3); border-radius:0; font-size:13px; font-weight:600;
|
|
line-height:1.4; border:1px solid var(--border); border-left:3px solid var(--border-strong);
|
|
background:var(--surface); color:var(--text); }
|
|
.banner.ok{ background:var(--green-bg); color:var(--green); border-color:var(--wp-status-success-border-a); border-left-color:var(--green); }
|
|
.banner.bad{ background:var(--red-bg); color:var(--red); border-color:var(--wp-status-error-border-a); border-left-color:var(--red); }
|
|
.banner.warn{ background:var(--amber-bg); color:var(--amber); border-color:var(--wp-status-warning-border-a); border-left-color:var(--amber); }
|
|
/* This used to read --muted rather than --dim, because --dim was #8d8d8d and
|
|
measured 3.3:1 on white — under the floor at 12px. S11 (T4.6) fixed --dim at the
|
|
source instead, so the local override is gone and helper text on these pages is
|
|
the same colour as helper text everywhere else. Re-measured: 5.02:1 on white,
|
|
4.81:1 on the zebra stripe, 4.57:1 on a shaded card. */
|
|
.note{ font-size:12px; line-height:1.55; color:var(--dim); margin-top:var(--s2); }
|
|
.note strong, .note em{ color:var(--text); }
|
|
pre.out{ background:var(--wp-term-bg); color:var(--wp-term-fg); border-radius:0; padding:var(--s3) var(--s4); font-family:var(--mono);
|
|
font-size:12px; line-height:1.55; white-space:pre-wrap; max-height:340px; overflow:auto; margin:var(--s3) 0 0; }
|
|
pre.out .p{ color:var(--wp-term-pass); font-weight:700; } pre.out .f{ color:var(--wp-term-fail); font-weight:700; }
|
|
table.kv{ border-collapse:collapse; font-size:13px; margin-top:var(--s2); }
|
|
table.kv th{ text-align:left; padding:var(--s1) var(--s5) var(--s1) 0; color:var(--muted); font-weight:600; white-space:nowrap; }
|
|
table.kv td{ padding:var(--s1) 0; font-variant-numeric:tabular-nums; font-weight:700; color:var(--text); }
|
|
|
|
/* ══ DATA TABLES ═══════════════════════════════════════════════════════════════
|
|
table.users is the name admin.js already emits; table.grid is the same object
|
|
under the shared name. One rule set serves both, so existing markup picks up the
|
|
dense styling without being rewritten. border-collapse is separate rather than
|
|
collapse because a collapsed border does not travel with a sticky header. */
|
|
table.grid, table.users{ width:100%; border-collapse:separate; border-spacing:0;
|
|
font-size:13px; color:var(--text); background:var(--surface); }
|
|
table.grid th, table.users th{ position:sticky; top:0; z-index:2; background:var(--head-bg);
|
|
text-align:left; padding:var(--s2) var(--s3); white-space:nowrap;
|
|
font-size:11px; font-weight:600; letter-spacing:.04em; text-transform:uppercase; color:var(--muted);
|
|
box-shadow:inset 0 -1px 0 var(--border); }
|
|
/* Cells never wrap: a wrapped cell turns one user into a 100px tall band and the
|
|
table stops reading as rows. Anything genuinely long truncates (.ell) or is
|
|
exempted by name in the page that owns the table. */
|
|
table.grid td, table.users td{ padding:var(--s1) var(--s3); border-bottom:1px solid var(--border);
|
|
vertical-align:middle; white-space:nowrap; }
|
|
table.grid tbody tr:last-child td, table.users tbody tr:last-child td{ border-bottom:none; }
|
|
table.grid tbody tr:nth-child(even) td, table.users tbody tr:nth-child(even) td{ background:var(--zebra); }
|
|
/* A neutral hover, not --accent-soft: that is .tag.admin's fill, and an "all
|
|
projects" pill sitting on its own colour disappears the moment you hover it. */
|
|
table.grid tbody tr:hover td, table.users tbody tr:hover td{ background:var(--row-hover); }
|
|
/* A row for an account this caller may see but not change. Dimmed as a whole so
|
|
the disabled controls aren't the only clue. */
|
|
table.grid tbody tr.is-locked td, table.users tbody tr.is-locked td{ color:var(--muted); }
|
|
/* Truncation has to hang off a block INSIDE the cell. max-width on a <td> is
|
|
advisory under table-layout:auto — the cell just grows to fit and the ellipsis
|
|
never appears, which is the usual reason this trick looks like it works in the
|
|
stylesheet and doesn't on the page. The scripts emit <td class="ell"><span>. */
|
|
.ell{ max-width:240px; }
|
|
.ell > span{ display:block; max-width:240px; overflow:hidden; text-overflow:ellipsis;
|
|
white-space:nowrap; }
|
|
/* Every action cell the scripts render is a .cellactions, and it must not wrap:
|
|
unwrapped, the three buttons stack and the row grows fourfold. */
|
|
.cellactions{ display:flex; flex-wrap:nowrap; align-items:center; gap:var(--s1); white-space:nowrap; }
|
|
/* Controls that live in a cell are one step smaller, which is what keeps a row at
|
|
~34px instead of ~100px. .chk is form-row sized by default, so it needs saying
|
|
again here or checkbox rows stand 6px taller than the rest. */
|
|
button.mini{ height:var(--ctl-sm); padding:0 var(--s2); font-size:12px; }
|
|
table.grid td .chk, table.users td .chk{ height:var(--ctl-sm); }
|
|
select.role-select{ height:var(--ctl-sm); max-width:170px; padding:0 var(--s1) 0 var(--s2);
|
|
font:inherit; font-size:12px; border:1px solid var(--border-strong); border-radius:0;
|
|
background:var(--surface); color:var(--text); cursor:pointer; }
|
|
select.role-select:hover{ border-color:var(--accent); }
|
|
select.role-select.is-admin{ color:var(--accent); border-color:var(--accent); font-weight:600; }
|
|
select.role-select:disabled{ color:var(--cds-text-disabled); border-color:var(--border); background:var(--bg); cursor:default; }
|
|
.tag{ display:inline-block; padding:1px 8px; border-radius:11px; font-size:11px; font-weight:600;
|
|
line-height:1.55; white-space:nowrap; vertical-align:middle; }
|
|
.tag.admin{ background:var(--accent-soft); color:var(--accent); }
|
|
.tag.super{ background:var(--wp-tag-super-bg); color:var(--wp-tag-super-text); }
|
|
.tag.user{ background:var(--cds-layer-hover); color:var(--muted); }
|
|
.tag.on{ background:var(--green-bg); color:var(--green); }
|
|
.tag.off{ background:var(--red-bg); color:var(--red); }
|
|
.tag.archived{ background:var(--amber-bg); color:var(--amber); }
|
|
.me-tag{ font-size:11px; color:var(--dim); margin-left:6px; white-space:nowrap; }
|
|
|
|
/* A wide table scrolls inside its own box so the page never scrolls sideways, and
|
|
the capped height is what gives the sticky header something to do. */
|
|
.tscroll{ overflow:auto; max-height:min(70vh,640px); overscroll-behavior:contain; }
|
|
|
|
/* ══ MODALS ════════════════════════════════════════════════════════════════════
|
|
The project-access dialog, shared by both pages. */
|
|
.modal-ov{ position:fixed; inset:0; background:var(--wp-scrim-cool-modal); display:flex; align-items:center;
|
|
justify-content:center; z-index:10002; padding:var(--s5); }
|
|
.modal-box{ background:var(--surface); border-radius:0; max-width:660px; width:100%; max-height:82vh;
|
|
display:flex; flex-direction:column; overflow:hidden; box-shadow:var(--wp-shadow-modal); }
|
|
.modal-head{ padding:var(--s3) var(--s4); border-bottom:1px solid var(--border); font-weight:700; }
|
|
.modal-body{ padding:var(--s3) var(--s4); overflow:auto; }
|
|
.modal-foot{ padding:var(--s3) var(--s4); border-top:1px solid var(--border);
|
|
display:flex; gap:var(--s2); justify-content:flex-end; }
|
|
.pickrow{ display:flex; align-items:center; gap:var(--s3); padding:var(--s2) var(--s1);
|
|
border-bottom:1px solid var(--border); font-size:13px; }
|
|
.pickrow:last-child{ border-bottom:none; }
|
|
.pickrow > label{ display:flex; align-items:center; gap:var(--s2); flex:1; min-width:0; cursor:pointer; }
|
|
.pickrow > label > span{ overflow:hidden; text-overflow:ellipsis; }
|
|
|
|
/* ══ GATES & WARNINGS ══════════════════════════════════════════════════════════ */
|
|
.gate-overlay{ position:fixed; inset:0; background:var(--bg); display:flex; align-items:center; justify-content:center; padding:var(--s5); z-index:9999; }
|
|
.gate-box{ background:var(--surface); border:1px solid var(--border); border-radius:0; padding:var(--s6); max-width:380px; width:100%; box-shadow:var(--wp-shadow-gate); }
|
|
.gate-box h2{ margin:0 0 var(--s1); padding:0; border:0; font-size:17px; text-transform:none; letter-spacing:0; color:var(--text); }
|
|
.gate-box p{ color:var(--muted); font-size:13px; margin:0 0 var(--s4); }
|
|
.gate-msg{ color:var(--red); font-size:12px; min-height:16px; margin-bottom:var(--s2); }
|
|
.secwarn{ background:var(--amber-bg); color:var(--amber); border:1px solid var(--amber); border-radius:0; padding:9px 13px; font-size:12px; margin-bottom:var(--s4); }
|
|
|
|
/* ══ NARROW SCREENS ════════════════════════════════════════════════════════════
|
|
The page itself must never scroll sideways; the wide tables scroll inside their
|
|
own box instead, and there they get the full page height to do it. */
|
|
@media (max-width:900px){
|
|
.wrap{ padding:var(--s4) var(--s3) 60px; }
|
|
.card{ padding:var(--s3) var(--s4) var(--s4); }
|
|
.toolbar > input{ flex:1 1 100%; }
|
|
.tscroll{ max-height:none; }
|
|
}
|
|
@media (max-width:620px){
|
|
.urow input, .urow select, .urow button{ flex:1 1 100%; }
|
|
}
|
|
|
|
/* C2 / T9.6: the console header links are standalone targets, not inline text,
|
|
so they meet the touch floor at coarse pointers / phone widths. */
|
|
@media (max-width: 500px), (pointer: coarse) {
|
|
a.home { min-height: 44px; display: inline-flex; align-items: center; }
|
|
}
|