* build(workspace): vendor the approved concept stylesheet with a drift check * refactor(workspace): adopt the concept stylesheet as the workspace base * feat(workspace): concept sidebar with real navigation counts * feat(workspace): concept topbar with Theme and ComfyUI link * refactor(workspace): one concept heading and footer for every route * fix(workspace): keep the canvas link on the proxy mount A resolver failure no longer stops the shell from mounting: the ComfyUI link falls back to the root read from the page's own mount path (never another origin). Tests cover a non-standard /ComfyBackendDirect mount, including that no request escapes it. * test(workspace): concept fixture and shell comparison * test(workspace): concept fixture carries the concept inspector facts * fix(workspace): match the concept brand name and compare shell hover states * test(workspace): shell comparison mutation check and docs Add mutate() to the shared concept inventory and a shell mutation check: a nav-row min-height rule and a removed .breadcrumbs each make the comparison fail with the changed path. Harden the resolver-failure guard test with an injection count, make the overlay lint fail when workspace.css is missing, mark the library.css .row-actions leftovers for PR E, and document the concept CSS base, the overlay lint, the comparison method and the recorded shell deviations in TESTING.md. * fix(workspace): focus the page title on a route change A sidebar or history navigation now focuses #page-title, as the concept does on every hashchange (app.js 1168), so a screen reader announces the page heading instead of the main region. The first render leaves focus alone and the skip link still focuses main. The heading module's comment now describes what the shell does. * fix(workspace): give the Overview nav entry its own home glyph Overview reused the concept's Activity pulse byte for byte, so once the Activity row lands two entries would share one icon. Overview now has an outline home glyph. The shell comparison takes it from the D28 ruling instead of the concept's activity path, and the icon test checks that every approved glyph is distinct. * test(workspace): accept only #249 decision markers and state the lint scope The overlay lint accepted any D-number, so another issue's ruling such as "D5 (#245)" could mark a concept override. A marker now has to be a D-number with no other issue cited; the vocabulary rule that cited #245 reads "#245 decision 5". TESTING.md now states that the lint covers workspace.css only, lists the unmarked overrides still in images.css, and says PRs C and D run the lint over each page sheet they keep. * perf(workspace): re-read only Library and Tags counts after a Library write A confirmed Library or vocabulary write cannot change the Images count, but it re-read all three, including the Images output listing. It now re-reads only the Library and Tags counts. Each count has its own read, so a write never cancels an Images read that is still in flight.
136 lines
16 KiB
CSS
136 lines
16 KiB
CSS
main.library-main { --library-positive: #73dda9; }
|
||
.library-main :where(.library-shelf, .library-history, .library-card, .library-card-content, .library-card-prompts, .library-linked-images) { min-inline-size: 0; }
|
||
.library-main .library-toolbar { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; margin-block: 0 20px; }
|
||
.library-main .library-toolbar .ca-field { position: relative; display: flex; min-inline-size: 0; flex: 1 1 140px; align-items: stretch; }
|
||
.library-main .library-toolbar .ca-field:first-child { flex: 3 1 250px; }
|
||
.library-main .library-toolbar .ca-field > span { position: absolute; inline-size: 1px; block-size: 1px; padding: 0; margin: -1px; overflow: clip; clip-path: inset(50%); white-space: nowrap; }
|
||
.library-main .library-toolbar :where(input, select, button), .ca-tools .library-main .library-toolbar > button { box-sizing: border-box; inline-size: 100%; min-inline-size: 0; block-size: 36px; min-block-size: 36px; font-size: 12px; }
|
||
.ca-tools .library-main .library-toolbar > button { inline-size: auto; }
|
||
.library-main .library-caption { display: flex; justify-content: space-between; font-size: 10px; color: var(--ca-muted); margin-block: 0 13px; }
|
||
.library-main .library-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px; overflow-anchor: none; }
|
||
.library-main .library-row { grid-column: 1 / -1; display: grid; grid-template-columns: inherit; gap: 18px; min-inline-size: 0; }
|
||
.library-main .library-card { box-sizing: border-box; display: grid; grid-template-rows: 170px 1fr auto; min-inline-size: 0; border: 1px solid var(--ca-line); border-radius: 8px; background: var(--ca-surface); }
|
||
.library-main .library-card-art { display: grid; grid-template-columns: 2fr 1fr; gap: 3px; block-size: 170px; border-radius: 7px 7px 0 0; background: var(--ca-field); overflow: clip; }
|
||
.library-main .library-card-art img { display: block; inline-size: 100%; block-size: 170px; aspect-ratio: 4 / 3; object-fit: cover; }
|
||
.library-main .library-card-art > :only-child { grid-column: 1 / -1; }
|
||
.library-main .library-art-empty { display: grid; place-content: center; min-inline-size: 0; font-size: 12px; color: var(--ca-muted); }
|
||
.library-main .library-card-content { min-block-size: 0; display: flex; flex-direction: column; gap: 10px; padding: 18px; }
|
||
.library-main .library-card-title { display: flex; align-items: start; justify-content: space-between; gap: 12px; }
|
||
.library-main .library-card-title h2 { margin: 0; font-size: 16px; font-weight: 600; min-inline-size: 0; overflow-wrap: anywhere; }
|
||
.library-main .library-title-link { color: var(--ca-text); text-decoration: none; }
|
||
.library-main .library-title-link:hover { color: var(--ca-accent); }
|
||
.library-main .library-card-prompts .prompt-block { margin: 0; padding-block: 10px 0; }
|
||
.library-main .library-card-meta { display: flex; align-items: center; flex-wrap: wrap; gap: 9px; font-size: 10px; color: var(--ca-muted); }
|
||
.library-main .library-chip { display: inline-block; max-inline-size: 100%; padding: 3px 8px; border: 1px solid var(--ca-line); border-radius: 4px; font-size: 10px; color: var(--ca-muted); background: var(--ca-field); overflow-wrap: anywhere; }
|
||
.library-main .library-chip-negative { color: var(--ca-error-text); border-color: color-mix(in srgb, var(--ca-error) 35%, var(--ca-line)); }
|
||
.library-main .library-tags { display: flex; flex-wrap: wrap; gap: 5px; }
|
||
.library-main .library-card-footer { padding: 11px 18px; border-block-start: 1px solid var(--ca-line); display: flex; justify-content: space-between; align-items: center; gap: 12px; font-size: 10px; }
|
||
.library-main .library-rating { color: var(--ca-muted); }
|
||
.library-main .library-history-link { display: inline-flex; align-items: center; gap: 7px; color: var(--ca-accent); }
|
||
.library-main .library-history-link svg { inline-size: 18px; block-size: 18px; }
|
||
.library-main .library-row-spacer { grid-column: 1 / -1; pointer-events: none; }
|
||
.library-main .library-continuation { padding-block: 22px; display: flex; flex-wrap: wrap; align-items: center; gap: 12px; }
|
||
.library-main .library-status { flex: 1 1 240px; color: var(--ca-muted); }
|
||
.library-main .library-surface { padding: 22px; background: var(--ca-surface); border: 1px solid var(--ca-line); border-radius: 7px; margin-block: 18px; }
|
||
.library-main .library-branches { padding: 18px 20px; border: 1px solid var(--ca-line); border-radius: 6px; background: var(--ca-field); margin-block: 16px; }
|
||
.library-main .library-positive-lane { padding-block-end: 12px; border-block-end: 2px solid var(--library-positive); color: var(--library-positive); font-size: 12px; }
|
||
.library-main .library-variant-lane { display: flex; align-items: center; gap: 16px; min-block-size: 57px; margin-inline-start: 18px; border-inline-start: 2px solid var(--ca-error); padding-inline-start: 18px; }
|
||
.library-main .library-variant-lane span { min-inline-size: 0; overflow-wrap: anywhere; font-size: 12px; color: var(--ca-muted); }
|
||
.ca-tools .library-main .library-variant-dot { flex: 0 0 29px; inline-size: 29px; min-block-size: 29px; padding: 0; border-radius: 50%; background: var(--ca-error); border: 2px solid var(--ca-error); color: white; }
|
||
.library-main .library-variant-dot[aria-pressed="true"] { outline: 3px solid var(--ca-focus); outline-offset: 4px; }
|
||
.library-main .library-variants > button[aria-pressed="true"] { border-color: var(--ca-focus); }
|
||
.library-main .library-shared-gallery { margin-block-start: 24px; }
|
||
.library-main .library-variant-context { color: var(--ca-muted); font-size: 12px; }
|
||
@media (min-width: 1700px) { .library-main .library-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
|
||
@media (max-width: 700px) { .library-main .library-grid { grid-template-columns: minmax(0, 1fr); } .library-main .library-surface { padding: 16px; } .library-main .library-card-title { flex-wrap: wrap; gap: 6px; } .library-main .library-toolbar { gap: 8px; } .library-main .library-toolbar .ca-field:first-child { flex-basis: 100%; } .library-main .library-card { grid-template-rows: 150px 1fr auto; } .library-main .library-card-art, .library-main .library-card-art img { block-size: 150px; } .library-main .library-card-content { padding: 15px; } }
|
||
|
||
[data-ca-theme="light"] main.library-main { --library-positive: #176b46; }
|
||
|
||
/* Role colors and branch geometry follow the approved history surface. */
|
||
main.library-main { --library-negative: #ff8c98; }
|
||
[data-ca-theme="light"] main.library-main { --library-negative: #b71931; }
|
||
.library-main :where(.library-surface, .library-recorded-container, .recorded-history) { min-inline-size: 0; }
|
||
.library-main .library-branches { overflow-x: auto; position: relative; }
|
||
.library-main .library-positive-lane { position: relative; box-sizing: border-box; block-size: 40px; min-inline-size: 520px; margin: 17px 0 0; padding: 0 0 0 38px; border: 0; border-block-start: 2px solid var(--library-positive); font-size: 10px; line-height: 1.6; }
|
||
.library-main .library-positive-lane::before, .history-positive-lane::before { content: "+"; position: absolute; inset-block-start: -13px; inset-inline-start: 0; border-radius: 50%; inline-size: 25px; block-size: 25px; background: var(--library-positive); color: #172b22; text-align: center; font-size: 14px; line-height: 21px; }
|
||
.library-positive-lane > span, .history-positive-lane > span { position: absolute; inset-block-start: -25px; inset-inline-start: 38px; font-size: 10px; color: var(--library-positive); }
|
||
.library-main .library-variants h2 { font-size: 14px; line-height: 1.5; margin: 0; }
|
||
.library-main .library-variants > p.muted { font-size: 12px; line-height: 1.5; margin: 0 0 12px; }
|
||
.library-main .library-panel-heading p.muted { font-size: 12px; line-height: 1.5; margin: 0; }
|
||
.library-main .library-variants .library-branches { margin-block: 0; }
|
||
.library-variant-footer { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px; margin-block-start: 14px; }
|
||
.library-variant-summary { display: flex; flex-wrap: wrap; gap: 6px; }
|
||
.library-main .library-variant-summary > p { font-size: 12px; line-height: 1.5; margin: 0; }
|
||
.ca-tools .library-variant-footer > button { margin-inline-start: auto; max-inline-size: 100%; white-space: normal; }
|
||
.library-main .library-variant-lane { position: relative; display: block; box-sizing: border-box; min-inline-size: 520px; block-size: 57px; min-block-size: 57px; margin-inline-start: var(--lane-offset, 38px); padding: 0; border: 0; border-block-start: 2px solid color-mix(in srgb, var(--library-negative) 60%, transparent); }
|
||
.library-main .library-variant-lane::before, .history-context-branch::before { content: ""; position: absolute; inset-block-start: -25px; inset-inline-start: -30px; inline-size: 30px; block-size: 25px; border-inline-start: 2px solid var(--library-negative); border-block-end: 2px solid var(--library-negative); border-end-start-radius: 22px; }
|
||
.library-main .library-variant-lane span { position: absolute; inset-inline-start: 43px; inset-block-start: 6px; font-size: 10px; max-inline-size: 430px; }
|
||
.ca-tools .library-main .library-variant-dot { position: absolute; inset-block-start: -16px; inset-inline-start: 0; inline-size: 29px; block-size: 29px; min-block-size: 29px; border-color: var(--library-negative); background: var(--library-negative); color: #38151b; font-size: 12px; }
|
||
.history-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-block: 14px; }
|
||
.ca-tools .library-main :where(.library-variants, .history-toolbar) > button { max-inline-size: 100%; white-space: normal; }
|
||
.recorded-history > .muted, .history-count, .history-scope, .history-status, .history-legend { font-size: 11px; line-height: 1.65; overflow-wrap: anywhere; }
|
||
.library-main .recorded-history > h2 { font-size: 14px; line-height: 1.5; }
|
||
.library-main .recorded-history > h2 + p { font-size: 12px; line-height: 1.5; }
|
||
.history-scope summary { cursor: pointer; }
|
||
.history-timeline { position: relative; box-sizing: border-box; inline-size: 100%; max-inline-size: 100%; max-block-size: 490px; overflow: auto; overscroll-behavior: contain; overflow-anchor: none; border: 1px solid var(--ca-line); border-radius: 6px; background: var(--ca-field); }
|
||
.history-canvas { position: relative; min-inline-size: calc(100% - 40px); margin: 18px 20px; }
|
||
.history-positive-lane { position: absolute; inset-block-start: 17px; inset-inline: 0; border-block-start: 2px solid var(--library-positive); color: var(--library-positive); font-size: 10px; line-height: 1.6; padding-inline-start: 38px; }
|
||
.history-earlier-edge { position: absolute; inset: 0 auto 0 0; inline-size: 1px; }
|
||
.history-context-branch { position: absolute; inset-inline-end: 0; block-size: 57px; border-block-start: 2px solid color-mix(in srgb, var(--library-negative) 60%, transparent); }
|
||
.history-context-label { position: absolute; inset-inline-start: 43px; inset-block-start: 6px; inline-size: 370px; max-inline-size: calc(100% - 43px); font-size: 10px; line-height: 1.5; color: var(--ca-muted); overflow-wrap: anywhere; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; overflow: clip; }
|
||
.history-run-list { position: absolute; inset: 0; margin: 0; padding: 0; list-style: none; }
|
||
.history-run-column { position: absolute; inset-block: 0; inline-size: 64px; pointer-events: none; }
|
||
.history-position { position: absolute; inset-block-start: 41px; font-size: 10px; color: var(--ca-muted); }
|
||
.ca-tools .history-run-marker { position: absolute; pointer-events: auto; transform: translate(-50%, -50%); inline-size: 12px; block-size: 12px; min-inline-size: 12px; min-block-size: 12px; border: 2px solid var(--library-negative); border-radius: 50%; background: var(--ca-field); padding: 0; color: var(--ca-field); font-size: 16px; line-height: 1; }
|
||
.ca-tools .history-context-anchor { inline-size: 29px; block-size: 29px; min-inline-size: 29px; min-block-size: 29px; background: var(--library-negative); color: #38151b; font-size: 12px; }
|
||
.history-run-marker[aria-pressed="true"], .history-run-marker:focus-visible { outline: 3px solid var(--ca-focus); outline-offset: 4px; }
|
||
.history-run-marker[aria-disabled="true"] { opacity: .6; cursor: progress; }
|
||
.recorded-run-dialog { box-sizing: border-box; inline-size: min(1100px, calc(100% - 32px)); max-inline-size: calc(100% - 32px); max-block-size: calc(100dvh - 32px); padding: 22px; border: 1px solid var(--ca-border); border-radius: 7px; color: var(--ca-text); background: var(--ca-surface); overflow: auto; overscroll-behavior: contain; scrollbar-gutter: stable; overflow-wrap: anywhere; }
|
||
.recorded-run-dialog::backdrop { background: #0009; }
|
||
.recorded-run-header { display: flex; gap: 12px; align-items: center; justify-content: space-between; }
|
||
.recorded-run-header h2 { margin: 0; font-size: 20px; }
|
||
.recorded-run-body, .recorded-run-body > section { min-inline-size: 0; }
|
||
.recorded-run-facts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; font-size: 12px; }
|
||
.recorded-run-facts dt { color: var(--ca-muted); font-size: 10px; }
|
||
.recorded-run-facts dd { margin: 4px 0 0; white-space: pre-wrap; }
|
||
.recorded-run-anchors, .recorded-run-mode { display: flex; flex-wrap: wrap; gap: 8px; margin-block: 18px; }
|
||
.recorded-run-dialog [aria-pressed="true"] { outline: 2px solid var(--ca-focus); outline-offset: 2px; }
|
||
.recorded-run-dialog :where(.muted, .prompt-source, .recorded-output-status) { font-size: 11px; line-height: 1.65; }
|
||
.recorded-provenance { border-block-start: 1px solid var(--ca-line); padding-block-start: 12px; margin-block: 18px; }
|
||
.recorded-provenance summary { cursor: pointer; }
|
||
.recorded-run-dialog pre { white-space: pre-wrap; overflow-wrap: anywhere; max-inline-size: 100%; }
|
||
.recorded-outputs { margin-block: 24px; }
|
||
.recorded-receipts { list-style: decimal; padding-inline-start: 24px; }
|
||
.recorded-receipt { border: 1px solid var(--ca-line); border-radius: 5px; padding: 12px; margin-block: 10px; font-size: 12px; }
|
||
.recorded-receipt > div { margin-block-end: 10px; }
|
||
.recorded-receipt[aria-current="true"] { outline: 2px solid var(--ca-focus); outline-offset: 2px; }
|
||
.recorded-current-file { border-block-start: 1px solid var(--ca-line); padding-block-start: 16px; }
|
||
@media (max-width: 700px) {
|
||
.library-main .library-surface { padding: 22px; }
|
||
.recorded-run-dialog { padding: 16px; }
|
||
.recorded-run-facts { grid-template-columns: minmax(0, 1fr); }
|
||
}
|
||
@media (pointer: coarse) {
|
||
.recorded-history :where(.history-toolbar button, .history-scope summary) { min-inline-size: 44px; min-block-size: 44px; }
|
||
.ca-tools .history-run-marker { inline-size: 44px; block-size: 44px; min-inline-size: 44px; min-block-size: 44px; border: 0; background: transparent; color: transparent; }
|
||
.ca-tools .history-run-marker::before { content: ""; position: absolute; inset: 16px; box-sizing: border-box; border: 2px solid var(--library-negative); border-radius: 50%; background: var(--ca-field); }
|
||
.ca-tools .history-context-anchor::before { content: "−"; inset: 7.5px; inline-size: 29px; block-size: 29px; line-height: 25px; color: #38151b; background: var(--library-negative); }
|
||
.ca-tools .library-main .library-variant-dot::after { content: ""; position: absolute; inset: -9px; }
|
||
.ca-tools .recorded-run-dialog :where(button, summary) { min-inline-size: 44px; min-block-size: 44px; }
|
||
}
|
||
@media (forced-colors: active) {
|
||
.history-context-branch, .history-context-branch::before, .history-run-marker, .history-run-marker::before { border-color: CanvasText; }
|
||
.history-run-marker[aria-pressed="true"] { outline-color: Highlight; }
|
||
}
|
||
|
||
/* Panel actions follow the concept (style.css 294-300, 540-549); the page heading is the concept's own (Task A5).
|
||
These .row-actions rules restyle the concept's own selector and are retired in PR E (library cards). */
|
||
.library-main .row-actions { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
|
||
.ca-tools .library-main .row-actions button { min-block-size: 32px; font-size: 12px; max-inline-size: 100%; white-space: normal; }
|
||
.library-main .library-panel-heading { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-block-end: 12px; }
|
||
@media (pointer: coarse) { .ca-tools .library-main .row-actions button { min-block-size: 40px; } }
|
||
/* Archived pairs: the existing lane at reduced emphasis (the existing .6 disabled-marker opacity); text stays at full contrast. */
|
||
.library-main .library-variant-archived::before, .ca-tools .library-main .library-variant-archived .library-variant-dot { opacity: .6; }
|
||
.ca-tools .library-main .library-variant-restore { position: static; margin-inline-start: 8px; min-block-size: 24px; padding: 2px 8px; font-size: 10px; vertical-align: middle; }
|
||
@media (pointer: coarse) { .ca-tools .library-main .library-variant-restore { min-block-size: 40px; } }
|