/* FNXC:SettingsStyling 2026-07-15-17:35: Settings mixed px, rem, em, and calc()-over-spacing font sizes across ~10 distinct values with no scale. Declarations now name scale rungs by role — 2xs for badges/pills, xs for help and caption copy, sm for control labels and body, base/md for headings — so type is retuned from the token definitions rather than by sweeping this file. The mobile `font-size: 16px` overrides stay raw on purpose: they are iOS's focus-zoom threshold, not a type rung, and must hold at 16px even if the root font size shrinks. */ /* === 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; /* These are tags styled as .btn — .btn never resets link underline, so without this the browser's default underline paints under the icon+label box. */ text-decoration: none; } @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); } /* FNXC:Settings 2026-07-11-00:00: FN-7848: Mobile Settings must still show the GitHub star count. FN-4375 kept the header in one row by collapsing promotional action labels; keep the count visible and rely on .settings-modal-heading min-width: 0 to truncate the title before the pill wraps. Only the redundant "Star" word stays collapsed to save horizontal room. */ .settings-header-actions .settings-github-star-btn__action, .settings-header-actions .settings-header-discord-btn { width: 40px; min-width: 40px; padding: 0; justify-content: center; font-size: 0; } .settings-header-actions .settings-github-star-btn__action { gap: 0; } } /* 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: var(--font-size-xs); 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: var(--font-size-md); 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%; } /* FNXC:Settings 2026-07-07-00:00: Mobile embedded Settings has no left sidebar to exit through (only the bottom MobileNavBar), so the header needs an explicit close affordance. Reuse the shared .modal-close sizing/hover and pin it to the header's trailing edge, after the Star/Discord actions, without displacing them. Desktop/tablet embedded and the standalone modal presentation are untouched by this rule (scoped to .settings-modal--embedded .modal-header--embedded). */ /* FNXC:Settings 2026-07-09-00:00: FN-7752 makes the mobile Settings header and footer shorter at ≤768px only. Keep the FN-4375 one-line header invariant while trimming vertical padding in both standalone modal and embedded SettingsView presentations. FNXC:Settings 2026-07-10-00:00: FN-7773 further tightens only the mobile footer rail so Version, Help, Import/Export, Reset, and Save read as one contained row without affecting desktop/tablet sizing. */ .settings-modal .modal-header { padding-block: var(--space-sm); padding-inline: var(--space-md); } .settings-modal .modal-actions { padding-block: var(--space-xs); padding-inline: var(--space-md); } .settings-modal--embedded .modal-header--embedded { min-height: 0; } .settings-modal--embedded .modal-header--embedded .settings-embedded-mobile-close { --settings-embedded-mobile-close-touch-target: calc(var(--space-lg) + var(--space-lg) + var(--space-xs)); flex-shrink: 0; margin-left: var(--space-xs); min-height: var(--settings-embedded-mobile-close-touch-target); min-width: var(--settings-embedded-mobile-close-touch-target); } } /* === 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: var(--font-size-sm); 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; } /* FNXC:SettingsLayout 2026-07-10-12:25: First-run review video showed the footer Save button clipped at the panel edge. The base `.modal-actions` row is a no-wrap flex rail of non-shrinking buttons (Help + Version + Export/Import/Reset + Save, plus the optional update-check result text); on narrow desktop panes its intrinsic width exceeds the panel and, because `.settings-modal`/`.modal` clip overflow, the rightmost Save button gets cut off (at ~770px pane width Save already sat exactly at the padding edge — any extra footer text or font scaling clipped it). Fix the invariant for BOTH presentations (standalone modal + embedded SettingsView share `.settings-modal .modal-actions`): let the desktop footer wrap onto additional rows instead of clipping. The ≤768px mobile block below (FN-7752/FN-7773) intentionally re-asserts a single nowrap rail with horizontal scroll and overrides this inside its media query. */ .settings-modal .modal-actions { flex-wrap: wrap; align-items: center; row-gap: var(--space-xs); min-width: 0; } @media (max-width: 768px) { /* FNXC:Settings 2026-07-09-00:00: FN-7752 requires the mobile Settings footer to remain a single horizontal row in both standalone and embedded presentations. Keep Version/Help, Export/Import/Reset, and Cancel/Save on one nowrap rail that can scroll horizontally instead of stacking into multiple rows. FNXC:Settings 2026-07-10-00:00: FN-7773 fixes the observed mobile overlap by centering every footer sub-region on the rail and making the Version text a non-wrapping inline box. Keep these selectors under the mobile media query so desktop/tablet footer flow remains unchanged. */ .settings-modal .modal-actions { flex-wrap: nowrap; align-items: center; gap: var(--space-xs); overflow-x: auto; overflow-y: hidden; } .settings-modal .modal-actions-left { align-items: center; flex-shrink: 0; gap: var(--space-xs); } .settings-modal .modal-actions-right { align-items: center; flex-shrink: 0; gap: var(--space-xs); } .settings-modal .settings-modal-footer-version { align-items: center; align-self: center; flex: 0 0 auto; margin-right: 0; min-width: max-content; } /* FNXC:SettingsUpdate 2026-07-16-00:00: FN-8138 adds a restart control and manual-restart explanation after an update. Let this inner result flow wrap on narrow screens while the existing footer rail remains horizontally scrollable, so the new controls never create a clipped shell. */ .settings-modal .settings-update-check { align-items: center; flex-wrap: wrap; row-gap: var(--space-xs); } .settings-modal .settings-update-result { align-self: center; flex: 0 1 auto; line-height: normal; white-space: normal; } .settings-modal .settings-footer-help-btn { align-items: center; flex-shrink: 0; } .settings-modal .settings-version-check-btn { align-items: center; flex-shrink: 0; line-height: 1; white-space: nowrap; } .settings-modal .settings-modal-version { align-items: center; display: inline-flex; flex-shrink: 0; line-height: 1; white-space: nowrap; } /* FNXC:Settings 2026-07-16-00:20: Help/Export/Import/Reset/Cancel/Save all share `.btn-sm`, which the global mobile touch-target rule (`.btn:not(...):not(.btn-sm)...{min-height:36px}` in styles.css) deliberately skips so dense table/card rows of small buttons stay compact. That exclusion also caught this footer, so these rendered at their ~24px unpadded height on mobile — visibly smaller and misaligned against the 36px auth Test/Disable buttons sitting on the same screen. Re-apply the 36px touch target scoped to this footer only, so the exclusion keeps holding everywhere else that intentionally wants compact `.btn-sm`. */ .settings-modal .modal-actions-left .btn-sm, .settings-modal .modal-actions-right .btn-sm, .settings-modal .settings-footer-help-btn { min-height: 36px; } } .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: var(--font-size-sm); 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-succeeded { display: inline-flex; align-items: center; flex-wrap: wrap; gap: var(--space-xs); } .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: var(--font-size-base); font-weight: 600; font-variant-numeric: tabular-nums; } .backup-stat-label { color: var(--text-muted); font-size: var(--font-size-xs); 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: var(--font-size-xs); white-space: nowrap; overflow-x: auto; } .backup-size { color: var(--text-muted); font-family: var(--font-mono); font-size: var(--font-size-xs); 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; } /* FNXC:SettingsSimplification 2026-07-11-00:42: The Settings rail is one navigation surface. The legacy translucent background on both the parent rail and nested section list compounded into a visibly lighter second tone; keep the parent opaque and the nested scroller transparent in every theme. FNXC:Settings 2026-07-11-18:45: FN-7825 removes the hard divider between the Settings rail and content, keeps section rows single-line at the rail's full width, and makes this parent rail the authoritative width owner so the upcoming desktop resize handle can update one CSS custom property without fighting nested sidebar rules. */ .settings-navigation { --settings-nav-width: calc(var(--space-xl) * 10 + var(--space-sm)); width: var(--settings-nav-width); min-width: var(--settings-nav-width); display: flex; flex-direction: column; min-height: 0; background: var(--surface); } .settings-navigation .settings-sidebar { background: transparent; } .settings-nav-resize-handle { flex: 0 0 var(--space-xs); margin-inline: calc(var(--space-xs) * -0.5); cursor: col-resize; background: transparent; border: 0; outline: none; position: relative; z-index: 1; } .settings-nav-resize-handle::before { content: ""; position: absolute; inset-block: var(--space-sm); inset-inline: calc(50% - (var(--btn-border-width) / 2)); width: var(--btn-border-width); border-radius: var(--radius-pill); background: transparent; transition: background var(--transition-fast); } .settings-nav-resize-handle:hover::before, .settings-nav-resize-handle:focus-visible::before { background: var(--border); } .settings-nav-resize-handle:focus-visible { box-shadow: var(--focus-ring-strong); } .settings-search { display: flex; flex-direction: column; gap: var(--space-xs); padding: var(--space-sm); border-bottom: var(--btn-border-width) solid var(--border); } /* FNXC:SettingsSimplification 2026-07-10-23:24: The Advanced settings preference is a navigation-level disclosure, so keep it visually adjacent to section search/picking in both desktop and mobile layouts and retain a full-row click target. */ .settings-advanced-toggle { display: flex; align-items: center; gap: var(--space-sm); padding: var(--space-sm); border-bottom: var(--btn-border-width) solid var(--border); color: var(--text); font-size: var(--font-size-xs); font-weight: 600; cursor: pointer; } .settings-advanced-toggle input { margin: 0; cursor: pointer; } /* FNXC:Settings 2026-07-09-12:00: the row wraps label + input + results; on desktop it always renders (see .settings-search-toggle below, hidden here). On mobile the inline section-picker toggle controls whether this wrapper mounts below the picker, avoiding an empty padded shell above the picker while collapsed. */ .settings-search-row { display: flex; flex-direction: column; gap: var(--space-xs); } /* Desktop/tablet: search row is always visible, so the toggle icon never renders here. */ .settings-search-toggle { display: none; } .settings-search-label { color: var(--text-muted); font-size: var(--font-size-xs); 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: var(--font-size-xs); margin: 0; } /* FNXC:SettingsSearch 2026-07-15-17:35: Per-setting search results. Sits between the search input and the section nav because it answers the question the operator actually asked — which setting, not which section — and the nav below stays filtered as the coarse view. Scrolls at a fixed max-height rather than growing: the list is capped at 8 entries, but long labels still wrap, and an unbounded block would push the section nav out of view on a short viewport. Sizes name the shared scale (label = xs, section = 2xs) so results read as the same UI as the rows they navigate to. */ .settings-search-hits { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 1px; max-height: calc(var(--space-2xl) * 6); overflow-y: auto; } .settings-search-hit { display: flex; flex-direction: column; align-items: flex-start; gap: 1px; width: 100%; padding: var(--space-xs) var(--space-sm); background: none; border: none; border-radius: var(--radius-sm); text-align: left; cursor: pointer; color: var(--text); } .settings-search-hit:hover, .settings-search-hit:focus-visible { background: var(--bg); } .settings-search-hit-label { font-size: var(--font-size-xs); line-height: var(--line-height-tight); } /* The owning section, so two similarly-named settings are distinguishable before navigating. */ .settings-search-hit-section { font-size: var(--font-size-2xs); color: var(--text-muted); } .settings-search-hits-more { padding: var(--space-xs) var(--space-sm); font-size: var(--font-size-2xs); color: var(--text-muted); } .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; } /* FNXC:SettingsResearch 2026-07-14-19:45: Source options stack the control label and default-state hint so hints stay visible without joining the checkbox accessible name. */ .settings-research-source-option { display: flex; flex-direction: column; gap: calc(var(--space-xs) / 2); 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: var(--font-size-sm); 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; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; transition: background var(--transition-fast), color var(--transition-fast), border-color var(--transition-fast); } /* FNXC:SettingsSimplification 2026-07-11-00:17: The simplified Settings surface needs one consistent reading rhythm across legacy and typed sections. Use a wider navigation rail to prevent routine labels wrapping, align section content to one gutter, normalize control height/type, and keep helper copy readable without changing the dashboard's existing tokens or font family. */ .settings-sidebar { padding-block: var(--space-md); } .settings-nav-item { min-height: 36px; display: flex; align-items: center; gap: var(--space-xs); line-height: 1.25; } .settings-content { padding: var(--space-lg) calc(var(--space-xl) + var(--space-sm)) calc(var(--space-xl) + var(--space-md)); } .settings-content > .settings-gitlab-disclosure { margin-inline: 0; } .settings-content .settings-section-heading { padding-inline: 0; color: var(--text); line-height: 1.3; text-wrap: balance; } .settings-content h4.settings-section-heading { font-size: var(--font-size-base); margin-bottom: var(--space-md); } .settings-content h5.settings-section-heading { font-size: var(--font-size-sm); } /* FNXC:SettingsStyling 2026-07-15-20:30: Bespoke rows keep the same vertical rhythm as migrated ones. `.settings-field-row` spaces itself with `padding-block: var(--space-sm)`, while a `.form-group` spaced itself with `margin-top: var(--space-md)`. Mixed in one section — which is now the normal case, since some rows deliberately stay bespoke — that produced three different gaps depending on which idioms happened to be adjacent: 16px between two migrated rows, 12px between two bespoke ones, and 20px where they met. Matching the primitive's `padding-block` (rather than giving the primitive a margin) keeps one idiom: every settings row owns its own space and margins never collapse or compound between them. `padding-inline: 0` stays — `.settings-content` already owns the horizontal inset, and `.form-group`'s global `0 var(--space-xl)` would double-indent every bespoke row. */ .settings-content .form-group { padding-inline: 0; margin-top: 0; padding-block: var(--space-sm); } /* FNXC:SettingsStyling 2026-07-15-20:30: Every label in Settings reads the same way, whether its row is migrated or still bespoke. Some rows deliberately stay hand-rolled — a `data-testid` the primitives have no slot for, help copy that interleaves `` or a link, a repeating-row editor — and those inherit the GLOBAL `.form-group label` treatment: 12px, weight 600, uppercase, letter-spaced, muted. So a section rendered "PLAN APPROVAL MODE" in caps directly above "Auto-merge conflict retries" in sentence case. Two idioms on one screen is the exact inconsistency the migration set out to remove, and migrating every last row is not achievable (nor desirable — see the bespoke rows' own FNXC notes). Retuning them here instead of at the global rule is deliberate: `.form-group` is dashboard-wide across 35 non-settings files, and its uppercase treatment is that context's convention, not a bug. This selector is settings-scoped, so it changes Settings only. Declarations mirror `.settings-field-row-label` — one contract, expressed at whatever specificity each markup idiom needs. */ .settings-content .form-group label:not(.checkbox-label) { font-size: var(--font-size-sm); font-weight: 500; line-height: var(--line-height-tight); color: var(--text); text-transform: none; letter-spacing: normal; margin-bottom: var(--space-xs); } /* FNXC:SettingsStyling 2026-07-15-20:30: Bespoke help text (`` inside a form-group) matches `.settings-field-row-help`: same rung, same colour, same measure. Without this a bespoke row's help sat at 12px/1.4 beside a migrated row's at 12.8px/1.5 — close enough to look like a rendering glitch rather than a choice. Still applies to the copy that legitimately stays inline: validation messages (`.field-error`) and the explanatory blurbs that describe a whole block rather than one control. */ .settings-content .form-group small, .settings-content .form-group .form-text { font-size: var(--font-size-xs); line-height: 1.5; color: var(--text-muted); } /* FNXC:SettingsHelp 2026-07-15-21:40: The label line for a row that is NOT on the shared primitive, so its help can hang off a "?" exactly like a migrated row's. A bespoke row is `