CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 7s
CI & Build / integration (push) Successful in 17s
CI & Build / TypeScript typecheck (push) Successful in 34s
CI & Build / Python tests (push) Successful in 48s
CI & Build / Build & push image (push) Successful in 37s
#2533. theme.css claimed "removing this block is a rename sweep across the
components, tracked separately" — written in 67a529a, never filed, which made
the comment itself an instance of the survey's presence-without-reference
pattern. This is that sweep.
73 alias declarations deleted; 69 files rewritten; every --color-*-style name
now references its --fs-* token directly. Mechanical by construction: the map
IS the alias block, applied longest-name-first with a boundary guard so
--color-text never matched inside --color-text-muted. Zero survivors outside
theme.css, verified by grep rather than assumed.
One deliberate survivor: --color-shadow stays DECLARED, because it was never
an alias — it is a literal value the design system has no token for. Marked
in place as a recorded gap: promote it to an --fs-* token when a second app
needs it, don't copy the line.
Nothing is lost mode-wise: the aliases' resolve-at-use-time trick (which
absorbed 48 dark-mode overrides) lives one layer down in the --fs-* tokens'
own derivations, which is why the sweep is a pure rename. Both CSS checkers
green.
Why now rather than never: check_snippets_against_design_system reports every
--color-* reference as "unknown — renders as NOTHING", and nine recipe
snippets recorded from components.css carried the deprecated names, making
them prior art pointing the wrong way. With the sweep in, the checker's
report over re-recorded snippets should be EMPTY — the acceptance test that
proves the checker was right all along (#2517's correction).
Refs #2533
558 lines
13 KiB
CSS
558 lines
13 KiB
CSS
/* ── Layout ── */
|
|
.editor-page {
|
|
max-width: 1400px;
|
|
margin: 0 auto;
|
|
height: 100%;
|
|
display: flex;
|
|
flex-direction: column;
|
|
overflow: hidden;
|
|
}
|
|
.editor-header {
|
|
flex-shrink: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.75rem;
|
|
padding: 1rem 1.5rem 0.5rem;
|
|
border-bottom: 1px solid var(--fs-border-color);
|
|
}
|
|
.editor-body {
|
|
flex: 1;
|
|
min-height: 0;
|
|
display: flex;
|
|
overflow: hidden;
|
|
}
|
|
.editor-main {
|
|
flex: 1;
|
|
min-width: 0;
|
|
overflow-y: auto;
|
|
padding: 0.75rem 1.5rem 1.5rem;
|
|
}
|
|
|
|
/* ── Toolbar & inputs ── */
|
|
.toolbar {
|
|
display: flex;
|
|
gap: 0.5rem;
|
|
align-items: center;
|
|
}
|
|
/* Save: Moss action-primary per the Hybrid rule. Saving is "operating
|
|
the software" — not a brand moment. Accent gradient is reserved for
|
|
Send / empty-state CTAs. */
|
|
/* Delete: Oxblood action-destructive per Hybrid rule. Should be paired
|
|
with a Trash icon at the call site to reinforce intent. */
|
|
.title-input:focus {
|
|
outline: none;
|
|
border-bottom-color: var(--fs-accent);
|
|
}
|
|
.title-input::placeholder {
|
|
color: var(--fs-text-tertiary);
|
|
font-weight: 400;
|
|
}
|
|
.editor-tabs {
|
|
display: flex;
|
|
gap: 0;
|
|
border-bottom: 1px solid var(--fs-border-color);
|
|
}
|
|
.tab {
|
|
padding: 0.45rem 1rem;
|
|
border: none;
|
|
background: none;
|
|
color: var(--fs-text-secondary);
|
|
cursor: pointer;
|
|
font-size: 0.9rem;
|
|
border-bottom: 2px solid transparent;
|
|
}
|
|
.tab.active {
|
|
color: var(--fs-accent);
|
|
border-bottom-color: var(--fs-accent);
|
|
}
|
|
.preview-pane {
|
|
padding: 0.75rem;
|
|
border: 1px solid var(--fs-border-color);
|
|
border-radius: var(--fs-radius-sm);
|
|
min-height: 200px;
|
|
background: var(--fs-surface-raised);
|
|
}
|
|
|
|
/* ── Tag suggestions ── */
|
|
.tag-suggest-row {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
align-items: center;
|
|
gap: 0.4rem;
|
|
}
|
|
.tag-pill {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 0.2rem;
|
|
padding: 0.2rem 0.55rem;
|
|
border: 1px solid var(--fs-accent);
|
|
border-radius: 999px;
|
|
background: transparent;
|
|
color: var(--fs-accent);
|
|
font-size: 0.8rem;
|
|
cursor: pointer;
|
|
transition: background 0.15s, color 0.15s;
|
|
}
|
|
.tag-pill:hover:not(:disabled) {
|
|
background: var(--fs-accent);
|
|
color: var(--fs-text-on-action);
|
|
}
|
|
.tag-pill.applied {
|
|
background: var(--fs-success);
|
|
border-color: var(--fs-success);
|
|
color: var(--fs-text-on-action);
|
|
cursor: default;
|
|
}
|
|
.tag-check {
|
|
font-size: 0.7rem;
|
|
}
|
|
|
|
/* ── Assist panel ── */
|
|
.assist-panel {
|
|
width: 320px;
|
|
flex-shrink: 0;
|
|
border-left: 1px solid var(--fs-border-color);
|
|
background: var(--fs-surface-raised);
|
|
display: flex;
|
|
flex-direction: column;
|
|
overflow: hidden;
|
|
}
|
|
.assist-panel-header {
|
|
flex-shrink: 0;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
padding: 0.65rem 0.9rem;
|
|
border-bottom: 1px solid var(--fs-border-color);
|
|
}
|
|
.assist-panel-title {
|
|
flex: 1;
|
|
font-size: 0.8rem;
|
|
font-weight: 500;
|
|
color: var(--fs-text-secondary);
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.05em;
|
|
}
|
|
.assist-panel-body {
|
|
flex: 1;
|
|
min-height: 0;
|
|
overflow-y: auto;
|
|
padding: 0.75rem 0.9rem 1rem;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.6rem;
|
|
}
|
|
|
|
/* Section list */
|
|
.assist-sections-label {
|
|
font-size: 0.72rem;
|
|
font-weight: 500;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.04em;
|
|
color: var(--fs-text-tertiary);
|
|
margin-bottom: 0.2rem;
|
|
}
|
|
.assist-sections {
|
|
border: 1px solid var(--fs-border-color);
|
|
border-radius: var(--fs-radius-sm);
|
|
background: var(--fs-surface-page);
|
|
max-height: 200px;
|
|
overflow-y: auto;
|
|
flex-shrink: 0;
|
|
}
|
|
.assist-section-item {
|
|
padding: 0.35rem 0.7rem;
|
|
cursor: pointer;
|
|
font-size: 0.82rem;
|
|
border-left: 3px solid transparent;
|
|
color: var(--fs-text-primary);
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
.assist-section-item:hover {
|
|
background: var(--fs-surface-raised);
|
|
}
|
|
.assist-section-item.selected {
|
|
border-left-color: var(--fs-accent);
|
|
background: var(--fs-surface-raised);
|
|
font-weight: 500;
|
|
}
|
|
.assist-empty,
|
|
.assist-hint {
|
|
padding: 0.6rem 0.7rem;
|
|
font-size: 0.82rem;
|
|
color: var(--fs-text-tertiary);
|
|
}
|
|
.assist-target-preview {
|
|
font-size: 0.8rem;
|
|
color: var(--fs-text-secondary);
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
.assist-target-preview em {
|
|
font-style: normal;
|
|
color: var(--fs-text-primary);
|
|
}
|
|
.assist-instruction {
|
|
width: 100%;
|
|
padding: 0.5rem 0.65rem;
|
|
border: 1px solid var(--fs-border-color);
|
|
border-radius: var(--fs-radius-sm);
|
|
font-size: 0.88rem;
|
|
font-family: inherit;
|
|
resize: vertical;
|
|
background: var(--fs-surface-page);
|
|
color: var(--fs-text-primary);
|
|
box-sizing: border-box;
|
|
min-height: 3.5rem;
|
|
}
|
|
.assist-input-actions {
|
|
display: flex;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
/* Streaming */
|
|
.assist-streaming-label {
|
|
font-size: 0.8rem;
|
|
color: var(--fs-text-secondary);
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
.assist-preview-box {
|
|
padding: 0.65rem;
|
|
border: 1px solid var(--fs-border-color);
|
|
border-radius: var(--fs-radius-sm);
|
|
background: var(--fs-surface-page);
|
|
font-size: 0.9rem;
|
|
max-height: 300px;
|
|
overflow-y: auto;
|
|
}
|
|
.typing-indicator {
|
|
color: var(--fs-text-tertiary);
|
|
font-size: 0.75rem;
|
|
letter-spacing: 0.15em;
|
|
animation: blink 1s step-end infinite;
|
|
}
|
|
@keyframes blink {
|
|
50% { opacity: 0; }
|
|
}
|
|
|
|
/* Active hint shown in the panel while output is inline */
|
|
.assist-active-hint {
|
|
padding: 0.5rem 0.75rem;
|
|
font-size: 0.8rem;
|
|
color: var(--fs-text-tertiary);
|
|
text-align: center;
|
|
}
|
|
|
|
/* Error */
|
|
.assist-error {
|
|
padding: 0.5rem 0.75rem;
|
|
background: color-mix(in srgb, var(--fs-error) 10%, transparent);
|
|
border: 1px solid var(--fs-error);
|
|
border-radius: var(--fs-radius-sm);
|
|
font-size: 0.85rem;
|
|
color: var(--fs-error);
|
|
}
|
|
|
|
/* Review / diff */
|
|
.assist-review-header {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
font-size: 0.8rem;
|
|
font-weight: 500;
|
|
color: var(--fs-text-secondary);
|
|
}
|
|
.diff-view {
|
|
border: 1px solid var(--fs-border-color);
|
|
border-radius: var(--fs-radius-sm);
|
|
background: var(--fs-surface-page);
|
|
font-size: 0.82rem;
|
|
font-family: monospace;
|
|
max-height: 340px;
|
|
overflow-y: auto;
|
|
padding: 0.4rem 0;
|
|
}
|
|
.diff-line {
|
|
display: flex;
|
|
align-items: baseline;
|
|
padding: 0.05rem 0.5rem;
|
|
line-height: 1.5;
|
|
}
|
|
.diff-delete {
|
|
background: color-mix(in srgb, var(--fs-error) 12%, transparent);
|
|
color: var(--fs-error);
|
|
}
|
|
.diff-insert {
|
|
background: color-mix(in srgb, var(--fs-success) 12%, transparent);
|
|
color: var(--fs-success);
|
|
}
|
|
.diff-equal {
|
|
color: var(--fs-text-tertiary);
|
|
}
|
|
.diff-marker {
|
|
flex-shrink: 0;
|
|
width: 1rem;
|
|
text-align: center;
|
|
user-select: none;
|
|
font-weight: 500;
|
|
}
|
|
.diff-text {
|
|
flex: 1;
|
|
white-space: pre-wrap;
|
|
word-break: break-word;
|
|
}
|
|
.diff-empty {
|
|
padding: 0.5rem;
|
|
color: var(--fs-text-tertiary);
|
|
font-size: 0.82rem;
|
|
}
|
|
.assist-actions {
|
|
display: flex;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
/* ── Modal ── */
|
|
.modal-overlay {
|
|
position: fixed;
|
|
inset: 0;
|
|
background: var(--fs-overlay);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
z-index: 200;
|
|
}
|
|
.modal-card {
|
|
background: var(--fs-surface-raised);
|
|
border-radius: var(--fs-radius-lg);
|
|
padding: 1.5rem;
|
|
max-width: 400px;
|
|
width: 90%;
|
|
box-shadow: 0 8px 32px var(--color-shadow);
|
|
}
|
|
.modal-title {
|
|
margin: 0 0 0.5rem;
|
|
font-size: 1.1rem;
|
|
}
|
|
.modal-message {
|
|
margin: 0 0 1.25rem;
|
|
color: var(--fs-text-secondary);
|
|
font-size: 0.95rem;
|
|
}
|
|
.modal-actions {
|
|
display: flex;
|
|
gap: 0.5rem;
|
|
justify-content: flex-end;
|
|
}
|
|
.modal-btn {
|
|
padding: 0.45rem 1rem;
|
|
border: 1px solid var(--fs-border-color);
|
|
border-radius: var(--fs-radius-sm);
|
|
background: var(--fs-surface-raised);
|
|
color: var(--fs-text-primary);
|
|
cursor: pointer;
|
|
font-size: 0.9rem;
|
|
}
|
|
.modal-btn-danger {
|
|
background: var(--fs-error);
|
|
color: var(--fs-text-on-action);
|
|
border-color: var(--fs-error);
|
|
}
|
|
|
|
/* ── Floating inline assist button (teleported to body) ── */
|
|
.inline-assist-btn {
|
|
position: fixed;
|
|
z-index: 100;
|
|
transform: translateX(-50%);
|
|
padding: 0.3rem 0.75rem;
|
|
background: var(--fs-action-primary);
|
|
color: var(--fs-text-on-action);
|
|
border: none;
|
|
border-radius: var(--fs-radius-sm);
|
|
cursor: pointer;
|
|
font-size: 0.8rem;
|
|
box-shadow: 0 2px 8px var(--color-shadow);
|
|
pointer-events: auto;
|
|
}
|
|
|
|
/* ── Sidebar shared styles ── */
|
|
.sidebar-toggle {
|
|
display: none;
|
|
width: 100%;
|
|
padding: 0.6rem 1rem;
|
|
background: var(--fs-surface-raised);
|
|
border: none;
|
|
border-bottom: 1px solid var(--fs-border-color);
|
|
font-size: 0.85rem;
|
|
font-weight: 500;
|
|
color: var(--fs-text-secondary);
|
|
cursor: pointer;
|
|
text-align: left;
|
|
font-family: inherit;
|
|
}
|
|
.sidebar-content {
|
|
padding: 0.75rem;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.65rem;
|
|
}
|
|
.sb-field {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.25rem;
|
|
}
|
|
.sb-label {
|
|
font-size: 0.78rem;
|
|
font-weight: 500;
|
|
color: var(--fs-text-secondary);
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.04em;
|
|
}
|
|
.sb-select,
|
|
.sb-input {
|
|
width: 100%;
|
|
padding: 0.35rem 0.5rem;
|
|
border: 1px solid var(--fs-border-color);
|
|
border-radius: var(--fs-radius-sm);
|
|
background: var(--fs-surface-raised);
|
|
color: var(--fs-text-primary);
|
|
font-size: 0.875rem;
|
|
font-family: inherit;
|
|
box-sizing: border-box;
|
|
}
|
|
.sb-select:focus,
|
|
.sb-input:focus {
|
|
outline: none;
|
|
border-color: var(--fs-accent);
|
|
}
|
|
.sb-divider {
|
|
height: 1px;
|
|
background: var(--fs-border-color);
|
|
margin: 0.15rem 0;
|
|
}
|
|
@media (max-width: 720px) {
|
|
.sidebar-toggle { display: block; }
|
|
.sidebar-content {
|
|
display: none;
|
|
padding: 0.75rem 1rem;
|
|
}
|
|
.sidebar-content.sidebar-open { display: flex; }
|
|
}
|
|
|
|
/* ── Mobile ── */
|
|
@media (max-width: 768px) {
|
|
.editor-body {
|
|
flex-direction: column;
|
|
}
|
|
.assist-panel {
|
|
width: auto;
|
|
flex: 0 0 45%;
|
|
border-left: none;
|
|
border-top: 1px solid var(--fs-border-color);
|
|
border-radius: var(--fs-radius-lg) var(--fs-radius-lg) 0 0;
|
|
}
|
|
.editor-header {
|
|
padding: 0.75rem 1rem 0.5rem;
|
|
}
|
|
.editor-main {
|
|
padding: 0.5rem 1rem 1rem;
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------------
|
|
* Editor button aliases.
|
|
*
|
|
* These names are used across six views, so they alias onto the shared variants
|
|
* rather than every call site being rewritten — the class stays the app's, the
|
|
* appearance comes from components.css. Same reasoning as .btn-small: a name
|
|
* already in the templates is cheaper to point somewhere than to replace.
|
|
*
|
|
* They are @extend-shaped, which CSS lacks, so each carries the variant's own
|
|
* declarations. That is the one duplication this migration cannot remove — but
|
|
* it is duplication of a REFERENCE (a var()), not of a value, so a palette
|
|
* change still moves everything at once.
|
|
* ------------------------------------------------------------------------ */
|
|
|
|
.btn-accept,
|
|
.btn-generate,
|
|
.btn-save {
|
|
background: var(--fs-action-primary);
|
|
color: var(--fs-text-on-action);
|
|
border: none;
|
|
}
|
|
.btn-accept:not(:disabled):hover,
|
|
.btn-generate:not(:disabled):hover,
|
|
.btn-save:not(:disabled):hover {
|
|
background: var(--fs-action-primary-hover);
|
|
}
|
|
|
|
.btn-back,
|
|
.btn-clear,
|
|
.btn-reject,
|
|
.btn-proofread,
|
|
.btn-suggest-tags {
|
|
background: none;
|
|
border: var(--fs-border);
|
|
color: var(--fs-text-primary);
|
|
}
|
|
.btn-back:not(:disabled):hover,
|
|
.btn-clear:not(:disabled):hover,
|
|
.btn-reject:not(:disabled):hover,
|
|
.btn-proofread:not(:disabled):hover,
|
|
.btn-suggest-tags:not(:disabled):hover {
|
|
border: var(--fs-border-hover);
|
|
background: var(--fs-surface-hover);
|
|
}
|
|
|
|
.btn-delete {
|
|
background: var(--fs-action-destructive);
|
|
color: var(--fs-text-on-action);
|
|
border: none;
|
|
}
|
|
.btn-delete:not(:disabled):hover {
|
|
background: var(--fs-action-destructive-hover);
|
|
}
|
|
|
|
/* Shared geometry for every alias above. */
|
|
.btn-accept, .btn-generate, .btn-save, .btn-back, .btn-clear, .btn-reject,
|
|
.btn-delete, .btn-dismiss-tags, .btn-proofread, .btn-suggest-tags {
|
|
border-radius: var(--fs-radius-md);
|
|
font-family: var(--fs-font-body);
|
|
font-weight: var(--fs-weight-medium);
|
|
cursor: pointer;
|
|
white-space: nowrap;
|
|
transition: background var(--fs-dur-fast) var(--fs-ease),
|
|
border-color var(--fs-dur-fast) var(--fs-ease),
|
|
color var(--fs-dur-fast) var(--fs-ease);
|
|
}
|
|
.btn-accept, .btn-generate, .btn-save, .btn-back, .btn-clear, .btn-reject,
|
|
.btn-delete {
|
|
padding: var(--fs-space-2) var(--fs-space-4);
|
|
font-size: var(--fs-size-label);
|
|
}
|
|
.btn-proofread, .btn-suggest-tags {
|
|
padding: var(--fs-space-1) var(--fs-space-3);
|
|
font-size: var(--fs-size-tiny);
|
|
}
|
|
.btn-dismiss-tags {
|
|
background: none;
|
|
border: none;
|
|
color: var(--fs-text-tertiary);
|
|
padding: 2px var(--fs-space-1);
|
|
font-size: var(--fs-size-tiny);
|
|
line-height: 1;
|
|
}
|
|
.btn-dismiss-tags:hover { color: var(--fs-text-primary); }
|
|
|
|
.btn-accept:disabled, .btn-generate:disabled, .btn-save:disabled,
|
|
.btn-back:disabled, .btn-clear:disabled, .btn-reject:disabled,
|
|
.btn-delete:disabled, .btn-proofread:disabled, .btn-suggest-tags:disabled,
|
|
.btn-dismiss-tags:disabled {
|
|
opacity: var(--fs-disabled-opacity);
|
|
cursor: not-allowed;
|
|
}
|