Files
fusion/packages/dashboard/app/components/SettingsModal.css
gsxdsm b9d60b3c39 FN-7602: fix Record/Clear button overlap in Keyboard Shortcuts rows
Fixes overlapping Record and Clear buttons on the Keyboard Shortcuts settings rows by replacing the icon-only button class with a text button class and locking layout with flex-shrink.

- Swap ShortcutCaptureInput Record/Clear buttons off the icon-only `btn-icon` class (which forced line-height:0 and a 36px mobile square, clipping labels) onto a text-button class
- Add `.shortcut-capture` row CSS with `flex-shrink:0` on controls so the input and buttons never overlap and stack cleanly on mobile
- Add regression tests covering the Keyboard Shortcuts section layout
- Add changeset documenting the fix

Files changed:
 .changeset/fn-7602-shortcut-row-layout.md          |  7 ++
 .../dashboard/app/components/SettingsModal.css     | 17 ++++
 .../settings/sections/ShortcutCaptureInput.tsx     | 14 +++-
 .../__tests__/KeyboardShortcutsSection.test.tsx    | 95 ++++++++++++++++++++++
 4 files changed, 131 insertions(+), 2 deletions(-)

Fusion-Task-Id: FN-7602

Fusion-Task-Lineage: 50cf6975-f0fb-42dd-87b0-50578977a0f4

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-05 18:56:24 -07:00

2604 lines
58 KiB
CSS

