mirror of
https://github.com/dustinkeeton/obsidian-synapse.git
synced 2026-07-22 07:44:43 +00:00
A blocking follow-up decision deserves a first-class surface: the trim-range picker is now a TimeRangeModal (front and center, can't be lost to a stray click) replacing both the slider toast and the fallback text-input toast. Dismissing it resolves 'cancelled' — do nothing — instead of silently transcribing the whole file. The trim bar's handles now actually overlay the bar: Obsidian styles input[type='range'] itself at higher specificity than a bare class, so every slider rule is prefixed with the attribute selector. The duplicate range readout above the bar and the redundant "Duration:" label are gone — the live start/end endpoint labels say it all. Co-Authored-By: Claude <bot@wafflenet.io> Claude-Session: https://claude.ai/code/session_012HVfTic7eKWvFiEYkoJe6m
1558 lines
41 KiB
CSS
1558 lines
41 KiB
CSS
/* Synapse plugin styles */
|
|
|
|
/* ══════════════════════════════════════════════════════════════
|
|
* Action-type color tokens — SINGLE SOURCE OF TRUTH (#342)
|
|
*
|
|
* One semantic token per Synapse action type. EVERY action-type surface
|
|
* (cards, badges, review labels, checklist headings, callouts, actions-sidebar
|
|
* groups, modal accents) consumes these — no action-type hue is hardcoded
|
|
* anywhere else. Re-theming a type is a one-line edit here.
|
|
*
|
|
* Base tokens map to Obsidian's `--color-*` vars so they adapt to the active
|
|
* theme (and light/dark) automatically. The TypeScript guard in
|
|
* `src/views/proposal-styles.ts` (`Record<ProposalKind, string>`) fails the
|
|
* build if a proposal kind ever loses its token.
|
|
*
|
|
* Notes:
|
|
* - `elaboration` uses `--color-blue` (moved OFF `--interactive-accent` so it
|
|
* no longer collides with the user's accent or the generic CTA buttons).
|
|
* - `tidy` intentionally shares organize's hue (sibling structural-cleanup
|
|
* ops) but keeps its own token, so it can diverge with a one-line change.
|
|
* - `main` ("General") is neutral.
|
|
* ══════════════════════════════════════════════════════════════ */
|
|
.theme-light,
|
|
.theme-dark {
|
|
--synapse-color-elaboration: var(--color-blue);
|
|
--synapse-color-enrichment: var(--color-green);
|
|
--synapse-color-organize: var(--color-orange);
|
|
--synapse-color-deep-dive: var(--color-purple);
|
|
--synapse-color-title: var(--color-cyan);
|
|
--synapse-color-rem: var(--color-pink);
|
|
--synapse-color-summarize: var(--color-red);
|
|
--synapse-color-tidy: var(--color-orange);
|
|
--synapse-color-video: var(--color-yellow);
|
|
--synapse-color-main: var(--text-muted);
|
|
|
|
/*
|
|
* Callout tints take comma-separated RGB CHANNELS (not a color value), so
|
|
* these companion tokens carry literal channels aligned to each hue above.
|
|
* Only the types that render as callouts need an `-rgb` companion. Channels
|
|
* are fixed (theme vars are not channel-decomposable), matching how the
|
|
* callouts already worked; the low-opacity tint reads fine in light + dark.
|
|
*/
|
|
--synapse-color-elaboration-rgb: 100, 160, 255;
|
|
--synapse-color-enrichment-rgb: 80, 180, 120;
|
|
--synapse-color-deep-dive-rgb: 160, 120, 220;
|
|
--synapse-color-summarize-rgb: 230, 110, 110;
|
|
--synapse-color-video-rgb: 220, 180, 70;
|
|
}
|
|
|
|
/*
|
|
* Brand impulse gold (2026 Iris+Gold refresh). Every registered glyph draws
|
|
* its body in currentColor and its single gold gesture in this var (see
|
|
* src/brand-icons.ts / assets/brand/README.md). Deepened on light surfaces
|
|
* for contrast against white.
|
|
*/
|
|
body {
|
|
--synapse-gold: #FFD23F;
|
|
}
|
|
|
|
.theme-light {
|
|
--synapse-gold: #E8B419;
|
|
}
|
|
|
|
/*
|
|
* Cap the height of embedded videos so portrait-oriented content
|
|
* (TikTok, Instagram Reels, phone recordings) does not dominate the note.
|
|
* Landscape videos are unaffected because they hit width constraints first.
|
|
*/
|
|
.markdown-preview-view video,
|
|
.markdown-reading-view video,
|
|
.markdown-source-view video {
|
|
max-height: 50vh;
|
|
width: auto;
|
|
}
|
|
|
|
/* ── Enhanced slider labels and tick marks ── */
|
|
|
|
.synapse-slider-wrapper {
|
|
display: flex;
|
|
flex-direction: column;
|
|
width: 100%;
|
|
min-width: 200px;
|
|
gap: 0;
|
|
}
|
|
|
|
.synapse-slider-wrapper input[type="range"] {
|
|
width: 100%;
|
|
}
|
|
|
|
.synapse-slider-current-value {
|
|
text-align: right;
|
|
font-size: var(--font-ui-small);
|
|
font-weight: var(--font-semibold);
|
|
color: var(--text-accent);
|
|
margin-bottom: 2px;
|
|
min-width: 2em;
|
|
}
|
|
|
|
.synapse-slider-labels {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
font-size: var(--font-ui-smaller);
|
|
color: var(--text-muted);
|
|
margin-top: 2px;
|
|
padding: 0 2px;
|
|
}
|
|
|
|
.synapse-slider-ticks {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
padding: 0 6px;
|
|
margin-top: 1px;
|
|
}
|
|
|
|
.synapse-slider-tick {
|
|
width: 1px;
|
|
height: 6px;
|
|
background-color: var(--text-faint);
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
/* ── AI content callout styles ── */
|
|
|
|
.callout[data-callout^="synapse-"] {
|
|
--callout-blend-mode: normal;
|
|
border-left-width: 3px;
|
|
opacity: 0.95;
|
|
}
|
|
|
|
/* synapse-summary ↔ summarize feature */
|
|
.callout[data-callout="synapse-summary"] {
|
|
--callout-color: var(--synapse-color-summarize-rgb);
|
|
--callout-icon: lucide-file-text;
|
|
}
|
|
|
|
/* synapse-transcription ↔ video feature */
|
|
.callout[data-callout="synapse-transcription"] {
|
|
--callout-color: var(--synapse-color-video-rgb);
|
|
--callout-icon: lucide-mic;
|
|
}
|
|
|
|
.callout[data-callout="synapse-enrichment"] {
|
|
--callout-color: var(--synapse-color-enrichment-rgb);
|
|
--callout-icon: lucide-link;
|
|
}
|
|
|
|
.callout[data-callout="synapse-elaboration"] {
|
|
--callout-color: var(--synapse-color-elaboration-rgb);
|
|
--callout-icon: lucide-pen-tool;
|
|
}
|
|
|
|
.callout[data-callout="synapse-deep-dive"] {
|
|
--callout-color: var(--synapse-color-deep-dive-rgb);
|
|
--callout-icon: lucide-layers;
|
|
}
|
|
|
|
/* ── Modal action buttons ── */
|
|
|
|
.synapse-modal-actions {
|
|
display: flex;
|
|
gap: 8px;
|
|
justify-content: flex-end;
|
|
margin-top: 16px;
|
|
}
|
|
|
|
/* ── Modal type accents (#342) ──
|
|
* A type-colored underline beneath the modal title ties each detail modal to
|
|
* its action type, matching the sidebar card/badge for that type. */
|
|
.synapse-elaboration-detail h2 {
|
|
border-bottom: 2px solid var(--synapse-color-elaboration);
|
|
padding-bottom: 6px;
|
|
}
|
|
.synapse-enrichment-detail h2 {
|
|
border-bottom: 2px solid var(--synapse-color-enrichment);
|
|
padding-bottom: 6px;
|
|
}
|
|
|
|
/* ── Proposal editor textarea ── */
|
|
|
|
.synapse-proposal-editor {
|
|
width: 100%;
|
|
font-family: var(--font-monospace, monospace);
|
|
max-height: 60vh;
|
|
resize: vertical;
|
|
}
|
|
|
|
/* ── Settings tab version footer ── */
|
|
|
|
.synapse-settings-footer {
|
|
margin-top: 24px;
|
|
text-align: center;
|
|
opacity: 0.7;
|
|
}
|
|
|
|
/* ── Dual-handle time-range slider (video trim bar) ──
|
|
*
|
|
* Styled as an editor's trim bar: a quiet rail, a solid gold selection
|
|
* between two vertical pill "in/out" handles. Gold (--synapse-gold) marks
|
|
* the selection — the one thing the user is adding — and everything else
|
|
* stays on neutral theme tokens so the control sits natively in any theme.
|
|
*
|
|
* Selector note: every rule targets `input[type='range'].synapse-…` because
|
|
* Obsidian styles `input[type='range']` itself (sizing + white thumb) at
|
|
* (0,1,1) specificity — a bare class selector loses and the handles render
|
|
* as Obsidian's detached default thumbs instead of overlaying the bar.
|
|
*/
|
|
|
|
.synapse-time-range-container {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 4px;
|
|
width: 100%;
|
|
padding: 8px 0 2px;
|
|
}
|
|
|
|
.synapse-time-range-track-wrapper {
|
|
position: relative;
|
|
height: 32px;
|
|
width: 100%;
|
|
}
|
|
|
|
/* Base rail — drawn once here so both range inputs stay transparent */
|
|
.synapse-time-range-track-wrapper::before {
|
|
content: '';
|
|
position: absolute;
|
|
top: 50%;
|
|
left: 0;
|
|
right: 0;
|
|
transform: translateY(-50%);
|
|
height: 6px;
|
|
background: var(--background-modifier-border);
|
|
border-radius: 3px;
|
|
}
|
|
|
|
/* Selected region: solid gold fill between the trim handles */
|
|
.synapse-time-range-track-highlight {
|
|
position: absolute;
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
height: 6px;
|
|
background-color: var(--synapse-gold, #FFD23F);
|
|
border-radius: 3px;
|
|
pointer-events: none;
|
|
z-index: 0;
|
|
}
|
|
|
|
input[type='range'].synapse-time-range-input {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
margin: 0;
|
|
padding: 0;
|
|
background: none;
|
|
pointer-events: none;
|
|
-webkit-appearance: none;
|
|
appearance: none;
|
|
z-index: 1;
|
|
}
|
|
|
|
/* Trim handles: vertical pills (an editor's in/out points), not blobs.
|
|
* The invisible 6px runnable track centers the 22px thumb via margin-top. */
|
|
input[type='range'].synapse-time-range-input::-webkit-slider-runnable-track {
|
|
height: 6px;
|
|
background: transparent;
|
|
border: none;
|
|
}
|
|
input[type='range'].synapse-time-range-input::-moz-range-track {
|
|
height: 6px;
|
|
background: transparent;
|
|
border: none;
|
|
}
|
|
|
|
input[type='range'].synapse-time-range-input::-webkit-slider-thumb {
|
|
pointer-events: auto;
|
|
-webkit-appearance: none;
|
|
appearance: none;
|
|
width: 12px;
|
|
height: 22px;
|
|
margin-top: -8px;
|
|
border-radius: 6px;
|
|
background: var(--synapse-gold, #FFD23F);
|
|
border: 2px solid var(--background-primary);
|
|
box-shadow: var(--shadow-s);
|
|
cursor: grab;
|
|
position: relative;
|
|
z-index: 2;
|
|
}
|
|
|
|
input[type='range'].synapse-time-range-input::-moz-range-thumb {
|
|
pointer-events: auto;
|
|
width: 12px;
|
|
height: 22px;
|
|
border-radius: 6px;
|
|
background: var(--synapse-gold, #FFD23F);
|
|
border: 2px solid var(--background-primary);
|
|
box-shadow: var(--shadow-s);
|
|
cursor: grab;
|
|
}
|
|
|
|
input[type='range'].synapse-time-range-input::-webkit-slider-thumb:active {
|
|
cursor: grabbing;
|
|
}
|
|
|
|
/* Visible keyboard focus on the handles */
|
|
input[type='range'].synapse-time-range-input:focus-visible::-webkit-slider-thumb {
|
|
box-shadow: 0 0 0 2px var(--background-modifier-border-focus);
|
|
}
|
|
input[type='range'].synapse-time-range-input:focus-visible::-moz-range-thumb {
|
|
box-shadow: 0 0 0 2px var(--background-modifier-border-focus);
|
|
}
|
|
|
|
/* Live start/end timestamps under their handles */
|
|
.synapse-time-range-labels {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: baseline;
|
|
gap: 12px;
|
|
font-size: var(--font-ui-smaller);
|
|
color: var(--text-muted);
|
|
font-variant-numeric: tabular-nums;
|
|
padding: 0 2px;
|
|
}
|
|
|
|
/* ── Time-range modal (choose what to transcribe) ── */
|
|
|
|
.synapse-time-range-modal .synapse-time-range-modal-media-title {
|
|
color: var(--text-muted);
|
|
font-size: var(--font-ui-small);
|
|
line-height: 1.4;
|
|
margin: 0 0 12px;
|
|
display: -webkit-box;
|
|
-webkit-line-clamp: 2;
|
|
-webkit-box-orient: vertical;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.synapse-time-range-modal .synapse-time-range-modal-desc {
|
|
font-size: var(--font-ui-small);
|
|
color: var(--text-muted);
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.synapse-time-range-modal .synapse-time-range-modal-inputs {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
margin-bottom: 4px;
|
|
}
|
|
|
|
.synapse-time-range-modal .synapse-time-range-modal-time-input {
|
|
width: 100px;
|
|
padding: 4px 8px;
|
|
font-size: var(--font-ui-small);
|
|
font-variant-numeric: tabular-nums;
|
|
border: 1px solid var(--background-modifier-border);
|
|
border-radius: 4px;
|
|
background: var(--background-primary);
|
|
color: var(--text-normal);
|
|
}
|
|
|
|
/* ── Collapsible settings accordions (#235) ── */
|
|
|
|
.synapse-accordion {
|
|
border-bottom: 1px solid var(--background-modifier-border);
|
|
}
|
|
|
|
.synapse-accordion-header {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
padding: 10px 4px;
|
|
cursor: pointer;
|
|
user-select: none;
|
|
border-radius: 6px;
|
|
}
|
|
|
|
.synapse-accordion-header:hover {
|
|
background-color: var(--background-modifier-hover);
|
|
}
|
|
|
|
.synapse-accordion-header:focus-visible {
|
|
outline: 2px solid var(--interactive-accent);
|
|
outline-offset: -2px;
|
|
}
|
|
|
|
.synapse-accordion-chevron {
|
|
flex-shrink: 0;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: 1em;
|
|
font-size: 0.7em;
|
|
color: var(--text-muted);
|
|
/* Rotates from ▶ (collapsed) to ▼ (expanded). */
|
|
transform: rotate(90deg);
|
|
transition: transform 150ms ease;
|
|
}
|
|
|
|
.synapse-accordion.is-collapsed .synapse-accordion-chevron {
|
|
transform: rotate(0deg);
|
|
}
|
|
|
|
.synapse-accordion-title {
|
|
flex-grow: 1;
|
|
font-weight: var(--font-semibold);
|
|
color: var(--text-normal);
|
|
}
|
|
|
|
.synapse-accordion-control {
|
|
flex-shrink: 0;
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
/*
|
|
* Per-section "Reset to defaults" footer row (#442). Appended to the bottom of
|
|
* each resettable section body as a labeled Setting row (replaces the #420
|
|
* header icon button). A subtle top border sets it apart as a section footer;
|
|
* the Reset button dims when the section already equals shipped defaults and is
|
|
* therefore disabled.
|
|
*/
|
|
.synapse-section-reset {
|
|
border-top: 1px solid var(--background-modifier-border);
|
|
margin-top: 8px;
|
|
}
|
|
|
|
.synapse-section-reset button:disabled {
|
|
opacity: 0.5;
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
/*
|
|
* The enable toggle lives inside a borderless Setting so we reuse the native
|
|
* ToggleComponent. Strip the Setting's default block layout/border/padding so
|
|
* it sits inline in the header next to the title.
|
|
*/
|
|
/*
|
|
* Compound `.setting-item.synapse-accordion-toggle-setting` selector wins on
|
|
* specificity over Obsidian's `.setting-item` defaults without needing
|
|
* `!important` (both classes co-occur on the Setting's settingEl).
|
|
*/
|
|
.setting-item.synapse-accordion-toggle-setting {
|
|
border-top: none;
|
|
padding: 0;
|
|
margin: 0;
|
|
}
|
|
|
|
.synapse-accordion-toggle-setting .setting-item-info {
|
|
display: none;
|
|
}
|
|
|
|
.synapse-accordion-toggle-setting .setting-item-control {
|
|
padding: 0;
|
|
}
|
|
|
|
/*
|
|
* Body: animate height + opacity on collapse/expand. A generous max-height
|
|
* accommodates the tallest feature section; it is purely an animation ceiling.
|
|
* Environments without this CSS fall back to instant show/hide via the
|
|
* is-collapsed display rule below.
|
|
*/
|
|
.synapse-accordion-body {
|
|
overflow: hidden;
|
|
max-height: 4000px;
|
|
opacity: 1;
|
|
transition: max-height 250ms ease, opacity 200ms ease;
|
|
}
|
|
|
|
.synapse-accordion.is-collapsed .synapse-accordion-body {
|
|
max-height: 0;
|
|
opacity: 0;
|
|
/*
|
|
* display:none after the transition would kill the animation, so we keep it
|
|
* laid out but zero-height. For no-transition fallbacks, max-height:0 +
|
|
* overflow:hidden already hides the content.
|
|
*/
|
|
pointer-events: none;
|
|
}
|
|
|
|
/* ── Mobile-responsive overrides ── */
|
|
|
|
@media (max-width: 768px) {
|
|
.synapse-slider-wrapper {
|
|
min-width: 0;
|
|
}
|
|
|
|
.synapse-accordion-header {
|
|
padding: 12px 4px;
|
|
}
|
|
|
|
.synapse-proposal-editor {
|
|
max-height: 40vh;
|
|
}
|
|
|
|
.synapse-modal-actions {
|
|
flex-direction: column;
|
|
}
|
|
|
|
.synapse-modal-actions button {
|
|
width: 100%;
|
|
}
|
|
}
|
|
|
|
/* ── Notification toasts (severity + tracked operations) ── */
|
|
|
|
/*
|
|
* Obsidian renders a toast as `.notice > .notice-message`, and styleNotice()
|
|
* adds the `synapse-notice*` classes to whatever `Notice.noticeEl` points at —
|
|
* the inner `.notice-message` in current Obsidian, not the `.notice` element.
|
|
* So the severity class is NOT reliably co-located with `.notice`. Match BOTH
|
|
* shapes for each rule:
|
|
* - `.notice.synapse-notice` — class on the `.notice` element itself
|
|
* - `.notice:has(.synapse-notice)` — class on a descendant (`.notice-message`)
|
|
* `:has()` keeps the (0,2,0) specificity (so we still beat core `.notice`
|
|
* padding/background without `!important`) AND styles the real `.notice`
|
|
* container, so the error wash is full-bleed rather than inset to the message.
|
|
*/
|
|
.notice.synapse-notice,
|
|
.notice:has(.synapse-notice) {
|
|
border-left: 3px solid var(--text-muted);
|
|
padding-left: 10px;
|
|
transition: border-color 0.3s ease;
|
|
}
|
|
/* Severity colors (source order after the base wins on equal specificity). */
|
|
.notice.synapse-notice--info, .notice:has(.synapse-notice--info) { border-left-color: var(--text-muted); }
|
|
.notice.synapse-notice--progress, .notice:has(.synapse-notice--progress) { border-left-color: var(--interactive-accent); }
|
|
.notice.synapse-notice--success, .notice:has(.synapse-notice--success) { border-left-color: var(--color-green); }
|
|
.notice.synapse-notice--warning, .notice:has(.synapse-notice--warning) { border-left-color: var(--color-yellow); }
|
|
/*
|
|
* Error toasts read unmistakably as errors and are click-to-copy/dismiss
|
|
* (see NotificationManager.showErrorNotice): a soft, theme-aware error wash
|
|
* behind the red accent, and a pointer cursor to signal they're clickable.
|
|
*/
|
|
.notice.synapse-notice--error,
|
|
.notice:has(.synapse-notice--error) {
|
|
border-left-color: var(--color-red);
|
|
background-color: var(--background-modifier-error);
|
|
cursor: pointer;
|
|
}
|
|
|
|
/* Running operation layout */
|
|
.synapse-notice-op {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
}
|
|
.synapse-notice-op-text {
|
|
flex: 1;
|
|
}
|
|
.synapse-notice-op-dots {
|
|
display: inline-block;
|
|
min-width: 1.5ch;
|
|
text-align: left;
|
|
}
|
|
.synapse-notice-op-cancel {
|
|
flex-shrink: 0;
|
|
padding: 2px 10px;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
font-size: 11px;
|
|
border: 1px solid var(--text-muted);
|
|
background: transparent;
|
|
color: var(--text-muted);
|
|
transition: color 0.15s, border-color 0.15s;
|
|
}
|
|
.synapse-notice-op-cancel:hover {
|
|
color: var(--text-normal);
|
|
border-color: var(--text-normal);
|
|
}
|
|
|
|
/* Prevent click-to-dismiss on running operations */
|
|
.synapse-notice--no-dismiss {
|
|
cursor: default;
|
|
}
|
|
|
|
/* Confirmation snackbar buttons */
|
|
.synapse-notice-actions {
|
|
display: flex;
|
|
gap: 8px;
|
|
margin-top: 8px;
|
|
}
|
|
.synapse-notice-actions button {
|
|
padding: 2px 12px;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
font-size: 12px;
|
|
border: 1px solid var(--background-modifier-border);
|
|
}
|
|
.synapse-notice-actions button.mod-cta {
|
|
background: var(--interactive-accent);
|
|
color: var(--text-on-accent);
|
|
border-color: var(--interactive-accent);
|
|
}
|
|
.synapse-notice-actions button.mod-cancel {
|
|
background: transparent;
|
|
color: var(--text-muted);
|
|
}
|
|
/*
|
|
* Actionable success/info toasts carry a single button (e.g. "Review");
|
|
* right-align it so it reads as a trailing call-to-action rather than a
|
|
* left-aligned form control. Scoped to single-action toasts so the
|
|
* confirmation snackbar's Proceed/Cancel pair is unaffected.
|
|
*/
|
|
.notice.synapse-notice--success .synapse-notice-actions,
|
|
.notice.synapse-notice--info .synapse-notice-actions,
|
|
.notice:has(.synapse-notice--success) .synapse-notice-actions,
|
|
.notice:has(.synapse-notice--info) .synapse-notice-actions {
|
|
justify-content: flex-end;
|
|
}
|
|
|
|
/* ══════════════════════════════════════════════════════════════
|
|
* Unified Proposal View (sidebar)
|
|
* ══════════════════════════════════════════════════════════════ */
|
|
|
|
/* ── Layout ── */
|
|
.synapse-view-root {
|
|
display: flex;
|
|
flex-direction: column;
|
|
height: 100%;
|
|
overflow: hidden;
|
|
}
|
|
.synapse-view-root > h3 {
|
|
flex-shrink: 0;
|
|
margin: 0 0 8px;
|
|
padding: 0;
|
|
}
|
|
|
|
/* ── List Mode ── */
|
|
.synapse-proposal-list {
|
|
flex: 1;
|
|
overflow-y: auto;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 4px;
|
|
}
|
|
.synapse-proposal-card {
|
|
border-left: 3px solid var(--text-muted);
|
|
padding: 8px 12px;
|
|
margin: 6px 0;
|
|
border-radius: 4px;
|
|
background: var(--background-secondary);
|
|
min-height: 100px;
|
|
flex: 1 0 auto;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
.synapse-proposal-card .synapse-preview {
|
|
flex: 1;
|
|
}
|
|
.synapse-proposal-card .synapse-actions {
|
|
margin-top: auto;
|
|
}
|
|
.synapse-card--elaboration {
|
|
border-left-color: var(--synapse-color-elaboration);
|
|
}
|
|
.synapse-card--enrichment {
|
|
border-left-color: var(--synapse-color-enrichment);
|
|
}
|
|
.synapse-card--organize {
|
|
border-left-color: var(--synapse-color-organize);
|
|
}
|
|
.synapse-badge {
|
|
display: inline-block;
|
|
font-size: 10px;
|
|
font-weight: 600;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.5px;
|
|
padding: 1px 6px;
|
|
border-radius: 3px;
|
|
margin-bottom: 4px;
|
|
width: min-content;
|
|
white-space: nowrap;
|
|
}
|
|
.synapse-badge--elaboration {
|
|
background: var(--synapse-color-elaboration);
|
|
color: var(--text-on-accent);
|
|
}
|
|
.synapse-badge--enrichment {
|
|
background: var(--synapse-color-enrichment);
|
|
color: var(--text-on-accent);
|
|
}
|
|
.synapse-badge--organize {
|
|
background: var(--synapse-color-organize);
|
|
color: var(--text-on-accent);
|
|
}
|
|
.synapse-reasons {
|
|
display: block;
|
|
color: var(--text-muted);
|
|
margin: 4px 0;
|
|
}
|
|
.synapse-preview {
|
|
font-size: 13px;
|
|
color: var(--text-normal);
|
|
margin: 4px 0;
|
|
}
|
|
.synapse-actions {
|
|
display: flex;
|
|
gap: 6px;
|
|
margin-top: 6px;
|
|
}
|
|
.synapse-actions button {
|
|
padding: 2px 10px;
|
|
border-radius: 4px;
|
|
font-size: 12px;
|
|
cursor: pointer;
|
|
border: 1px solid var(--background-modifier-border);
|
|
background: var(--background-primary);
|
|
color: var(--text-normal);
|
|
}
|
|
.synapse-actions button:hover {
|
|
background: var(--background-modifier-hover);
|
|
}
|
|
.synapse-proposal-group h4 {
|
|
margin: 12px 0 4px;
|
|
font-size: 13px;
|
|
color: var(--text-muted);
|
|
}
|
|
/*
|
|
* No underline at rest; underline + accent color on hover. We transition only
|
|
* `color` (text-decoration-color animation has partial support on older
|
|
* Obsidian/Electron, flagged by the community CSS lint). Loses just the
|
|
* underline fade-in animation.
|
|
*/
|
|
.synapse-note-link {
|
|
cursor: pointer;
|
|
text-decoration: none;
|
|
transition: color 0.15s;
|
|
}
|
|
.synapse-note-link:hover {
|
|
color: var(--text-accent);
|
|
text-decoration: underline;
|
|
}
|
|
.synapse-empty {
|
|
color: var(--text-muted);
|
|
font-style: italic;
|
|
}
|
|
|
|
/* ── Review Mode (shared) ── */
|
|
.synapse-review-header {
|
|
flex-shrink: 0;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
margin-bottom: 6px;
|
|
}
|
|
.synapse-review-back {
|
|
padding: 2px 8px;
|
|
border-radius: 4px;
|
|
font-size: 12px;
|
|
cursor: pointer;
|
|
border: 1px solid var(--background-modifier-border);
|
|
background: var(--background-primary);
|
|
color: var(--text-muted);
|
|
flex-shrink: 0;
|
|
}
|
|
.synapse-review-back:hover {
|
|
color: var(--text-normal);
|
|
border-color: var(--text-muted);
|
|
}
|
|
.synapse-review-title {
|
|
font-weight: 600;
|
|
font-size: 13px;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
.synapse-review-reasons {
|
|
flex-shrink: 0;
|
|
display: block;
|
|
color: var(--text-muted);
|
|
margin-bottom: 8px;
|
|
font-size: 11px;
|
|
}
|
|
.synapse-review-actions {
|
|
flex-shrink: 0;
|
|
display: flex;
|
|
gap: 8px;
|
|
padding: 8px 0 0;
|
|
border-top: 1px solid var(--background-modifier-border);
|
|
margin-top: 8px;
|
|
}
|
|
.synapse-review-actions button {
|
|
padding: 4px 16px;
|
|
border-radius: 4px;
|
|
font-size: 13px;
|
|
cursor: pointer;
|
|
border: 1px solid var(--background-modifier-border);
|
|
background: var(--background-primary);
|
|
color: var(--text-normal);
|
|
}
|
|
.synapse-review-actions button.mod-cta {
|
|
background: var(--interactive-accent);
|
|
color: var(--text-on-accent);
|
|
border-color: var(--interactive-accent);
|
|
}
|
|
.synapse-review-actions button:hover {
|
|
opacity: 0.9;
|
|
}
|
|
|
|
/* ── Elaboration Review ── */
|
|
.synapse-review-pane {
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
min-height: 0;
|
|
}
|
|
.synapse-review-pane-label {
|
|
flex-shrink: 0;
|
|
font-size: 11px;
|
|
font-weight: 600;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.5px;
|
|
padding: 4px 8px;
|
|
border-radius: 4px 4px 0 0;
|
|
}
|
|
.synapse-review-pane-label--elaboration {
|
|
background: var(--synapse-color-elaboration);
|
|
color: var(--text-on-accent);
|
|
}
|
|
.synapse-review-pane-label--enrichment {
|
|
background: var(--synapse-color-enrichment);
|
|
color: var(--text-on-accent);
|
|
}
|
|
.synapse-review-pane-label--rem {
|
|
background: var(--synapse-color-rem);
|
|
color: var(--text-on-accent);
|
|
}
|
|
/*
|
|
* Shared editor base — neutral structural border. The action-type hue is
|
|
* applied per editor via a `.synapse-review-editor--<type>` modifier so the
|
|
* editor matches its label/card (elaboration was previously hardcoded to
|
|
* `--interactive-accent`, colliding with the user's accent).
|
|
*/
|
|
.synapse-review-editor {
|
|
flex: 1;
|
|
padding: 8px;
|
|
font-size: 13px;
|
|
font-family: var(--font-monospace);
|
|
line-height: 1.5;
|
|
background: var(--background-primary);
|
|
border: 1px solid var(--background-modifier-border);
|
|
border-top: none;
|
|
border-radius: 0 0 4px 4px;
|
|
resize: none;
|
|
color: var(--text-normal);
|
|
min-height: 120px;
|
|
}
|
|
.synapse-review-editor--elaboration {
|
|
border-color: var(--synapse-color-elaboration);
|
|
}
|
|
.synapse-review-editor:focus {
|
|
outline: none;
|
|
border-color: var(--text-accent);
|
|
}
|
|
|
|
/* ── Enrichment Review (checklist) ── */
|
|
.synapse-enrichment-checklist {
|
|
flex: 1;
|
|
overflow-y: auto;
|
|
min-height: 0;
|
|
}
|
|
.synapse-checklist-section {
|
|
margin-bottom: 12px;
|
|
}
|
|
.synapse-checklist-heading {
|
|
font-size: 11px;
|
|
font-weight: 600;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.5px;
|
|
padding: 4px 8px;
|
|
border-radius: 4px;
|
|
background: var(--synapse-color-enrichment);
|
|
color: var(--text-on-accent);
|
|
margin-bottom: 4px;
|
|
}
|
|
.synapse-checklist-row {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
gap: 8px;
|
|
padding: 4px 8px;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
font-size: 13px;
|
|
line-height: 1.4;
|
|
}
|
|
.synapse-checklist-row:hover {
|
|
background: var(--background-modifier-hover);
|
|
}
|
|
.synapse-checklist-row input[type="checkbox"] {
|
|
margin-top: 2px;
|
|
flex-shrink: 0;
|
|
}
|
|
.synapse-checklist-row span {
|
|
color: var(--text-normal);
|
|
word-break: break-word;
|
|
}
|
|
|
|
/* ── Deep Dive ── */
|
|
.synapse-card--deep-dive {
|
|
border-left-color: var(--synapse-color-deep-dive);
|
|
}
|
|
.synapse-badge--deep-dive {
|
|
background: var(--synapse-color-deep-dive);
|
|
color: var(--text-on-accent);
|
|
}
|
|
.synapse-badge-row {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
margin-bottom: 4px;
|
|
}
|
|
.synapse-depth-badge {
|
|
font-size: 10px;
|
|
font-weight: 600;
|
|
padding: 1px 6px;
|
|
border-radius: 3px;
|
|
background: var(--background-modifier-border);
|
|
color: var(--text-muted);
|
|
}
|
|
.synapse-quality-badge {
|
|
font-size: 10px;
|
|
padding: 1px 6px;
|
|
border-radius: 3px;
|
|
background: var(--background-modifier-border);
|
|
color: var(--text-muted);
|
|
}
|
|
.synapse-deep-dive-meta {
|
|
display: flex;
|
|
gap: 8px;
|
|
margin-bottom: 6px;
|
|
}
|
|
.synapse-review-pane-label--deep-dive {
|
|
background: var(--synapse-color-deep-dive);
|
|
color: var(--text-on-accent);
|
|
}
|
|
.synapse-review-editor--deep-dive {
|
|
border-color: var(--synapse-color-deep-dive);
|
|
}
|
|
|
|
/* ── Title ── */
|
|
.synapse-card--title {
|
|
border-left-color: var(--synapse-color-title);
|
|
}
|
|
.synapse-badge--title {
|
|
background: var(--synapse-color-title);
|
|
color: var(--text-on-accent);
|
|
}
|
|
.synapse-review-pane-label--title {
|
|
background: var(--synapse-color-title);
|
|
color: var(--text-on-accent);
|
|
}
|
|
|
|
/* ── REM ── */
|
|
.synapse-card--rem {
|
|
border-left-color: var(--synapse-color-rem);
|
|
}
|
|
.synapse-badge--rem {
|
|
background: var(--synapse-color-rem);
|
|
color: var(--text-on-accent);
|
|
}
|
|
.synapse-badge--rem-title {
|
|
background: var(--interactive-accent);
|
|
color: var(--text-on-accent);
|
|
font-size: 9px;
|
|
padding: 0 4px;
|
|
border-radius: 2px;
|
|
}
|
|
.synapse-badge--rem-alias {
|
|
background: var(--color-green);
|
|
color: var(--text-on-accent);
|
|
font-size: 9px;
|
|
padding: 0 4px;
|
|
border-radius: 2px;
|
|
}
|
|
.synapse-badge--rem-semantic {
|
|
background: var(--color-purple);
|
|
color: var(--text-on-accent);
|
|
font-size: 9px;
|
|
padding: 0 4px;
|
|
border-radius: 2px;
|
|
}
|
|
.synapse-rem-candidate-header {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
padding: 4px 8px;
|
|
margin-bottom: 2px;
|
|
}
|
|
.synapse-rem-target {
|
|
font-weight: 600;
|
|
font-size: 13px;
|
|
color: var(--text-accent);
|
|
}
|
|
.synapse-rem-context {
|
|
font-size: 12px;
|
|
color: var(--text-muted);
|
|
padding: 2px 8px 4px 32px;
|
|
font-family: var(--font-monospace);
|
|
line-height: 1.4;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
.synapse-rem-context mark {
|
|
background: var(--text-highlight-bg);
|
|
color: var(--text-normal);
|
|
padding: 0 2px;
|
|
border-radius: 2px;
|
|
}
|
|
|
|
/* ── Organize Review ── */
|
|
.synapse-review-pane-label--organize {
|
|
background: var(--synapse-color-organize);
|
|
color: var(--text-on-accent);
|
|
}
|
|
.synapse-organize-detail {
|
|
margin-bottom: 12px;
|
|
}
|
|
/*
|
|
* `.synapse-organize-directory` / `.synapse-organize-reasoning` are the generic
|
|
* "detail box" styles, shared by the organize, deep-dive, and title reviews.
|
|
* The base border is neutral structural chrome; the action-type hue is applied
|
|
* per box via a `.synapse-review-box--<type>` modifier (below) so each review's
|
|
* box matches its label and card instead of all defaulting to one hue.
|
|
*/
|
|
.synapse-organize-directory {
|
|
font-size: 14px;
|
|
font-weight: 600;
|
|
font-family: var(--font-monospace);
|
|
color: var(--text-normal);
|
|
padding: 8px;
|
|
background: var(--background-primary);
|
|
border: 1px solid var(--background-modifier-border);
|
|
border-top: none;
|
|
border-radius: 0 0 4px 4px;
|
|
margin: 0;
|
|
}
|
|
.synapse-organize-reasoning {
|
|
font-size: 13px;
|
|
line-height: 1.5;
|
|
color: var(--text-normal);
|
|
padding: 8px;
|
|
background: var(--background-primary);
|
|
border: 1px solid var(--background-modifier-border);
|
|
border-top: none;
|
|
border-radius: 0 0 4px 4px;
|
|
margin: 0;
|
|
}
|
|
/* Per-type accent for detail boxes — keeps each box on its own action token. */
|
|
.synapse-review-box--organize {
|
|
border-color: var(--synapse-color-organize);
|
|
}
|
|
.synapse-review-box--deep-dive {
|
|
border-color: var(--synapse-color-deep-dive);
|
|
}
|
|
.synapse-review-box--title {
|
|
border-color: var(--synapse-color-title);
|
|
}
|
|
|
|
/* ── Title collision (#414) ── */
|
|
.synapse-badge--conflict {
|
|
background: var(--color-orange);
|
|
color: var(--text-on-accent);
|
|
}
|
|
.synapse-title-conflict {
|
|
margin-top: 8px;
|
|
padding: 8px;
|
|
background: var(--background-secondary);
|
|
border-radius: 6px;
|
|
border-left: 3px solid var(--color-orange);
|
|
}
|
|
.synapse-title-conflict-heading {
|
|
font-size: 11px;
|
|
font-weight: 600;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.5px;
|
|
color: var(--color-orange);
|
|
margin-bottom: 4px;
|
|
}
|
|
.synapse-title-conflict-body {
|
|
display: block;
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
/* ── Checkpoint Banner ── */
|
|
.synapse-checkpoint-banner {
|
|
margin-bottom: 12px;
|
|
padding: 8px;
|
|
background: var(--background-secondary);
|
|
border-radius: 6px;
|
|
border-left: 3px solid var(--color-yellow);
|
|
}
|
|
.synapse-checkpoint-heading {
|
|
font-size: 11px;
|
|
font-weight: 600;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.5px;
|
|
color: var(--color-yellow);
|
|
margin-bottom: 6px;
|
|
}
|
|
.synapse-checkpoint-card {
|
|
padding: 6px 0;
|
|
border-bottom: 1px solid var(--background-modifier-border);
|
|
}
|
|
.synapse-checkpoint-card:last-child {
|
|
border-bottom: none;
|
|
}
|
|
.synapse-checkpoint-info {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 2px;
|
|
margin-bottom: 4px;
|
|
}
|
|
.synapse-checkpoint-info strong {
|
|
font-size: 13px;
|
|
}
|
|
.synapse-checkpoint-track {
|
|
width: 100%;
|
|
height: 4px;
|
|
border-radius: 2px;
|
|
background: var(--background-modifier-border);
|
|
overflow: hidden;
|
|
margin-bottom: 6px;
|
|
}
|
|
.synapse-checkpoint-fill {
|
|
height: 100%;
|
|
border-radius: 2px;
|
|
background: var(--color-yellow);
|
|
transition: width 0.2s ease;
|
|
}
|
|
|
|
/* ── Accept All / Reject All ── */
|
|
.synapse-accept-all-bar {
|
|
flex-shrink: 0;
|
|
display: flex;
|
|
gap: 6px;
|
|
margin-bottom: 8px;
|
|
}
|
|
.synapse-accept-all-btn {
|
|
flex: 1;
|
|
padding: 6px 16px;
|
|
border-radius: 4px;
|
|
font-size: 13px;
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
border: 1px solid var(--interactive-accent);
|
|
background: var(--interactive-accent);
|
|
color: var(--text-on-accent);
|
|
}
|
|
.synapse-accept-all-btn:hover {
|
|
opacity: 0.9;
|
|
}
|
|
.synapse-accept-all-btn:disabled {
|
|
opacity: 0.5;
|
|
cursor: not-allowed;
|
|
}
|
|
.synapse-reject-all-btn {
|
|
flex: 1;
|
|
padding: 6px 16px;
|
|
border-radius: 4px;
|
|
font-size: 13px;
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
border: 1px solid var(--background-modifier-border);
|
|
background: var(--background-primary);
|
|
color: var(--text-normal);
|
|
}
|
|
.synapse-reject-all-btn:hover {
|
|
background: var(--background-modifier-hover);
|
|
}
|
|
.synapse-reject-all-btn:disabled {
|
|
opacity: 0.5;
|
|
cursor: not-allowed;
|
|
}
|
|
.synapse-accept-all-progress {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 12px;
|
|
padding: 32px 16px;
|
|
}
|
|
.synapse-accept-all-progress-text {
|
|
font-size: 14px;
|
|
font-weight: 600;
|
|
color: var(--text-normal);
|
|
margin: 0;
|
|
}
|
|
.synapse-accept-all-track {
|
|
width: 100%;
|
|
height: 6px;
|
|
border-radius: 3px;
|
|
background: var(--background-modifier-border);
|
|
overflow: hidden;
|
|
}
|
|
.synapse-accept-all-fill {
|
|
height: 100%;
|
|
border-radius: 3px;
|
|
background: var(--interactive-accent);
|
|
transition: width 0.2s ease;
|
|
}
|
|
|
|
/* ── First-run: required-field emphasis (API key, #89) ──
|
|
* Marks the one field that gates every AI feature while it is still unset.
|
|
* The accent is drawn with an inset box-shadow (not a border) so it adds no
|
|
* layout box and never reflows the row; it clears live the moment a key is
|
|
* entered. Uses the user's accent (violet by default — bridges the brand). */
|
|
.synapse-setting-required {
|
|
box-shadow: inset 3px 0 0 0 var(--interactive-accent);
|
|
padding-left: 12px;
|
|
border-radius: 2px;
|
|
}
|
|
.synapse-setting-required .setting-item-name {
|
|
font-weight: var(--font-semibold);
|
|
}
|
|
|
|
/* ── Friendlier provider auth: get-key link + live validation (#335) ──
|
|
* The "Get an API key →" deep link and the ✓/✗ status chip render INSIDE the
|
|
* credential row's `.setting-item`, on their own full-width line beneath the
|
|
* name/control (the host `.setting-item` sets `flex-wrap: wrap`), so the helper
|
|
* still wraps independently of the row. Colors use Obsidian theme vars for
|
|
* light/dark compatibility. */
|
|
.synapse-credential-extras {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
align-items: center;
|
|
gap: 8px 14px;
|
|
flex-basis: 100%;
|
|
margin-top: 4px;
|
|
font-size: var(--font-ui-smaller);
|
|
}
|
|
/* Lets a nested full-width helper (credential extras / exclusion chips) drop onto
|
|
* its own line below the row's name + control instead of overflowing the flex row. */
|
|
.setting-item.synapse-setting--has-helper {
|
|
flex-wrap: wrap;
|
|
}
|
|
.synapse-get-key-link {
|
|
font-size: var(--font-ui-smaller);
|
|
}
|
|
.synapse-credential-chip {
|
|
min-height: 1em;
|
|
font-size: var(--font-ui-smaller);
|
|
color: var(--text-muted);
|
|
}
|
|
.synapse-credential-chip.is-valid {
|
|
color: var(--text-success);
|
|
}
|
|
.synapse-credential-chip.is-invalid {
|
|
color: var(--text-error);
|
|
}
|
|
.synapse-credential-chip.is-error {
|
|
color: var(--text-warning);
|
|
}
|
|
.synapse-credential-chip.is-checking,
|
|
.synapse-credential-chip.is-hint {
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
/* ── Exclusions: feature scope chips (#328) ──
|
|
* A compact, wrapping row of removable chips (the rule's blocked features) plus
|
|
* an inline "add" dropdown, replacing the per-feature toggle grid. Rendered
|
|
* INSIDE each exclusion rule / add-folder / add-pattern `.setting-item`, on its
|
|
* own full-width line beneath the row (the host sets `flex-wrap: wrap`), so it
|
|
* still wraps independently. */
|
|
.synapse-exclusion-chips {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
align-items: center;
|
|
gap: 6px;
|
|
flex-basis: 100%;
|
|
padding: 4px 0 8px;
|
|
}
|
|
.synapse-chips-container {
|
|
display: flex;
|
|
align-items: center;
|
|
flex: 1;
|
|
gap: 6px;
|
|
flex-wrap: wrap;
|
|
}
|
|
.synapse-chip {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 4px;
|
|
padding: 2px 4px 2px 10px;
|
|
border-radius: 12px;
|
|
background: var(--interactive-accent);
|
|
color: var(--text-on-accent);
|
|
font-size: var(--font-ui-small);
|
|
line-height: 1.4;
|
|
}
|
|
.synapse-chip-remove {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: 16px;
|
|
height: 16px;
|
|
padding: 0;
|
|
border: none;
|
|
border-radius: 50%;
|
|
background: transparent;
|
|
color: inherit;
|
|
font-size: var(--font-ui-smaller);
|
|
cursor: pointer;
|
|
opacity: 0.75;
|
|
box-shadow: none;
|
|
}
|
|
.synapse-chip-remove:hover {
|
|
opacity: 1;
|
|
background: var(--background-modifier-hover);
|
|
}
|
|
.synapse-chip-remove:focus-visible {
|
|
outline: 2px solid var(--interactive-accent);
|
|
outline-offset: 1px;
|
|
opacity: 1;
|
|
}
|
|
.synapse-chip-add {
|
|
font-size: var(--font-ui-small);
|
|
}
|
|
.synapse-exclusion-chips-empty {
|
|
font-size: var(--font-ui-small);
|
|
color: var(--text-muted);
|
|
font-style: italic;
|
|
}
|
|
|
|
/* ══════════════════════════════════════════════════════════════
|
|
* Synapse actions sidebar (#289)
|
|
* Registry-driven action buttons, grouped by feature. Buttons are
|
|
* sized for touch so mobile users reach key functions in <=2 taps.
|
|
* ══════════════════════════════════════════════════════════════ */
|
|
.synapse-actions-view-root {
|
|
padding: 0 8px;
|
|
}
|
|
.synapse-actions-group {
|
|
margin-bottom: 12px;
|
|
}
|
|
.synapse-actions-group-heading {
|
|
font-size: var(--font-ui-smaller);
|
|
font-weight: 600;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.05em;
|
|
color: var(--text-muted);
|
|
margin: 8px 0 4px;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
/*
|
|
* Subtle per-feature accent: a colored left marker on the group heading,
|
|
* driven by the same action-type tokens as the cards/badges. Per-feature
|
|
* overrides below recolor it; `main` keeps the neutral default.
|
|
*/
|
|
padding-left: 8px;
|
|
border-left: 3px solid var(--synapse-color-main);
|
|
}
|
|
.synapse-actions-group--elaboration .synapse-actions-group-heading {
|
|
border-left-color: var(--synapse-color-elaboration);
|
|
}
|
|
.synapse-actions-group--enrichment .synapse-actions-group-heading {
|
|
border-left-color: var(--synapse-color-enrichment);
|
|
}
|
|
.synapse-actions-group--organize .synapse-actions-group-heading {
|
|
border-left-color: var(--synapse-color-organize);
|
|
}
|
|
.synapse-actions-group--deep-dive .synapse-actions-group-heading {
|
|
border-left-color: var(--synapse-color-deep-dive);
|
|
}
|
|
.synapse-actions-group--summarize .synapse-actions-group-heading {
|
|
border-left-color: var(--synapse-color-summarize);
|
|
}
|
|
.synapse-actions-group--tidy .synapse-actions-group-heading {
|
|
border-left-color: var(--synapse-color-tidy);
|
|
}
|
|
.synapse-actions-group--rem .synapse-actions-group-heading {
|
|
border-left-color: var(--synapse-color-rem);
|
|
}
|
|
.synapse-actions-group--video .synapse-actions-group-heading {
|
|
border-left-color: var(--synapse-color-video);
|
|
}
|
|
.synapse-actions-group--main .synapse-actions-group-heading {
|
|
border-left-color: var(--synapse-color-main);
|
|
}
|
|
.synapse-actions-button {
|
|
display: block;
|
|
width: 100%;
|
|
min-height: 44px; /* comfortable touch target (iOS/Material guidance) */
|
|
margin: 4px 0;
|
|
padding: 8px 12px;
|
|
text-align: left;
|
|
white-space: normal;
|
|
cursor: pointer;
|
|
}
|
|
.synapse-actions-button:disabled {
|
|
opacity: 0.5;
|
|
cursor: default;
|
|
}
|
|
/*
|
|
* Feature glyph prefixed to the group heading (#349). The registered SVG draws
|
|
* in `currentColor`, so the feature tint is applied by setting `color` on this
|
|
* span; it reuses the same action-type tokens that accent the heading's left
|
|
* marker. `main`/General keeps the muted default; per-feature overrides recolor.
|
|
*/
|
|
.synapse-actions-group-icon {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
flex: 0 0 auto;
|
|
color: var(--synapse-color-main);
|
|
}
|
|
.synapse-actions-group-icon .svg-icon {
|
|
width: 16px;
|
|
height: 16px;
|
|
}
|
|
.synapse-actions-group-label {
|
|
flex: 1 1 auto;
|
|
}
|
|
.synapse-actions-group--elaboration .synapse-actions-group-icon {
|
|
color: var(--synapse-color-elaboration);
|
|
}
|
|
.synapse-actions-group--enrichment .synapse-actions-group-icon {
|
|
color: var(--synapse-color-enrichment);
|
|
}
|
|
.synapse-actions-group--organize .synapse-actions-group-icon {
|
|
color: var(--synapse-color-organize);
|
|
}
|
|
.synapse-actions-group--deep-dive .synapse-actions-group-icon {
|
|
color: var(--synapse-color-deep-dive);
|
|
}
|
|
.synapse-actions-group--summarize .synapse-actions-group-icon {
|
|
color: var(--synapse-color-summarize);
|
|
}
|
|
.synapse-actions-group--tidy .synapse-actions-group-icon {
|
|
color: var(--synapse-color-tidy);
|
|
}
|
|
.synapse-actions-group--rem .synapse-actions-group-icon {
|
|
color: var(--synapse-color-rem);
|
|
}
|
|
.synapse-actions-group--video .synapse-actions-group-icon {
|
|
color: var(--synapse-color-video);
|
|
}
|
|
.synapse-actions-group--main .synapse-actions-group-icon {
|
|
color: var(--synapse-color-main);
|
|
}
|
|
.synapse-actions-empty {
|
|
color: var(--text-muted);
|
|
font-style: italic;
|
|
padding: 8px;
|
|
}
|
|
|
|
/* ── Video install help (#382/#383) ── */
|
|
|
|
/*
|
|
* Per-OS install-command panel toggled open by the yt-dlp/ffmpeg `?` help
|
|
* button (it adds `.is-open`). Renders directly beneath its path row; left
|
|
* aligned, with each command code-styled and individually copy-able.
|
|
*/
|
|
.synapse-install-help {
|
|
display: none;
|
|
margin: 4px 0 12px;
|
|
padding: 8px 10px;
|
|
border-left: 2px solid var(--background-modifier-border);
|
|
text-align: left;
|
|
}
|
|
|
|
.synapse-install-help.is-open {
|
|
display: block;
|
|
}
|
|
|
|
.synapse-install-help-heading {
|
|
margin-bottom: 6px;
|
|
color: var(--text-muted);
|
|
font-size: var(--font-ui-smaller);
|
|
}
|
|
|
|
.synapse-install-row {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
margin-bottom: 4px;
|
|
}
|
|
|
|
.synapse-install-row:last-child {
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
.synapse-install-os {
|
|
flex: 0 0 auto;
|
|
min-width: 56px;
|
|
color: var(--text-muted);
|
|
font-size: var(--font-ui-smaller);
|
|
}
|
|
|
|
.synapse-install-cmd {
|
|
flex: 1 1 auto;
|
|
font-family: var(--font-monospace);
|
|
font-size: var(--font-ui-smaller);
|
|
background: var(--code-background, var(--background-primary-alt));
|
|
color: var(--code-normal, var(--text-normal));
|
|
padding: 2px 6px;
|
|
border-radius: 4px;
|
|
user-select: text;
|
|
white-space: pre;
|
|
overflow-x: auto;
|
|
}
|
|
|
|
.synapse-install-copy {
|
|
flex: 0 0 auto;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 4px;
|
|
border: none;
|
|
border-radius: 4px;
|
|
background: transparent;
|
|
color: var(--text-muted);
|
|
cursor: pointer;
|
|
}
|
|
|
|
.synapse-install-copy:hover {
|
|
color: var(--text-normal);
|
|
background: var(--background-modifier-hover);
|
|
}
|
|
|
|
.synapse-install-copy.is-copied {
|
|
color: var(--text-success);
|
|
}
|
|
|
|
/* ── Changelog view (#375) ──
|
|
* In-app "What's new" modal: a scrollable, lightly-styled render of CHANGELOG.md.
|
|
* The entry matching the installed version is accented so users can orient. */
|
|
.synapse-changelog .synapse-changelog-body {
|
|
max-height: 60vh;
|
|
overflow-y: auto;
|
|
padding-right: 8px;
|
|
}
|
|
.synapse-changelog-entry {
|
|
margin-bottom: 1.25em;
|
|
}
|
|
.synapse-changelog-version {
|
|
margin-bottom: 0.25em;
|
|
}
|
|
.synapse-changelog-entry--current {
|
|
border-left: 2px solid var(--text-accent);
|
|
padding-left: 0.75em;
|
|
}
|
|
.synapse-changelog-entry--current .synapse-changelog-version {
|
|
color: var(--text-accent);
|
|
}
|
|
.synapse-changelog-section {
|
|
margin: 0.5em 0 0.25em;
|
|
color: var(--text-muted);
|
|
}
|
|
.synapse-changelog-list {
|
|
margin-top: 0;
|
|
}
|
|
.synapse-changelog-link {
|
|
cursor: pointer;
|
|
}
|