loopable / web /src /shell /navExtras.css
fsanyoto's picture
Deploy AIOS web (React glide grid + FastAPI slice)
ef68ae0 verified
Raw
History Blame Contribute Delete
15 kB
/* shell/navExtras.css — C-SCHEMA (2026-08-02): nav folders, three-dots, schema drawer.
New classes only; the shell's own rail classes stay in index.css untouched. */
.shell-nav-row {
position: relative;
display: flex;
align-items: stretch;
min-width: 0;
/* wave17 SHELL (item 12) — the row is the painted surface now, so it needs
the shape the `<a>` used to draw. `--lp-r-sm` and not the Views rail's
`--lp-r-md`: the tint must land exactly where the item's hover pill lands
today, and every other pill in this rail is 4px. Item 12 asks the highlight
to reach the ⋯; it does not ask the nav to change shape. */
border-radius: var(--lp-r-sm);
}
/* The ROW carries hover and current-state, exactly as `.cg-view-row` does in
the Views rail — which is the whole of item 12. Hovering the three-dots now
lights the row it belongs to instead of leaving the link beside it cold. */
.shell-nav-row:hover {
background: var(--lp-surface-2);
}
.shell-nav-row.is-active {
background: var(--lp-blue-tint);
}
.shell-nav-row > .shell-nav-item {
flex: 1 1 auto;
min-width: 0;
}
/* ⚠ LOAD-BEARING, not tidiness. `.shell-nav-item:hover` still paints its own
grey — it must, because the AI-assistant row is a bare `.shell-nav-item`
with no row around it. Left alone inside a row it would paint that grey
OVER the blue of the current database the moment the pointer crossed the
label: the link half would go grey while the ⋯ half stayed blue. The child
selector outranks it (0,3,0 over 0,2,0), so this holds no matter which
stylesheet the bundler emits first — the nav has lost a rule to source
order before ([[loopable-nav-logo-toggle]]) and specificity is the fix that
does not depend on being lucky. */
.shell-nav-row > .shell-nav-item:hover {
background: transparent;
}
.shell-nav-row > .shell-dots,
.shell-nav-folder > .shell-dots {
flex: 0 0 auto;
width: 24px;
border: 0;
padding: 0;
margin: 2px 2px 2px 0;
border-radius: 6px;
background: transparent;
color: var(--lp-muted);
cursor: pointer;
opacity: 0;
display: grid;
place-items: center;
}
.shell-nav-row:hover > .shell-dots,
.shell-nav-row:focus-within > .shell-dots,
.shell-nav-folder:hover > .shell-dots,
.shell-nav-folder:focus-within > .shell-dots {
opacity: 1;
}
.shell-nav-row > .shell-dots:hover,
.shell-nav-folder > .shell-dots:hover {
background: var(--lp-wash);
color: var(--lp-ink);
}
.shell-dots-icon {
width: 14px;
height: 14px;
fill: currentColor;
}
.shell-nav-row.is-foldered > .shell-nav-item {
padding-left: 30px;
}
/* ── folder heads ─────────────────────────────────────────────────────────── */
.shell-nav-folder {
display: flex;
align-items: stretch;
min-width: 0;
}
.shell-nav-folderbtn {
flex: 1 1 auto;
min-width: 0;
display: flex;
align-items: center;
gap: 7px;
border: 0;
background: transparent;
padding: 6px 8px;
border-radius: 7px;
color: var(--lp-ink);
font: inherit;
font-size: var(--lp-fs-xs);
/* Wave 14 R3 — the Views-rail folder look: BOLD label, no chevron. */
font-weight: 600;
cursor: pointer;
text-align: left;
}
.shell-nav-folderbtn:hover {
background: var(--lp-wash);
}
.shell-nav-foldercount {
margin-left: auto;
/* Wave 14 item 7 — the count wears the LABEL's size, muted; nothing "all over the
place with regards to symmetry".
⚠ wave17 SHELL (item 11b) SUPERSEDES THE SIZE HALF. Wave 14 matched the count
to the label so the row would not look ragged; at the label's own size, next
to a 600-weight name, it stopped reading as an annotation and started reading
as a second piece of the title. Smaller is what makes it recede.
The COLOUR TOKEN IS UNCHANGED on purpose: `--lp-muted` already IS the grey,
and the same owner item asks the Views rail's `cg-fold-count` for the same
treatment. A lighter grey invented here would need a literal that has nowhere
legal to live, and would put the two rails' counts a shade apart — which is
the exact symmetry complaint wave 14 was answering. Shrinking the type does
the lightening. */
font-size: var(--lp-fs-3xs);
font-weight: 400;
color: var(--lp-muted);
/* Counts line up column-wise as folders open and close, in both rails. */
font-variant-numeric: tabular-nums;
}
/* ── wave 14 C-NAVFOLD: drag placement (items 4/6) ───────────────────────── */
.shell-nav-row.is-dragging {
opacity: 0.45;
}
.shell-nav-folder.is-drop {
background: var(--lp-blue-tint);
border-radius: 7px;
box-shadow: inset 0 0 0 1px var(--lp-blue-deep);
}
.shell-nav-list.is-drop-root {
border-radius: 9px;
box-shadow: inset 0 0 0 1px var(--lp-line);
}
.shell-newfolder {
display: block;
width: 100%;
border: 0;
background: transparent;
padding: 6px 8px;
margin-top: 2px;
border-radius: 7px;
font: inherit;
font-size: var(--lp-fs-2xs);
color: var(--lp-muted);
text-align: left;
cursor: pointer;
white-space: nowrap;
}
.shell-newfolder:hover {
background: var(--lp-wash);
color: var(--lp-ink);
}
/* WAVE 19 R11 — the same row in the folded rail: the "+" alone, centred in the
56px strip, opening the rail rather than a popover it has no room for. */
.shell-newfolder.is-collapsed {
display: grid;
place-items: center;
padding: 6px 0;
}
.shell-newthing-plus {
width: 16px;
height: 16px;
fill: none;
stroke: currentColor;
stroke-width: 1.5;
stroke-linecap: round;
}
.shell-newfolder-form {
padding: 4px 2px 2px;
}
/* ── the fixed popover menu ───────────────────────────────────────────────── */
.shell-navmenu {
position: fixed;
z-index: 80;
min-width: 196px;
max-width: 240px;
padding: 5px;
border: 1px solid var(--lp-line);
border-radius: 9px;
background: var(--lp-surface);
box-shadow: 0 10px 34px rgba(20, 30, 43, 0.16);
font-size: var(--lp-fs-xs);
}
.shell-navmenu-item {
display: flex;
align-items: center;
gap: 8px;
width: 100%;
border: 0;
background: transparent;
padding: 6px 8px;
border-radius: 6px;
font: inherit;
color: var(--lp-ink);
cursor: pointer;
text-align: left;
/* Wave 14 R7 — every menu action occupies ONE line, app-wide. */
white-space: nowrap;
}
.shell-navmenu-item:hover {
background: var(--lp-wash);
}
.shell-navmenu-item.is-current {
color: var(--lp-muted);
cursor: default;
}
.shell-navmenu-item.is-danger {
color: var(--lp-red-deep);
}
/* A secondary action inside a picker, not a menu row in its own right. */
.shell-navmenu-item.is-quiet {
margin-top: 2px;
font-size: var(--lp-fs-3xs);
color: var(--lp-muted);
}
/* ── WAVE 19 R8 / C1: the database icon picker ─────────────────────────────── */
.shell-navmenu-pick {
padding: 4px 3px 3px;
}
/* WRAPS on purpose: twelve 26px swatches is ~312px and the menu is capped at
240 (a popover wider than the rail it hangs off reads as a panel that has
come loose). Two rows of six is the shape that falls out of the cap, and the
tone row below it is five — so the block reads as "shape, then colour"
without a heading having to say so. */
.shell-navmenu-pickrow {
display: flex;
flex-wrap: wrap;
gap: 2px;
}
.shell-navmenu-pickrow + .shell-navmenu-pickrow {
margin-top: 4px;
padding-top: 5px;
border-top: 1px solid color-mix(in srgb, var(--lp-line) 55%, transparent);
}
.shell-navmenu-swatch {
flex: 0 0 auto;
display: grid;
place-items: center;
width: 26px;
height: 26px;
border: 1px solid transparent;
border-radius: 6px;
background: transparent;
padding: 0;
font: inherit;
cursor: pointer;
}
.shell-navmenu-swatch:hover {
background: var(--lp-wash);
}
/* The current choice is marked by its OUTLINE, never by a fill: the swatch's
whole job is to show the mark in its real colours, and a tinted plate behind
a pastel glyph changes the thing it is previewing. */
.shell-navmenu-swatch.is-on {
border-color: var(--lp-blue-deep);
}
.shell-navmenu-swatch:focus-visible {
outline: 2px solid var(--lp-blue-deep);
outline-offset: -2px;
}
.shell-navmenu-tick {
margin-left: auto;
font-size: var(--lp-fs-3xs);
color: var(--lp-muted);
}
.shell-navmenu-kicker {
padding: 7px 8px 3px;
font-size: var(--lp-fs-3xs);
font-weight: 600;
color: var(--lp-muted);
}
.shell-navmenu-note {
padding: 4px 8px 6px;
font-size: var(--lp-fs-3xs);
color: var(--lp-muted);
}
.shell-navmenu-form {
display: flex;
gap: 5px;
padding: 5px 6px 6px;
}
.shell-navmenu-input {
flex: 1 1 auto;
min-width: 0;
border: 1px solid var(--lp-line);
border-radius: 6px;
padding: 4px 7px;
font: inherit;
font-size: var(--lp-fs-xs);
background: var(--lp-surface);
color: var(--lp-ink);
}
.shell-navmenu-input:focus {
outline: none;
border-color: var(--lp-blue-deep);
}
.shell-navmenu-go {
flex: 0 0 auto;
border: 1px solid var(--lp-line);
border-radius: 6px;
background: var(--lp-surface);
padding: 4px 9px;
font: inherit;
font-size: var(--lp-fs-xs);
color: var(--lp-ink);
cursor: pointer;
}
.shell-navmenu-go:disabled {
color: var(--lp-muted);
cursor: default;
}
/* ── WAVE 21 item 6 (R3 / C3): the delete-database confirm face ─────────────
Wider than the action menu, and only while it is showing: the panel's job
changes from "pick one of four one-line verbs" to "read what is about to be
destroyed", and R7's one-line law is about MENU ROWS, not about prose. The
width is matched in `MenuShell`'s viewport clamp — a wider panel clamped at
the narrow number spills off the right edge on precisely the rows nearest
it. */
.shell-navmenu.is-wide {
max-width: 312px;
}
.shell-navconfirm {
padding: 3px 2px 2px;
}
.shell-navconfirm-h {
margin: 0;
padding: 5px 8px 2px;
font-size: var(--lp-fs-xs);
font-weight: 600;
color: var(--lp-ink);
}
/* The footprint. `disc` rather than the app's usual bare rows because these ARE
a list of things and reading them as one takes a mark — this is the one place
in the nav chrome where the user is counting. */
.shell-navconfirm-list {
margin: 0;
padding: 0 8px 4px 24px;
font-size: var(--lp-fs-3xs);
color: var(--lp-ink);
line-height: 1.55;
}
.shell-navconfirm-err {
margin: 0;
padding: 2px 8px 4px;
font-size: var(--lp-fs-3xs);
color: var(--lp-red-deep);
}
.shell-navconfirm-actions {
display: flex;
align-items: center;
gap: 6px;
padding: 4px 6px 4px;
}
/* ⚠ THE DESTRUCTIVE BUTTON IS FILLED, and the way back is the quiet one. The
opposite arrangement (a quiet Delete beside a filled Cancel) is the pattern
that makes people click twice: the eye lands on the filled control, and if
that control is the one that does nothing the second click goes to the one
that does. Weight follows CONSEQUENCE here, not safety — the safety is the
sentence above it. */
.shell-navconfirm-go {
flex: 0 0 auto;
border: 1px solid var(--lp-red-deep);
border-radius: 6px;
background: var(--lp-red-deep);
padding: 4px 11px;
font: inherit;
font-size: var(--lp-fs-xs);
color: var(--lp-surface);
cursor: pointer;
}
.shell-navconfirm-go:disabled {
border-color: var(--lp-line);
background: var(--lp-wash);
color: var(--lp-muted);
cursor: default;
}
.shell-navconfirm-actions .shell-navmenu-item.is-quiet {
width: auto;
margin-top: 0;
}
/* ── the schema drawer ────────────────────────────────────────────────────── */
.shell-schema-backdrop {
position: fixed;
inset: 0;
z-index: 90;
background: rgba(25, 34, 46, 0.28);
}
.shell-schema {
position: absolute;
top: 0;
right: 0;
bottom: 0;
width: min(430px, 92vw);
display: flex;
flex-direction: column;
background: var(--lp-surface);
border-left: 1px solid var(--lp-line);
box-shadow: -18px 0 48px rgba(20, 30, 43, 0.16);
animation: shell-schema-in 160ms cubic-bezier(0.2, 0, 0, 1);
}
@keyframes shell-schema-in {
from {
transform: translateX(14px);
opacity: 0;
}
}
.shell-schema-head {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 10px;
padding: 16px 18px 12px;
border-bottom: 1px solid var(--lp-line);
}
.shell-schema-title {
font-size: var(--lp-fs-md);
font-weight: 600;
color: var(--lp-ink);
}
.shell-schema-sub {
margin-top: 2px;
font-size: var(--lp-fs-2xs);
color: var(--lp-muted);
}
.shell-schema-close {
border: 0;
background: transparent;
font-size: var(--lp-fs-md);
line-height: 1;
color: var(--lp-muted);
cursor: pointer;
padding: 2px 6px;
border-radius: 6px;
}
.shell-schema-close:hover {
background: var(--lp-wash);
color: var(--lp-ink);
}
.shell-schema-body {
flex: 1 1 auto;
min-height: 0;
overflow-y: auto;
padding: 12px 18px 22px;
}
.shell-schema-empty {
padding: 26px 18px;
color: var(--lp-muted);
font-size: var(--lp-fs-xs);
}
/* wave17 SHELL (item 3/R6) — the same box, carrying the mark instead of a
sentence. Centred, because a drawer that has not loaded yet has no left edge
of content for it to hang off. */
.shell-schema-empty.is-spin {
display: flex;
justify-content: center;
padding: 40px 18px;
}
.shell-schema-note {
padding: 9px 11px;
border: 1px solid var(--lp-line);
border-radius: 8px;
background: var(--lp-wash);
color: var(--lp-muted);
font-size: var(--lp-fs-xs);
margin-bottom: 12px;
}
.shell-schema-kicker {
margin: 14px 0 7px;
font-size: var(--lp-fs-2xs);
font-weight: 600;
color: var(--lp-muted);
}
.shell-schema-table {
width: 100%;
border-collapse: collapse;
font-size: var(--lp-fs-xs);
}
.shell-schema-table th {
text-align: left;
font-weight: 600;
font-size: var(--lp-fs-3xs);
color: var(--lp-muted);
padding: 4px 8px 4px 0;
border-bottom: 1px solid var(--lp-line);
}
.shell-schema-table td {
vertical-align: top;
padding: 7px 8px 7px 0;
border-bottom: 1px solid color-mix(in srgb, var(--lp-line) 55%, transparent);
}
.shell-schema-fname {
color: var(--lp-ink);
}
.shell-schema-fdesc {
margin-top: 2px;
font-size: var(--lp-fs-2xs);
color: var(--lp-muted);
line-height: 1.4;
}
.shell-schema-type {
white-space: nowrap;
color: var(--lp-muted);
font-size: var(--lp-fs-2xs);
}
.shell-schema-measures {
display: flex;
flex-direction: column;
}
.shell-schema-measure {
display: flex;
align-items: baseline;
justify-content: space-between;
gap: 10px;
padding: 5px 0;
border-bottom: 1px solid color-mix(in srgb, var(--lp-line) 55%, transparent);
font-size: var(--lp-fs-xs);
}