Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions docs/design-system/DECISIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,30 @@ without retraining the reader.

---

## C9 · The desktop and tablet shell (usefulness and layout audit, 11 October 2026)

**Chose.** Built on the owner's go-ahead for the 11 October usefulness and layout audit:

1. **Tablet rule.** Page content behaves like a phone at 768 px (an upright tablet: one
column) and like desktop from 1024 px (a tablet on its side: two columns, a list beside a
record). The side rail still replaces the menu button from 768 px (owner pick "Burger and
rail", 7 October), so only the content follows the rule.
2. **One width per kind of page.** Reading pages (lists, forms, settings) keep the 45rem
column; wide pages (calendars, boards, tables, a list beside a record, the shared page
shell) take 64rem from 1024 px. The band's title and tabs always take the page's width,
so the title lines up with the cards. Declared with `data-page-width` (work-mode.css,
"page widths"); `src/components/work-frame/work-desktop-layout.tsx` gives area pages
`WorkWidePage`, `WorkSplit` (list beside record) and `WorkColumns` (two or three columns).
3. **Desktop Clinical matches Work.** The Clinical rail shows a name under every icon, in the
work rail's style and Clinical blue; the mode pill drops its small "Mode" label at every
width; tablets and desktop show the bell in the Clinical header, as on Work pages. Phones,
the brand lockup on mode homes and the Clinical search box are unchanged.

**Rejected.** Moving the side rail to 1024 px: it was the owner's own 7 October pick, and an
upright tablet reads well with it.

---

## Q&A record — clinical inputs (31 July 2026)

| # | Question | Answer | Design consequence |
Expand Down
130 changes: 126 additions & 4 deletions src/app/work-mode.css
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,95 @@ html[data-work-frame] main {
background-color: var(--surface-raised);
}

/* ------------------------------------------------------ page widths

One column width per kind of work page, and the band's title and tabs
always line up with it (desktop and tablet shell, 11 Oct 2026 audit).

- Reading pages (lists, forms, settings) keep the 45rem column.
- Wide pages (calendars, boards, tables, list beside a record) declare
`data-page-width="wide"` on their outer container, and from 1024px the
whole frame, band included, takes the 64rem column. A reading page that
sizes its own container says `data-page-width="reading"`.

Tablet rule: below 1024px (an upright tablet) every page stays the single
phone column; from 1024px (sideways, and desktop) wide pages open out.
`:has()` keeps it in CSS, so the server render is already the right width. */
body {
--work-col: 45rem;
}

@media (min-width: 1024px) {
body:has([data-work-frame] [data-page-width="wide"]) {
--work-col: 64rem;
}
}

/* The shared page shell inside a work area takes the frame's column rather
than the clinical 80rem container, so the title and the cards line up. */
[data-work-frame] [data-page-width] {
max-width: var(--work-col);
}

/* A column that draws its own 12px side padding (the work body's) holds the
same content width as the band. */
[data-work-frame] [data-page-width][data-page-padded] {
max-width: calc(var(--work-col) + 1.5rem);
}

/* ------------------------------------------------------ desktop layouts

The pieces in work-desktop-layout.tsx. One phone column below 1024px; from
1024px a list beside the record, or two or three columns of cards. */
.work-wide,
.work-split,
.work-columns {
display: grid;
grid-template-columns: minmax(0, 1fr);
align-content: start;
gap: calc(var(--spacing) * 2.25);
width: 100%;
margin: 0 auto;
padding: calc(var(--spacing) * 3) calc(var(--spacing) * 3)
max(calc(var(--spacing) * 7.5), calc(var(--safe-area-bottom, 0px) + var(--spacing) * 4));
box-sizing: border-box;
}

.work-split__list,
.work-split__detail,
.work-columns > * {
display: grid;
min-width: 0;
align-content: start;
gap: calc(var(--spacing) * 2.25);
}

@media (min-width: 1024px) {
.work-split {
grid-template-columns: minmax(17rem, 22rem) minmax(0, 1fr);
gap: calc(var(--spacing) * 5);
align-items: start;
}

.work-split__list {
position: sticky;
top: calc(var(--work-chrome-h, 0px) + var(--work-tabs-h, 0px) + var(--spacing) * 3);
max-height: calc(100dvh - var(--work-chrome-h, 0px) - var(--work-tabs-h, 0px) - var(--spacing) * 6);
overflow-y: auto;
overscroll-behavior: contain;
}

.work-columns {
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: calc(var(--spacing) * 4);
align-items: start;
}

.work-columns[data-columns="3"] {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
}

/* ------------------------------------------------------------ the band */

.work-band {
Expand Down Expand Up @@ -309,7 +398,7 @@ html[data-motion="reduced"] .work-band__mark {
align-items: flex-end;
justify-content: space-between;
gap: calc(var(--spacing) * 2.5);
max-width: calc(45rem + var(--work-gutter) * 2);
max-width: calc(var(--work-col, 45rem) + var(--work-gutter) * 2);
margin: 0 auto;
padding: 0.375rem var(--work-gutter-right) 0 var(--work-gutter-left);
}
Expand Down Expand Up @@ -341,7 +430,7 @@ html[data-motion="reduced"] .work-band__mark {
}

.work-band__status {
max-width: calc(45rem + var(--work-gutter) * 2);
max-width: calc(var(--work-col, 45rem) + var(--work-gutter) * 2);
margin: calc(var(--spacing) * 1.5) auto 0;
padding: 0 var(--work-gutter-right) 0 var(--work-gutter-left);
box-sizing: border-box;
Expand Down Expand Up @@ -397,7 +486,7 @@ html[data-motion="reduced"] .work-band__mark {
--work-tab-gap: calc(var(--spacing) * 5);
display: flex;
gap: var(--work-tab-gap);
max-width: calc(45rem + var(--work-gutter) * 2);
max-width: calc(var(--work-col, 45rem) + var(--work-gutter) * 2);
margin: calc(var(--spacing) * 1) auto -1px;
/* The 1px under the row holds the current tab's underline, which sits on
the band's bottom line, inside the row's own box. */
Expand Down Expand Up @@ -2727,6 +2816,37 @@ html[data-work-frame] .app-toast-region {
color: var(--mode-identity-deep, var(--mode-identity));
}

/* The clinical rail wears the same items (ClinicalSidebar's collapsed rail),
lit in Clinical blue and marked current by `aria-current="page"`. */
.clinical-rail__item {
--mode-identity: var(--clinical-accent);
--mode-identity-soft: var(--clinical-accent-soft);
--mode-identity-deep: var(--clinical-accent);
flex: none;
text-align: center;
}

.clinical-rail__item:focus-visible {
outline: 2px solid var(--focus);
outline-offset: 2px;
}

.clinical-rail__item[aria-current="page"] .work-rail__pill,
.clinical-rail__item[data-current="true"] .work-rail__pill {
background: var(--mode-identity-soft);
color: var(--mode-identity);
Comment thread
qodo-code-review[bot] marked this conversation as resolved.
Resolved
}

.clinical-rail__item[aria-current="page"] .work-rail__label,
.clinical-rail__item[data-current="true"] .work-rail__label {
font-weight: 750;
color: var(--mode-identity-deep);
}

.clinical-rail__item:hover .work-rail__pill {
background: var(--surface-subtle);
}

.work-rail__count {
position: absolute;
top: -0.1875rem;
Expand All @@ -2747,7 +2867,9 @@ html[data-work-frame] .app-toast-region {

@media (forced-colors: active) {
.work-side-menu__row[aria-current="true"],
.work-rail__item[aria-current="true"] .work-rail__pill {
.work-rail__item[aria-current="true"] .work-rail__pill,
.clinical-rail__item[aria-current="page"] .work-rail__pill,
.clinical-rail__item[data-current="true"] .work-rail__pill {
outline: 2px solid Highlight;
}

Expand Down
8 changes: 7 additions & 1 deletion src/components/admin/admin-kit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,13 @@ export function AdminPage({
}) {
return (
<main data-testid={testId} className={styles.page}>
<div className={cn("work-body", wide && styles.wide)}>{children}</div>
<div
className={cn("work-body", wide && styles.wide)}
data-page-width={wide ? "wide" : undefined}
data-page-padded={wide ? "" : undefined}
>
{children}
</div>
</main>
);
}
Expand Down
Loading
Loading