/* === SettingsModal: all settings-related layout, panel, and component styles ===
Extracted from styles.css as part of the Sweep-3 CSS extraction effort.
Imported by SettingsModal.tsx (and MemoryView.tsx for shared classes). */
/* === Settings Modal header action buttons (Star on GitHub, Discord) === */
.settings-header-actions {
--settings-header-action-height: calc(var(--space-md) * 2 + var(--space-xs) / 2);
display: flex;
align-items: stretch;
gap: var(--space-xs);
margin-left: auto;
margin-right: var(--space-sm);
}
/* Keep the GitHub Star and Help buttons at matching heights regardless of
their differing icon sizes (provider icon 16px vs. HelpCircle 13px). */
.settings-header-actions > .settings-github-star-btn,
.settings-header-actions > .settings-header-discord-btn {
height: var(--settings-header-action-height);
box-sizing: border-box;
}
.settings-header-discord-btn,
.settings-footer-help-btn {
display: inline-flex;
align-items: center;
}
@media (max-width: 768px) {
/* FN-4375: keep heading, actions, and close in one row on mobile; supersedes FN-4281/FN-4331/FN-4363 wrap/order behavior. */
.settings-modal .modal-header {
flex-wrap: nowrap;
align-items: center;
column-gap: var(--space-sm);
}
.settings-modal-heading {
flex: 1 1 0;
min-width: 0;
}
.settings-header-actions {
margin-left: auto;
margin-right: var(--space-sm);
}
}
/* GitHub star button — split-pill layout: [Star half | Count half] */
.settings-github-star-btn {
display: inline-flex;
align-items: stretch;
border: var(--btn-border-width) solid var(--border);
border-radius: var(--radius-pill);
background: var(--card);
color: var(--text);
font-size: 12px;
font-weight: 500;
text-decoration: none;
overflow: hidden;
transition:
border-color var(--transition-fast),
background var(--transition-fast);
}
.settings-github-star-btn:hover {
border-color: var(--text-muted);
background: var(--card-hover);
}
.settings-github-star-btn:focus-visible {
outline: none;
box-shadow: var(--focus-ring-strong);
border-color: var(--todo);
}
.settings-github-star-btn__action {
display: inline-flex;
align-items: center;
gap: var(--space-xs);
padding: var(--space-xs) calc(var(--space-sm) + var(--space-xs) / 2);
}
.settings-github-star-btn__count {
display: inline-flex;
align-items: center;
padding: var(--space-xs) calc(var(--space-sm) + var(--space-xs) / 4);
border-left: var(--btn-border-width) solid var(--border);
background: color-mix(in srgb, var(--surface) 60%, var(--card));
color: var(--text-muted);
font-variant-numeric: tabular-nums;
}
/* === Settings Modal: sizing + resizability === */
.settings-modal {
width: min(95vw, 1100px);
max-width: 95vw;
min-width: 520px;
height: 80vh;
min-height: 480px;
max-height: calc(100dvh - var(--overlay-padding-top, 10vh) - 16px);
overflow: hidden;
resize: both;
}
/*
FNXC:Settings 2026-06-22-00:00:
Embedded settings is a main-content destination (taskView === "settings"), mirroring Planning/Command Center. The host (.settings-embedded.right-dock-embedded-view) fills the content pane and the inner panel (.settings-modal--embedded) sheds all dialog chrome — fixed dialog sizing, shadow, border, radius, resize grip — so the view sits flush on the project-content surface. Theme tokens only; no hardcoded colors.
FNXC:Settings 2026-06-22-14:36:
The Settings page should match other main-content views with no extra outer inset around the whole box. Keep breathing room inside each settings screen instead so controls never sit directly against the content edge.
*/
.settings-embedded.right-dock-embedded-view {
display: flex;
flex: 1;
width: 100%;
height: 100%;
min-height: 0;
padding: 0;
overflow: hidden;
}
.settings-embedded .settings-modal--embedded {
flex: 1;
width: 100%;
max-width: none;
min-width: 0;
height: 100%;
min-height: 0;
max-height: none;
resize: none;
box-shadow: none;
border: none;
border-radius: 0;
background: transparent;
position: static;
}
/*
FNXC:Settings 2026-06-22-00:00:
The embedded title reads like other embedded-view titles (Planning modal-header--embedded, Command Center cc-title): a plain heading with no tinted modal-header bar, no bottom divider, no close button, aligned to the content edge, at the shared 1.125rem embedded-title size. Header actions (Star/Discord) and footer remain so the full-width panel keeps its controls.
*/
/* FNXC:Settings 2026-06-23-04:45: The embedded Settings header now matches the canonical ViewHeader/other sidebar views exactly — same min-height, space-lg/space-xl padding, surface bg, no bottom divider, var(--todo) icon, 1.125rem/600 title, actions pinned right. */
.settings-modal--embedded .modal-header--embedded {
box-sizing: border-box;
display: flex;
align-items: center;
gap: var(--space-sm);
min-height: var(--view-header-min-height);
padding: var(--space-lg) var(--space-xl);
background: var(--surface);
border-bottom: none;
flex-shrink: 0;
}
.settings-modal--embedded .modal-header--embedded .settings-header-actions {
margin-left: auto;
}
.settings-modal--embedded .modal-header--embedded .settings-modal-heading h3 {
display: flex;
align-items: center;
gap: var(--space-sm);
font-size: 1.125rem;
font-weight: 600;
color: var(--text);
letter-spacing: normal;
}
.settings-modal--embedded .modal-header--embedded .settings-modal-heading svg {
color: var(--todo);
flex-shrink: 0;
}
/* Embedded footer actions sit flush on the content surface (no tinted modal bar).
FNXC:Settings 2026-06-23-04:45: Trim the footer's bottom padding so the space BELOW the Save/Help/Version/Import-Export row matches the space above it (the base .modal-actions var(--modal-padding) left too large a gap under the row in the embedded full-height view). */
.settings-modal--embedded .modal-actions {
background: transparent;
flex-shrink: 0;
padding-bottom: var(--space-sm);
}
/* Mobile: full-screen sheet. The desktop `min-width: 520px` was forcing the
modal wider than narrow viewports, pushing it off-screen; the desktop
`height: 80vh` left awkward strips of overlay above and below. Drop the
overlay's default top padding so the modal actually fills the viewport,
and disable resize (touchscreen users can't drag the grip anyway).
FNXC:Settings 2026-06-22-16:00: scope the viewport-takeover rules to the
NON-embedded (dialog) presentation only via :not(.settings-modal--embedded).
The embedded panel lives inside the main-content pane (between the mobile
Header and MobileNavBar); without the guard its base .settings-modal class
matched these 100vw/100dvh rules and covered the whole screen, hiding the
app header/footer. The embedded view's own fill-the-pane sizing is handled
below. */
@media (max-width: 768px) {
.modal-overlay.settings-modal-overlay,
.modal-overlay:has(.settings-modal:not(.settings-modal--embedded)) {
padding: 0;
inset: 0;
align-items: stretch;
justify-content: stretch;
}
.modal.settings-modal:not(.settings-modal--embedded) {
width: 100vw;
min-width: 0;
max-width: 100vw;
height: 100dvh;
min-height: 100dvh;
max-height: 100dvh;
margin: 0;
border: none;
border-radius: 0;
resize: none;
flex: 1 1 auto;
}
.modal.settings-modal:not(.settings-modal--embedded)[style*="--keyboard-overlap"] {
height: var(--vv-height, 100dvh);
min-height: var(--vv-height, 100dvh);
max-height: var(--vv-height, 100dvh);
transform: translateY(var(--vv-offset-top, 0px));
will-change: transform;
}
/* FNXC:Settings 2026-06-22-16:00: on mobile the embedded settings view fills
only its own content pane (not the viewport) and scrolls internally so the
app Header + MobileNavBar stay visible. Trim the outer host padding so the
panel and its section navigation sit edge-to-edge in the narrow pane. */
.settings-embedded.right-dock-embedded-view {
padding: var(--space-sm);
}
.settings-embedded .settings-modal--embedded {
width: 100%;
height: 100%;
}
}
/* === Settings Layout === */
.settings-modal-heading {
display: flex;
flex-direction: column;
gap: var(--space-xs);
}
.settings-modal-heading h3 {
margin: 0;
}
.settings-modal-version {
margin: 0;
font-size: 0.85rem;
color: var(--text-muted);
font-weight: 500;
}
.settings-modal-footer-version {
display: flex;
align-items: center;
gap: var(--space-xs);
margin-right: var(--space-sm);
min-width: 0;
}
.settings-update-check {
display: flex;
align-items: center;
gap: var(--space-sm);
min-width: 0;
}
@media (max-width: 768px) {
.settings-modal-footer-version {
flex: 1 1 100%;
margin-right: 0;
}
.settings-update-check {
flex-wrap: wrap;
row-gap: var(--space-xs);
}
.settings-update-result {
flex: 1 1 100%;
}
.settings-footer-help-btn {
flex-shrink: 0;
}
}
.settings-version-check-btn {
--settings-inline-touch-target: calc(var(--space-lg) + var(--space-lg) + var(--space-xs));
display: inline-flex;
align-items: center;
gap: var(--space-xs);
margin: 0;
min-height: var(--settings-inline-touch-target);
padding: var(--space-xs) var(--space-sm);
border: none;
background: transparent;
color: var(--text-muted);
cursor: pointer;
transition: opacity var(--transition-fast), box-shadow var(--transition-fast);
}
.settings-version-check-btn:hover:not(:disabled) {
opacity: 0.85;
}
.settings-version-check-btn:focus-visible {
outline: none;
box-shadow: var(--focus-ring-strong);
border-radius: var(--radius-sm);
}
.settings-version-check-btn:disabled {
cursor: default;
opacity: 0.7;
}
.settings-version-check-btn svg {
color: var(--text-muted);
}
.settings-version-check-btn svg.spinning {
animation: settings-update-spin 1s linear infinite;
}
.settings-update-result {
display: inline-flex;
align-items: center;
flex-wrap: wrap;
gap: var(--space-xs);
font-size: 0.85rem;
font-weight: 500;
}
.settings-update-result--up-to-date {
color: var(--color-success);
}
.settings-update-result--available {
color: var(--color-info);
}
.settings-update-result--error {
color: var(--color-error);
}
.settings-update-result-link {
color: var(--color-info);
text-decoration: underline;
transition: color var(--transition-fast), box-shadow var(--transition-fast);
}
.settings-update-result-link:hover {
color: color-mix(in srgb, var(--color-info) 80%, var(--text));
}
.settings-update-result-link:focus-visible {
outline: none;
box-shadow: var(--focus-ring-strong);
border-radius: var(--radius-sm);
}
.settings-update-now-btn {
display: inline-flex;
align-items: center;
gap: var(--space-xs);
min-height: calc(var(--space-lg) + var(--space-sm));
color: var(--text);
}
.settings-update-now-btn:disabled {
color: var(--color-warning);
}
.settings-update-now-btn svg.spinning {
animation: settings-update-spin 1s linear infinite;
}
.settings-update-install-status {
color: var(--text-muted);
}
.settings-update-install-status--success {
color: var(--color-success);
}
.settings-update-install-status--error {
color: var(--color-error);
}
@keyframes settings-update-spin {
to {
transform: rotate(360deg);
}
}
/* === Settings Backups: summary stats + backup list === */
.backup-stats {
display: flex;
align-items: center;
gap: var(--space-lg);
padding: var(--space-sm) var(--space-md);
border: var(--btn-border-width) solid var(--border);
border-radius: var(--radius-md);
background: color-mix(in srgb, var(--surface) 85%, transparent);
}
.backup-stat {
display: flex;
flex: 1 1 0;
flex-direction: column;
align-items: center;
gap: var(--space-xs);
min-width: 0;
}
.backup-stat-value {
color: var(--text);
font-size: 1rem;
font-weight: 600;
font-variant-numeric: tabular-nums;
}
.backup-stat-label {
color: var(--text-muted);
font-size: 0.75rem;
font-weight: 600;
letter-spacing: 0.04em;
text-transform: uppercase;
}
.backup-list {
margin-top: var(--space-sm);
}
.backup-list summary {
padding: var(--space-sm) 0;
color: var(--text-muted);
cursor: pointer;
transition: color var(--transition-fast);
}
.backup-list summary:hover {
color: var(--text);
}
.backup-list summary:focus-visible {
outline: none;
border-radius: var(--radius-sm);
box-shadow: var(--focus-ring-strong);
}
.backup-list ul {
display: flex;
flex-direction: column;
gap: var(--space-xs);
margin: 0;
margin-top: var(--space-sm);
padding: 0;
list-style: none;
}
.backup-list li {
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--space-sm);
padding: var(--space-sm) 0;
border-top: var(--btn-border-width) solid color-mix(in srgb, var(--border) 80%, transparent);
}
.backup-list li code {
min-width: 0;
color: var(--text);
font-family: var(--font-mono);
font-size: 0.75rem;
white-space: nowrap;
overflow-x: auto;
}
.backup-size {
color: var(--text-muted);
font-family: var(--font-mono);
font-size: 0.75rem;
text-align: right;
white-space: nowrap;
}
@media (max-width: 768px) {
.backup-stats {
flex-direction: column;
align-items: stretch;
gap: var(--space-sm);
}
.backup-stat {
align-items: flex-start;
}
.backup-list ul {
max-height: calc(var(--space-xl) * 9 + var(--space-md));
overflow-y: auto;
-webkit-overflow-scrolling: touch;
}
.backup-list li code {
white-space: normal;
overflow-wrap: anywhere;
word-break: normal;
}
}
.settings-layout {
display: flex;
flex: 1;
flex-direction: row;
min-height: 0;
overflow: hidden;
}
.settings-navigation {
width: calc(var(--space-xl) * 7 + var(--space-sm));
min-width: calc(var(--space-xl) * 7 + var(--space-sm));
border-right: var(--btn-border-width) solid var(--border);
display: flex;
flex-direction: column;
min-height: 0;
background: color-mix(in srgb, var(--text) 10%, transparent);
}
.settings-search {
display: flex;
flex-direction: column;
gap: var(--space-xs);
padding: var(--space-sm);
border-bottom: var(--btn-border-width) solid var(--border);
}
.settings-search-label {
color: var(--text-muted);
font-size: 0.75rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.settings-search-input-wrap {
display: flex;
align-items: center;
gap: var(--space-xs);
min-width: 0;
}
.settings-search-input {
min-width: 0;
width: 100%;
}
.settings-search-clear {
flex-shrink: 0;
}
.settings-search-results,
.settings-search-empty-hint {
color: var(--text-muted);
font-size: 0.75rem;
margin: 0;
}
.settings-search-empty {
display: flex;
flex-direction: column;
gap: var(--space-sm);
padding: var(--space-md);
color: var(--text-muted);
}
.settings-search-empty p,
.settings-search-content-empty p {
margin: 0;
}
.settings-search-content-empty {
gap: var(--space-md);
}
.settings-mobile-section-picker {
display: none;
}
.settings-sidebar {
display: flex;
flex: 1;
flex-direction: column;
min-height: 0;
overflow-y: auto;
padding: var(--space-sm) var(--space-sm);
gap: calc(var(--space-xs) / 2);
scrollbar-color: var(--border) transparent;
scrollbar-width: thin;
}
.settings-sidebar::-webkit-scrollbar {
width: 6px;
}
.settings-sidebar::-webkit-scrollbar-track {
background: transparent;
}
.settings-sidebar::-webkit-scrollbar-thumb {
background: var(--border);
border-radius: var(--radius-sm);
}
.settings-sidebar::-webkit-scrollbar-thumb:hover {
background: var(--text-muted);
}
.settings-research-source-locked {
cursor: default;
color: var(--text-muted) !important;
}
.settings-research-source-locked input[type="checkbox"] {
cursor: not-allowed;
}
.settings-research-source-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: var(--space-sm);
min-width: 0;
}
.settings-research-source-grid > * {
min-width: 0;
}
.settings-research-limits-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: var(--space-sm);
min-width: 0;
}
.settings-research-limits-grid > * {
min-width: 0;
}
.settings-research-limit-field {
display: flex;
flex-direction: column;
gap: var(--space-xs);
min-width: 0;
}
.settings-research-limits-error {
grid-column: 1 / -1;
}
@media (max-width: 768px) {
.settings-research-source-grid,
.settings-research-limits-grid {
grid-template-columns: 1fr;
}
}
.settings-nav-item {
display: block;
width: 100%;
padding: var(--space-sm) var(--space-md);
font-size: 13px;
font-weight: 500;
color: var(--text-muted);
background: none;
border: none;
border-left: 3px solid transparent;
border-radius: 0 var(--radius-md) var(--radius-md) 0;
cursor: pointer;
text-align: left;
transition:
background var(--transition-fast),
color var(--transition-fast),
border-color var(--transition-fast);
}
.settings-nav-item:hover {
background: var(--bg);
color: var(--text);
border-left-color: var(--border);
}
.settings-nav-item:focus-visible {
box-shadow: var(--focus-ring-strong);
outline: none;
}
.settings-nav-item.active {
background: var(--bg);
color: var(--todo);
font-weight: 600;
border-left-color: var(--todo);
}
/* Settings group headers - visual separators between global and project sections */
.settings-group-header {
font-size: 10px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--text-muted);
padding: var(--space-md) var(--space-md) var(--space-xs);
margin-top: var(--space-sm);
user-select: none;
}
.settings-group-header:first-child {
margin-top: 0;
}
.settings-content {
flex: 1;
overflow-x: hidden;
overflow-y: auto;
padding: var(--space-md) var(--space-xl) var(--space-lg);
scrollbar-color: var(--border) transparent;
scrollbar-width: thin;
}
.settings-content::-webkit-scrollbar {
width: 6px;
}
.settings-content::-webkit-scrollbar-track {
background: transparent;
}
.settings-content::-webkit-scrollbar-thumb {
background: var(--border);
border-radius: var(--radius-sm);
}
.settings-content::-webkit-scrollbar-thumb:hover {
background: var(--text-muted);
}
.settings-content > * {
animation: settingsFadeIn var(--duration-normal) ease;
}
@keyframes settingsFadeIn {
from {
opacity: 0;
transform: translateY(4px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/*
FNXC:SettingsMobile 2026-06-23-09:02:
Settings section headings should preserve hierarchy through spacing and type only. Avoid per-heading divider borders so mobile and desktop shared Settings sections keep the lighter scrollbar-focused chrome contract.
*/
.settings-section-heading {
font-size: 14px;
font-weight: 600;
padding: var(--space-lg) 0 var(--space-md);
margin: 0 0 var(--space-md);
color: var(--text);
}
/* First heading inside the section drops top padding to remove a redundant
gap stacked on top of the settings-content container's own top padding. */
.settings-content > .settings-section-heading:first-child,
.settings-modal-section > .settings-section-heading:first-child {
padding-top: var(--space-md);
}
/* Spacing modifier for settings-section-heading that need extra top margin */
.settings-section-heading--spaced {
margin-top: var(--space-lg);
}
.settings-section-description {
margin: 0;
margin-bottom: var(--space-sm);
color: var(--text-muted);
font-size: 13px;
line-height: 1.5;
}
.settings-plugins-subsection-toggle {
display: inline-flex;
gap: var(--space-xs);
margin: var(--space-md) 0;
}
.settings-plugins-subsection-btn {
display: inline-flex;
align-items: center;
justify-content: center;
border: var(--btn-border-width) solid var(--border);
border-radius: var(--radius-pill);
background: var(--surface);
color: var(--text-muted);
font-size: 0.85rem;
font-weight: 600;
padding: var(--space-xs) var(--space-md);
cursor: pointer;
transition:
background var(--transition-fast),
color var(--transition-fast),
border-color var(--transition-fast),
box-shadow var(--transition-fast);
}
.settings-plugins-subsection-btn:hover {
background: var(--surface-hover, color-mix(in srgb, var(--text) 6%, transparent));
color: var(--text);
}
.settings-plugins-subsection-btn:focus-visible {
outline: none;
box-shadow: var(--focus-ring-strong);
}
.settings-plugins-subsection-btn.active {
background: color-mix(in srgb, var(--todo) 14%, transparent);
border-color: color-mix(in srgb, var(--todo) 45%, var(--border));
color: var(--todo);
}
.settings-plugins-subsection-panel {
padding-bottom: var(--space-md);
}
/* Scope indicators in sidebar nav items */
.settings-scope-icon {
margin-right: 6px;
display: inline-flex;
vertical-align: middle;
color: var(--text-muted);
}
/* Scope banner above section content */
.settings-scope-banner {
display: flex;
align-items: center;
gap: var(--space-sm);
padding: var(--space-sm) var(--space-xl);
margin: 0 var(--space-xl) var(--space-xs);
font-size: 12px;
border-radius: var(--radius-md);
color: var(--text-muted);
}
.settings-scope-global {
background: color-mix(in srgb, var(--color-info) 8%, transparent);
border-left: 3px solid color-mix(in srgb, var(--color-info) 40%, transparent);
}
.settings-scope-project {
background: color-mix(in srgb, var(--color-success) 8%, transparent);
border-left: 3px solid color-mix(in srgb, var(--color-success) 40%, transparent);
}
.settings-scope-mixed {
background: color-mix(in srgb, var(--triage) 8%, transparent);
border-left: 3px solid color-mix(in srgb, var(--triage) 40%, transparent);
}
/* Helper note styling for Settings sections — aligns with form-group horizontal gutters */
.settings-note {
display: block;
padding: 0 var(--space-xl);
margin-top: var(--space-xs);
font-size: 12px;
color: var(--text-muted);
}
/* Inline text input + secondary action ("Use dropdown") for fields that
sometimes want a free-text fallback. */
.form-inline-group {
display: flex;
align-items: center;
gap: var(--space-sm);
}
.form-inline-group .input {
flex: 1;
min-width: 0;
}
.btn-link {
background: none;
border: none;
padding: 0;
font-size: 12px;
color: var(--accent, #4a90e2);
cursor: pointer;
text-decoration: underline;
white-space: nowrap;
}
.btn-link:hover {
text-decoration: none;
}
.settings-overlap-ignore-group code {
font-family: var(--font-mono);
font-size: 0.9em;
}
.settings-button-row {
display: flex;
flex-wrap: wrap;
gap: var(--space-sm);
margin-top: var(--space-sm);
}
.settings-raw-output {
margin: var(--space-sm) 0 0;
padding: var(--space-sm);
border: 1px solid var(--border);
border-radius: var(--radius-sm);
background: var(--surface);
color: var(--text-muted);
max-height: calc(var(--space-2xl) * 7);
overflow: auto;
font-family: var(--font-mono);
font-size: calc(var(--space-sm) + var(--space-xs));
}
.settings-url-output {
display: block;
margin-top: var(--space-xs);
padding: var(--space-sm);
border: 1px solid var(--border);
border-radius: var(--radius-sm);
background: var(--surface);
color: var(--text-muted);
font-family: var(--font-mono);
font-size: calc(var(--space-sm) + var(--space-xs));
overflow-wrap: anywhere;
word-break: break-word;
overflow-x: auto;
max-width: 100%;
}
.settings-qr-preview {
margin-top: var(--space-sm);
display: flex;
flex-direction: column;
gap: var(--space-sm);
}
.settings-qr-preview-label {
margin: 0;
font-size: calc(var(--space-sm) + var(--space-xs));
color: var(--text-muted);
}
.settings-qr-preview-image-wrap {
width: fit-content;
max-width: 100%;
padding: var(--space-sm);
border: 1px solid var(--border);
border-radius: var(--radius-sm);
background: var(--card);
}
.settings-qr-preview-image {
display: block;
width: min(calc(var(--space-2xl) * 6), 100%);
height: auto;
aspect-ratio: 1 / 1;
}
.remote-provider-selector {
display: flex;
gap: var(--space-xs);
border: var(--btn-border-width) solid var(--border);
border-radius: var(--radius-md);
padding: var(--space-xs);
background: var(--surface);
}
.remote-provider-option {
position: relative;
flex: 1;
cursor: pointer;
}
.remote-provider-option input {
position: absolute;
opacity: 0;
width: 0;
height: 0;
}
.remote-provider-option span {
display: block;
padding: var(--space-sm) var(--space-md);
text-align: center;
border-radius: var(--radius-sm);
border: var(--btn-border-width) solid transparent;
color: var(--text-muted);
transition: background var(--transition-fast), color var(--transition-fast), border-color var(--transition-fast);
}
.remote-provider-option-content {
display: inline-flex;
align-items: center;
gap: var(--space-xs);
}
.remote-provider-option input:checked + span {
background: var(--card);
color: var(--text);
border-color: var(--border);
}
.remote-provider-option input:focus-visible + span {
box-shadow: var(--focus-ring-strong);
}
.remote-status-bar {
--status-color: var(--text-muted);
display: flex;
align-items: center;
gap: var(--space-sm);
padding: var(--space-sm) var(--space-md);
border-radius: var(--radius-md);
margin: 0 var(--space-xl) var(--space-md);
background: color-mix(in srgb, var(--status-color) 10%, transparent);
}
.remote-status-bar--running {
--status-color: var(--color-success);
}
.remote-status-bar--starting {
--status-color: var(--color-warning);
}
.remote-status-bar--error {
--status-color: var(--color-error);
}
.remote-status-bar--stopped {
--status-color: var(--text-muted);
}
.remote-share-block {
display: flex;
flex-direction: column;
gap: var(--space-sm);
margin: 0 var(--space-xl) var(--space-md);
padding: var(--space-sm) var(--space-md);
border: 1px solid var(--border);
border-radius: var(--radius-md);
background: color-mix(in srgb, var(--text-muted) 5%, transparent);
}
.remote-share-row {
display: flex;
flex-direction: column;
gap: var(--space-xs);
}
.remote-share-row .settings-qr-preview-image {
margin-top: var(--space-xs);
}
.remote-status-dot {
width: var(--space-sm);
height: var(--space-sm);
border-radius: 50%;
display: inline-block;
flex-shrink: 0;
}
.remote-status-dot--running {
background: var(--color-success);
}
.remote-status-dot--starting {
background: var(--color-warning);
}
.remote-status-dot--error {
background: var(--color-error);
}
.remote-status-dot--stopped {
background: var(--text-muted);
}
.remote-status-url {
margin-left: auto;
font-family: var(--font-mono);
overflow-wrap: anywhere;
word-break: break-word;
user-select: all;
}
.remote-provider-settings {
display: flex;
flex-direction: column;
gap: var(--space-sm);
}
.remote-cli-detection {
display: flex;
align-items: flex-start;
gap: var(--space-sm);
margin: 0 var(--space-xl) var(--space-md);
padding: var(--space-sm) var(--space-md);
border-radius: var(--radius-sm);
}
.remote-cli-detection--available {
background: color-mix(in srgb, var(--color-success) 10%, transparent);
color: var(--color-success);
}
.remote-cli-detection--missing {
background: color-mix(in srgb, var(--color-warning) 10%, transparent);
color: var(--color-warning);
}
.remote-cli-detection-content {
display: flex;
flex-direction: column;
gap: var(--space-xs);
color: var(--text);
}
.remote-cli-detection .btn {
align-self: flex-start;
}
.remote-cli-install-error {
color: var(--color-error);
}
.remote-cli-manual {
color: var(--text-dim);
}
.remote-external-tunnel-panel {
display: flex;
flex-direction: column;
gap: var(--space-sm);
margin: 0 var(--space-xl) var(--space-md);
padding: var(--space-sm) var(--space-md);
border: 1px solid var(--border);
border-radius: var(--radius-md);
background: color-mix(in srgb, var(--color-info) 10%, transparent);
}
.remote-external-tunnel-header {
display: flex;
align-items: center;
gap: var(--space-sm);
color: var(--color-info);
}
.remote-external-tunnel-qr {
display: flex;
flex-direction: column;
gap: var(--space-xs);
}
.remote-external-tunnel-actions {
display: flex;
flex-direction: column;
gap: var(--space-sm);
}
.remote-advanced-details {
margin: var(--space-lg) var(--space-xl) 0;
border: var(--btn-border-width) solid var(--border);
border-radius: var(--radius-md);
padding: var(--space-md);
background: var(--surface);
}
.remote-advanced-details > summary {
cursor: pointer;
color: var(--text-muted);
font-size: calc(var(--space-sm) + var(--space-xs));
list-style: none;
}
.remote-advanced-details > summary::-webkit-details-marker {
display: none;
}
.remote-advanced-details > summary::before {
content: "▸";
margin-right: var(--space-xs);
}
.remote-advanced-details[open] > summary::before {
content: "▾";
}
.settings-option-details {
margin-top: var(--space-xs);
}
.settings-research-provider-group {
display: flex;
flex-direction: column;
gap: var(--space-sm);
min-width: 0;
}
.settings-research-provider-advanced-details {
min-width: 0;
padding-inline-start: var(--space-md);
}
.settings-research-provider-advanced-body {
display: flex;
flex-direction: column;
gap: var(--space-sm);
min-width: 0;
padding-top: var(--space-sm);
}
.settings-research-provider-advanced-body > .form-group {
margin-top: 0;
padding: 0;
min-width: 0;
}
.settings-research-provider-advanced-body .input {
width: 100%;
min-width: 0;
}
.settings-research-empty-state {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--space-sm);
min-width: 0;
}
@media (max-width: 768px) {
.settings-research-provider-advanced-details {
padding-inline-start: 0;
}
}
.settings-option-details > summary {
cursor: pointer;
color: var(--text-muted);
font-size: calc(var(--space-sm) + var(--space-xs));
list-style: none;
}
.settings-option-details > summary::-webkit-details-marker {
display: none;
}
.settings-option-details > summary::before {
content: "▸";
margin-right: var(--space-xs);
}
.settings-option-details[open] > summary::before {
content: "▾";
}
/*
FNXC:GitLabSettings 2026-07-02-00:00:
FN-7453 keeps GitLab's enable switch visible while hiding noisy URL/token fields behind native details disclosure. The layout uses token spacing and native summary semantics so collapsed and disabled states do not leave empty icon-button shells or focusable hidden fields.
*/
.settings-gitlab-disclosure {
display: flex;
flex-direction: column;
gap: var(--space-sm);
margin-top: var(--space-md);
padding: var(--space-md);
border: var(--btn-border-width) solid var(--border);
border-radius: var(--radius-md);
background: var(--surface-secondary);
}
.settings-gitlab-disclosure > summary {
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--space-md);
cursor: pointer;
list-style: none;
color: var(--text-primary);
}
.settings-gitlab-disclosure > summary::-webkit-details-marker {
display: none;
}
.settings-gitlab-disclosure > summary::before {
content: "▸";
color: var(--text-muted);
}
.settings-gitlab-disclosure[open] > summary::before {
content: "▾";
}
.settings-gitlab-disclosure__title {
flex: 1 1 auto;
font-weight: var(--font-weight-semibold);
min-width: 0;
}
.settings-gitlab-disclosure__toggle {
flex: 0 0 auto;
}
.settings-gitlab-disclosure__body {
display: flex;
flex-direction: column;
gap: var(--space-sm);
margin-top: var(--space-sm);
min-width: 0;
}
.settings-gitlab-disclosure__body > .form-group {
margin-top: 0;
padding: 0;
}
@media (max-width: 768px) {
.settings-gitlab-disclosure {
padding: var(--space-sm);
}
.settings-gitlab-disclosure > summary {
align-items: flex-start;
flex-wrap: wrap;
gap: var(--space-sm);
}
.settings-gitlab-disclosure__toggle {
flex-basis: 100%;
}
}
.remote-cf-advanced-details {
margin-top: var(--space-xs);
}
.remote-cf-advanced-details > summary {
cursor: pointer;
color: var(--text-muted);
font-size: calc(var(--space-sm) + var(--space-xs));
list-style: none;
}
.remote-cf-advanced-details > summary::-webkit-details-marker {
display: none;
}
.remote-cf-advanced-details > summary::before {
content: "▸";
margin-right: var(--space-xs);
}
.remote-cf-advanced-details[open] > summary::before {
content: "▾";
}
.remote-cf-advanced-fields {
display: flex;
flex-direction: column;
gap: var(--space-sm);
margin-top: var(--space-sm);
}
.remote-tunnel-actions {
margin-top: var(--space-md);
}
.remote-tunnel-actions .btn {
width: 100%;
}
.settings-overlap-ignore-list {
display: flex;
flex-direction: column;
gap: var(--space-sm);
margin: var(--space-sm) 0;
}
.settings-overlap-ignore-row {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
gap: var(--space-sm);
align-items: center;
}
.settings-overlap-ignore-path-controls {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
gap: var(--space-sm);
align-items: center;
}
.settings-overlap-path-picker-modal {
max-width: min(960px, calc(100vw - var(--space-2xl)));
}
.settings-overlap-path-picker-body {
display: flex;
flex-direction: column;
gap: var(--space-sm);
max-height: min(70vh, 720px);
}
.settings-overlap-path-picker-note {
margin: 0;
font-size: 12px;
color: var(--text-muted);
}
.settings-section-divider {
border-top: 1px solid var(--border);
margin: var(--space-lg) var(--space-xl);
}
/*
FNXC:SettingsReset 2026-07-04-00:45:
Reset Settings confirmation dialog (FN-7506). Reuses .modal/.modal-md/.modal-overlay/
.modal-actions chrome; only the choice-list layout and destructive-reason hint are new.
Design tokens only (spacing/radius/color vars), no hardcoded px besides 0.
*/
.settings-reset-dialog__choice {
display: flex;
flex-direction: column;
gap: var(--space-xs);
margin-block-end: var(--space-md);
}
.settings-reset-dialog__choice-btn {
align-self: flex-start;
width: 100%;
}
.settings-reset-dialog__ineligible-reason {
color: var(--text-muted);
}
@media (max-width: 768px) {
.settings-reset-dialog {
max-width: calc(100vw - var(--space-md));
}
.settings-reset-dialog__choice-btn {
/* Full-width tappable target at narrow widths; avoids horizontal overflow. */
width: 100%;
}
}
@media (max-width: 768px) {
.settings-note {
padding: 0 var(--space-lg);
}
.settings-overlap-ignore-row {
grid-template-columns: minmax(0, 1fr);
}
.settings-overlap-ignore-path-controls {
grid-template-columns: minmax(0, 1fr);
}
.settings-overlap-ignore-row > .btn {
justify-self: start;
}
.settings-overlap-path-picker-modal {
max-width: calc(100vw - var(--space-md));
}
.remote-provider-selector {
flex-direction: column;
}
.remote-status-bar {
flex-wrap: wrap;
margin: 0 var(--space-lg) var(--space-md);
}
.remote-share-block {
margin: 0 var(--space-lg) var(--space-md);
}
.remote-status-url {
width: 100%;
margin-left: 0;
font-size: 0.8em;
}
.remote-provider-option {
min-height: 36px;
}
.remote-tunnel-actions .btn {
min-height: 36px;
}
.remote-cli-detection {
margin: 0 var(--space-lg) var(--space-md);
}
.remote-external-tunnel-panel {
margin: 0 var(--space-lg) var(--space-md);
}
}
/* === Notifications Settings === */
.ntfy-advanced-disclosure {
margin-top: var(--space-md);
border: var(--btn-border-width) solid var(--border);
border-radius: var(--radius-md);
background: var(--surface);
}
.ntfy-advanced-disclosure > summary {
cursor: pointer;
list-style: none;
padding: var(--space-sm) var(--space-md);
font-size: 12px;
font-weight: 600;
color: var(--text);
}
.ntfy-advanced-disclosure > summary::-webkit-details-marker {
display: none;
}
.ntfy-advanced-content {
padding: 0 var(--space-md) var(--space-md);
display: flex;
flex-direction: column;
gap: var(--space-sm);
}
.settings-inline-link {
color: var(--todo);
text-decoration: none;
transition: text-decoration var(--transition-fast);
}
.settings-inline-link:hover {
text-decoration: underline;
}
.settings-inline-link:focus-visible {
outline: none;
box-shadow: var(--focus-ring-strong);
border-radius: var(--radius-sm);
}
/**
* Notification provider cards:
* reusable container pattern for per-provider notification configuration
* (ntfy, webhook, and future providers).
*/
.notification-provider-card {
border: var(--btn-border-width) solid var(--border);
border-radius: var(--radius-lg);
background: var(--surface);
margin: 0 var(--space-xl) var(--space-lg);
overflow: hidden;
}
.notification-provider-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: var(--space-md) var(--space-lg);
border-bottom: var(--btn-border-width) solid var(--border);
}
.notification-provider-body {
padding: var(--space-lg);
display: flex;
flex-direction: column;
gap: var(--space-lg);
}
.notification-provider-actions {
display: flex;
flex-wrap: wrap;
gap: var(--space-sm);
padding-top: var(--space-md);
border-top: var(--btn-border-width) solid var(--border);
margin-top: var(--space-md);
}
.notification-test-feedback {
display: flex;
flex-direction: column;
gap: var(--space-xs);
margin-top: var(--space-sm);
}
.notification-test-feedback-item {
border: var(--btn-border-width) solid var(--border);
border-radius: var(--radius-sm);
padding: var(--space-xs) var(--space-sm);
}
.notification-test-feedback-item--success {
border-color: color-mix(in srgb, var(--color-success) 45%, var(--border));
background: color-mix(in srgb, var(--color-success) 8%, transparent);
color: var(--color-success);
}
.notification-test-feedback-item--error {
border-color: color-mix(in srgb, var(--color-error) 45%, var(--border));
background: color-mix(in srgb, var(--color-error) 8%, transparent);
color: var(--color-error);
}
@media (max-width: 768px) {
.notification-provider-actions {
flex-direction: column;
}
.notification-provider-actions .btn {
width: 100%;
}
}
/* === Memory Settings === */
.memory-status-message {
display: flex;
gap: var(--space-md);
align-items: center;
justify-content: space-between;
margin-bottom: var(--space-md);
}
.memory-status-message span {
min-width: 0;
}
.memory-retrieval-test {
margin-top: var(--space-lg);
}
.memory-test-result {
margin: 0 var(--space-xl) var(--space-lg);
padding: var(--space-md);
border: var(--btn-border-width) solid var(--border);
border-radius: var(--radius-md);
background: var(--card);
}
.memory-test-result strong,
.memory-test-result span {
color: var(--text);
font-size: 12px;
}
.memory-test-result small {
display: block;
margin-top: var(--space-xs);
color: var(--text-muted);
font-size: 12px;
}
.memory-test-result ul {
margin: var(--space-md) 0 0;
padding: 0;
list-style: none;
}
.memory-test-result li {
padding-top: var(--space-sm);
border-top: var(--btn-border-width) solid var(--border);
}
.memory-test-result li + li {
margin-top: var(--space-sm);
}
.memory-test-result p {
margin: var(--space-xs) 0 0;
color: var(--text-muted);
font-size: 12px;
line-height: 1.5;
overflow-wrap: anywhere;
}
.memory-editor-section {
margin-top: var(--space-lg);
display: flex;
flex: 1 1 auto;
flex-direction: column;
min-height: 0;
}
.memory-editor-form-group {
display: flex;
flex: 1 1 auto;
flex-direction: column;
min-height: 0;
}
.memory-file-summary {
display: grid;
grid-template-columns: auto minmax(0, 1fr);
gap: var(--space-xs) var(--space-md);
align-items: center;
margin: 0 var(--space-xl) var(--space-md);
padding: var(--space-md);
border: var(--btn-border-width) solid var(--border);
border-radius: var(--radius-md);
background: var(--card);
}
.memory-file-summary span {
display: inline-flex;
align-items: center;
justify-content: center;
padding: var(--space-xs) var(--space-sm);
border-radius: var(--radius-pill);
color: var(--color-info);
background: color-mix(in srgb, var(--color-info) 12%, transparent);
font-size: 11px;
font-weight: 600;
}
.memory-file-summary strong {
min-width: 0;
overflow-wrap: anywhere;
color: var(--text);
font-family: var(--font-mono);
font-size: 12px;
}
.memory-file-summary small {
grid-column: 2;
color: var(--text-muted);
font-size: 12px;
}
.memory-editor-frame {
min-height: 50vh;
border: var(--btn-border-width) solid var(--border);
border-radius: var(--radius-md);
overflow: hidden;
display: flex;
flex: 1 1 auto;
flex-direction: column;
min-width: 0;
}
/* === Auth Provider Cards === */
/* Horizontal gutter wrapper for the auth section body. Tighter than the
default form-group gutter so each provider card gets more horizontal room
— the cards are dense enough that the wider --space-xl gutter wasted
visible width without any visual benefit. */
.auth-panel-body {
padding-inline: var(--space-md);
}
.auth-section-hint {
padding: var(--space-md) var(--space-lg);
margin-bottom: var(--space-md);
background: var(--bg-tertiary);
border-radius: var(--radius-md);
font-size: 13px;
color: var(--text-muted);
border-left: 3px solid var(--text-muted);
}
.auth-provider-group {
margin-bottom: calc(var(--space-sm) + var(--space-xs) / 2);
}
.auth-group-label {
font-size: 11px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.5px;
color: var(--text-muted);
margin-bottom: var(--space-xs);
padding: 0 4px;
}
.auth-provider-card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius-md);
margin-bottom: var(--space-xs);
overflow: hidden;
transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}
.auth-provider-card:hover {
border-color: var(--text-dim);
}
.auth-provider-card--authenticated {
border-color: color-mix(in srgb, var(--color-success) 40%, var(--border));
background: color-mix(in srgb, var(--color-success) 5%, var(--surface));
}
.auth-provider-card--authenticated:hover {
border-color: color-mix(in srgb, var(--color-success) 60%, var(--border));
}
.auth-provider-header {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
padding: var(--space-sm) var(--space-md);
gap: 12px;
}
.auth-provider-info {
display: flex;
align-items: center;
gap: 10px;
flex-wrap: wrap;
flex: 1;
min-width: 0;
}
.auth-provider-info strong {
font-weight: 500;
color: var(--text);
}
.auth-provider-icon-slot {
display: inline-flex;
align-items: center;
justify-content: center;
inline-size: calc(var(--space-md) + var(--space-xs) * 2);
block-size: calc(var(--space-md) + var(--space-xs) * 2);
flex-shrink: 0;
}
.auth-provider-icon-slot .provider-icon {
display: inline-flex;
}
.auth-hint {
display: block;
padding: 12px 4px 0;
font-size: 12px;
color: var(--text-muted);
border-top: 1px solid var(--border);
margin-top: 8px;
}
.auth-apikey-section {
display: flex;
flex-direction: column;
gap: var(--space-xs);
align-items: flex-end;
flex-shrink: 0;
}
.auth-apikey-input-row {
display: flex;
gap: 6px;
align-items: center;
}
.auth-apikey-input {
background: var(--surface-1);
border: 1px solid var(--border);
border-radius: 6px;
color: var(--text);
padding: 6px 10px;
font-size: 13px;
width: 180px;
font-family: monospace;
}
.auth-apikey-input:focus {
outline: none;
border-color: var(--todo);
box-shadow: var(--focus-ring);
}
.auth-apikey-input:disabled {
opacity: 0.6;
}
.auth-apikey-progress {
font-size: calc(var(--space-sm) + var(--space-xs) * 0.75);
color: var(--text-muted);
padding-right: 4px;
}
.auth-apikey-error {
font-size: 11px;
color: var(--color-error);
padding-right: 4px;
}
.auth-provider-actions-row {
display: flex;
width: 100%;
align-items: center;
gap: var(--space-sm);
}
.auth-device-code-panel {
width: 100%;
margin-top: var(--space-sm);
padding: var(--space-sm);
border: var(--btn-border-width) solid var(--border);
border-radius: var(--radius-md);
background: color-mix(in srgb, var(--surface) 85%, transparent);
display: flex;
flex-direction: column;
gap: var(--space-sm);
}
.auth-device-code-pill {
font-family: var(--font-mono);
font-size: calc(var(--space-md) + var(--space-xs) * 0.5);
letter-spacing: var(--space-xs);
padding: var(--space-sm) var(--space-md);
border-radius: var(--radius-pill);
border: var(--btn-border-width) solid var(--border);
background: var(--card);
color: var(--text);
display: flex;
align-self: stretch;
}
/* === Key Hint === */
.auth-key-hint {
font-family: var(--font-mono);
font-size: 12px;
color: var(--text-muted);
display: inline-block;
margin-top: var(--space-xs);
user-select: none;
}
/* === Model Lane Status Badges === */
.settings-lane-badge {
display: inline-flex;
align-items: center;
padding: 2px 8px;
border-radius: 10px;
font-size: 11px;
font-weight: 500;
white-space: nowrap;
}
.settings-lane-badge--override {
background-color: color-mix(in srgb, var(--todo) 20%, transparent);
color: var(--todo);
}
.settings-lane-badge--inherited {
background-color: color-mix(in srgb, var(--text-muted) 15%, transparent);
color: var(--text-muted);
}
/*
FNXC:SettingsScopeGrouping 2026-06-25-10:42:
Mobile settings must make clear which controls are global (all projects) vs project-scoped; group scheduling fields under labeled Global/This-project subheadings with a scope badge so operators don't mistake the global concurrency cap for a per-project setting.
The header row wraps so the badge drops below the heading on narrow widths instead of overflowing.
*/
.settings-scope-group {
margin-top: var(--space-md);
}
.settings-scope-group-header {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--space-sm);
}
.settings-scope-group-header .settings-section-heading {
padding-bottom: 0;
margin-bottom: 0;
}
.settings-scope-badge {
display: inline-flex;
align-items: center;
padding: 2px 8px;
border-radius: 10px;
font-size: 11px;
font-weight: 500;
white-space: nowrap;
}
.settings-scope-badge--global {
background-color: color-mix(in srgb, var(--accent, #4a90e2) 18%, transparent);
color: var(--accent, #4a90e2);
}
.settings-scope-badge--project {
background-color: color-mix(in srgb, var(--text-muted) 15%, transparent);
color: var(--text-muted);
}
.settings-scope-caption {
display: block;
margin: var(--space-xs) 0 var(--space-md);
color: var(--text-muted);
font-size: 12px;
line-height: 1.4;
}
.settings-description {
font-size: 13px;
color: var(--text-dim);
padding-inline: var(--space-xl);
margin-block: 0 var(--space-md);
line-height: 1.5;
}
.settings-token-cap-row {
display: flex;
align-items: center;
gap: var(--space-sm);
}
.settings-model-lane-label-row {
display: flex;
align-items: center;
gap: var(--space-sm);
margin-bottom: var(--space-xs);
}
.settings-model-lane-control-row {
display: flex;
align-items: center;
gap: var(--space-sm);
}
.settings-model-lane-control-main {
flex: 1;
}
.settings-model-lane-actions {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--space-sm);
padding: var(--space-md) var(--space-xl) var(--space-lg);
margin-block: var(--space-sm) var(--space-lg);
border-bottom: var(--btn-border-width) solid var(--border);
}
.settings-error {
color: var(--color-error);
}
.settings-summarization-actions {
justify-content: flex-start;
}
/* === Settings: Model Presets === */
.settings-model-presets {
display: flex;
flex-direction: column;
gap: var(--space-md);
}
.settings-preset-list {
display: flex;
flex-direction: column;
gap: var(--space-sm);
}
.settings-preset-item {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: var(--space-md);
padding: var(--space-md);
border: var(--btn-border-width) solid var(--border);
border-radius: var(--radius-md);
background: var(--card);
}
.settings-preset-item-meta {
display: flex;
flex-direction: column;
gap: var(--space-xs);
min-width: 0;
}
.settings-preset-item-meta strong {
color: var(--text);
overflow-wrap: anywhere;
}
.settings-preset-summary {
font-size: 12px;
overflow-wrap: anywhere;
}
.settings-preset-item-actions {
display: flex;
gap: var(--space-xs);
flex-wrap: wrap;
justify-content: flex-end;
}
.settings-preset-actions {
display: flex;
justify-content: flex-start;
}
.settings-preset-editor {
display: flex;
flex-direction: column;
gap: var(--space-md);
padding: var(--space-md);
border: var(--btn-border-width) solid var(--border);
border-radius: var(--radius-md);
background: color-mix(in srgb, var(--surface) 85%, var(--card));
}
.settings-preset-editor-fields {
display: flex;
flex-direction: column;
gap: var(--space-sm);
}
.settings-preset-editor .form-group {
padding: 0;
}
.settings-preset-editor-actions {
justify-content: flex-start;
margin-top: 0;
padding: 0;
}
.settings-preset-auto-select {
margin-top: var(--space-sm);
}
.settings-preset-size-grid {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: var(--space-sm);
}
.settings-preset-size-row {
padding: 0;
}
@media (max-width: 768px) {
/* Settings modal: use the section picker as the only mobile navigation */
.settings-layout {
flex-direction: column;
min-height: 0;
}
.settings-navigation {
width: 100%;
min-width: 0;
flex: 0 0 auto;
border-right: none;
border-bottom: var(--btn-border-width) solid var(--border);
background: var(--surface);
}
.settings-search {
padding: var(--space-md) var(--space-lg) var(--space-sm);
}
.settings-search-input-wrap {
align-items: stretch;
}
.settings-search-input {
font-size: 16px;
}
.settings-mobile-section-picker {
display: flex;
flex-direction: column;
gap: var(--space-xs);
padding: var(--space-sm) var(--space-lg) var(--space-md);
border-bottom: none;
background: var(--surface);
}
.settings-mobile-section-picker label {
color: var(--text-muted);
font-weight: 600;
text-transform: uppercase;
}
.settings-mobile-section-picker select {
width: 100%;
}
.settings-mobile-section-picker select:focus-visible {
outline: none;
border-color: var(--todo);
box-shadow: var(--focus-ring-strong);
}
.settings-sidebar {
display: none;
}
.settings-nav-item {
display: flex;
align-items: center;
justify-content: center;
gap: var(--space-xs);
border-left: none;
border-bottom: 2px solid transparent;
border-radius: var(--radius-md) var(--radius-md) 0 0;
padding: calc(var(--space-xs) + var(--space-xs) / 2) var(--space-md);
white-space: nowrap;
}
.settings-nav-item:hover {
border-left-color: transparent;
border-bottom-color: var(--border);
}
.settings-nav-item.active {
border-left-color: transparent;
border-bottom-color: var(--todo);
}
/* Hide group headers on mobile - they don't fit well in horizontal scroll row */
.settings-group-header {
display: none;
}
.notification-provider-card {
margin: 0 var(--space-lg) var(--space-md);
}
.notification-provider-header {
padding: var(--space-sm) var(--space-md);
}
.notification-provider-body {
padding: var(--space-md);
}
.settings-scope-icon {
margin-right: 0;
}
.settings-content {
flex: 1;
min-height: 0;
overflow-x: hidden;
overflow-y: auto;
}
.settings-content .form-group small {
overflow-wrap: break-word;
word-break: normal;
}
.settings-content input,
.settings-content select,
.settings-content textarea {
font-size: 16px;
}
.settings-section-heading {
padding: var(--space-lg) var(--space-lg) var(--space-md);
margin: 0 0 var(--space-md);
}
.settings-plugins-subsection-toggle {
display: flex;
width: 100%;
padding: 0 var(--space-lg);
}
.settings-plugins-subsection-btn {
flex: 1;
min-height: 36px;
}
.settings-plugins-subsection-panel {
padding-left: var(--space-lg);
padding-right: var(--space-lg);
}
.form-group {
padding: 0 calc(var(--space-md) + var(--space-xs) / 2);
}
.settings-scope-banner {
padding: var(--space-sm) var(--space-lg);
}
.memory-editor-frame {
min-height: 65vh;
}
.memory-file-summary {
grid-template-columns: 1fr;
margin: 0 var(--space-lg) var(--space-md);
}
.memory-status-message {
align-items: stretch;
flex-direction: column;
}
.memory-file-summary span {
justify-content: flex-start;
}
.memory-file-summary small {
grid-column: auto;
}
.settings-description {
padding: 0 var(--space-lg);
}
.settings-model-lane-actions {
align-items: stretch;
flex-direction: column;
padding-inline: calc(var(--space-md) + var(--space-xs) / 2);
}
.settings-content .btn,
.settings-preset-item-actions .btn {
min-height: 36px;
}
.auth-provider-row {
flex-wrap: wrap;
padding: var(--space-md) calc(var(--space-md) + var(--space-xs) / 2);
gap: var(--space-sm);
}
.auth-section-hint {
margin: 0 calc(var(--space-md) + var(--space-xs) / 2) var(--space-md);
padding: calc(var(--space-sm) + var(--space-xs) / 2) calc(var(--space-md) + var(--space-xs) / 2);
}
.auth-provider-group {
margin-bottom: var(--space-md);
}
.auth-group-label {
padding: 0 calc(var(--space-md) + var(--space-xs) / 2);
}
.auth-provider-card {
margin: 0 calc(var(--space-md) + var(--space-xs) / 2) var(--space-sm);
}
.auth-provider-header {
flex-wrap: wrap;
padding: calc(var(--space-sm) + var(--space-xs) / 2) calc(var(--space-md) + var(--space-xs) / 2);
gap: 10px;
}
.auth-provider-header > div:not(.auth-provider-info):not(.auth-apikey-section) {
margin-left: auto;
}
.auth-provider-actions-row {
width: 100%;
justify-content: flex-end;
}
.auth-device-code-panel {
width: 100%;
}
.auth-device-code-pill {
max-width: 100%;
overflow-wrap: anywhere;
}
.auth-provider-info {
width: 100%;
flex-basis: 100%;
}
.auth-apikey-section {
width: 100%;
flex-basis: 100%;
align-items: flex-end;
}
.auth-apikey-input-row {
width: 100%;
flex-wrap: wrap;
justify-content: flex-end;
}
.auth-apikey-input {
flex: 1;
min-width: 120px;
width: auto;
}
.auth-apikey-input-row .btn {
flex-shrink: 0;
margin-left: auto;
}
.auth-hint {
padding: var(--space-md) calc(var(--space-md) + var(--space-xs) / 2) 0;
}
/* Settings modal: model preset controls stack cleanly on narrow screens */
.settings-model-presets {
gap: var(--space-sm);
}
.settings-preset-item {
flex-direction: column;
align-items: stretch;
padding: var(--space-sm) var(--space-md);
}
.settings-preset-item-actions {
justify-content: flex-start;
}
.settings-preset-editor {
padding: var(--space-sm) var(--space-md);
}
.settings-preset-editor-actions {
flex-wrap: wrap;
}
.settings-preset-size-grid {
grid-template-columns: 1fr;
gap: var(--space-xs);
}
.settings-node-routing-note {
padding: var(--space-sm) var(--space-md);
font-size: 12px;
}
}
/* Node Routing section */
.settings-node-routing-note {
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius-md);
padding: var(--space-md) var(--space-lg);
margin-top: var(--space-sm);
color: var(--text-muted);
font-size: 13px;
line-height: 1.5;
}
.settings-node-status {
display: inline-flex;
align-items: center;
gap: var(--space-xs);
margin-top: var(--space-sm);
font-size: 12px;
color: var(--text-muted);
}
.auth-advanced-disclosure {
margin-top: var(--space-md);
border: 1px solid var(--border);
border-radius: var(--radius-md);
background: var(--surface);
}
.auth-advanced-disclosure > summary {
cursor: pointer;
padding: var(--space-sm) var(--space-md);
}
.auth-advanced-content {
display: flex;
flex-direction: column;
gap: var(--space-sm);
padding: 0 var(--space-md) var(--space-md);
}
.auth-custom-provider-item {
display: flex;
justify-content: space-between;
align-items: center;
gap: var(--space-sm);
}
.auth-custom-provider-actions {
display: flex;
gap: var(--space-sm);
}
.settings-warning-banner {
margin-top: var(--space-sm);
padding: var(--space-sm) var(--space-md);
border: 1px solid var(--color-warning);
border-radius: var(--radius-md);
background: color-mix(in srgb, var(--color-warning) 12%, transparent);
color: var(--text);
font-size: 0.875rem;
line-height: 1.4;
}
.settings-warning-banner strong {
color: var(--color-warning);
margin-right: var(--space-xs);
}
/* KTD-8: informational note at the bottom of the Node Sync section. */
.settings-sync-workflow-note {
margin-top: var(--space-md);
font-size: 0.875rem;
color: var(--text-muted);
}
@media (max-width: 768px) {
.auth-custom-provider-item {
flex-direction: column;
align-items: flex-start;
}
.settings-warning-banner {
padding: var(--space-sm);
}
}
/*
FNXC:DashboardShortcuts 2026-07-04-00:00:
FN-7553's dedicated Keyboard Shortcuts section groups every action under a category heading and gives each row a press-to-record capture control (input + Record + Clear) instead of the old bare text input. Token spacing/colors only; wraps to a single column under 768px so the record/clear buttons never overflow the row on mobile.
*/
.shortcut-category {
margin-top: var(--space-lg);
}
.shortcut-category:first-of-type {
margin-top: 0;
}
.shortcut-row {
display: flex;
flex-direction: column;
gap: var(--space-xs);
padding: var(--space-sm) 0;
border-bottom: 1px solid var(--color-border);
}
.shortcut-row:last-child {
border-bottom: 0;
}
/*
FNXC:DashboardShortcuts 2026-07-05-00:00:
FN-7602 fixes an overlap bug: Record/Clear previously used the icon-only `btn-icon` class
(line-height:0 + mobile 36px square), which clipped/overlapped their text labels
("Record"/"Recording…"/"Clear") against the input and each other (IMG_1305). The input
keeps `flex: 1 1 auto; min-width: 0;` so it shrinks first, while the buttons get
`flex-shrink: 0; white-space: nowrap;` so their content-sized width (including the longer
"Recording…" label) is never crushed or allowed to overlap a neighbor on desktop. Below
768px the row stacks to a column so the buttons sit on their own row under the full-width
input, still non-overlapping.
*/
.shortcut-capture {
display: flex;
align-items: center;
gap: var(--space-sm);
flex-wrap: wrap;
}
.shortcut-capture__input {
flex: 1 1 auto;
min-width: 0;
}
.shortcut-capture__input--invalid {
border-color: var(--color-error);
}
.shortcut-capture__record,
.shortcut-capture__clear {
flex-shrink: 0;
white-space: nowrap;
}
.shortcut-capture__record--active {
color: var(--color-warning);
}
.shortcut-conflict-banner {
color: var(--color-error);
}
@media (max-width: 768px) {
.shortcut-capture {
flex-direction: column;
align-items: stretch;
}
.shortcut-capture__input {
width: 100%;
}
}