.tiptap-ai-target { background: color-mix(in oklab, var(--color-accent-500) 22%, transparent); border-radius: 2px; } .tiptap-ai-preview { display: block; margin: 6px 0; padding: 10px 12px; width: 100%; max-width: 40rem; border-radius: 6px; background: color-mix(in oklab, var(--color-accent-500) 14%, transparent); border: 1px solid color-mix(in oklab, var(--color-accent-500) 45%, transparent); color: var(--color-zinc-100); font-size: 0.92em; white-space: normal; box-sizing: border-box; } .tiptap-ai-preview-streaming { background: color-mix(in oklab, var(--color-accent-500) 9%, transparent); } .tiptap-ai-preview-error { background: color-mix(in oklab, var(--color-red-500, #ef4444) 12%, transparent); border-color: color-mix(in oklab, var(--color-red-500, #ef4444) 45%, transparent); } .tiptap-ai-preview-bubble { display: block; min-height: 1.35em; word-break: break-word; color: var(--color-zinc-100); } .tiptap-ai-preview-actions { display: flex; justify-content: flex-end; align-items: center; gap: 8px; margin-top: 8px; padding-top: 8px; border-top: 1px solid color-mix(in oklab, var(--color-accent-500) 22%, transparent); font-size: 0.82em; color: var(--color-zinc-400); } .tiptap-ai-preview-divider { color: color-mix(in oklab, var(--color-zinc-400) 70%, transparent); user-select: none; } .tiptap-ai-preview-bubble-pending { color: var(--color-zinc-400); font-style: italic; animation: tiptap-ai-preview-pending 1.2s ease-in-out infinite; } @keyframes tiptap-ai-preview-pending { 0%, 100% { opacity: 0.55; } 50% { opacity: 1; } } .tiptap-ai-preview-action { appearance: none; border: none; background: transparent; color: inherit; font: inherit; cursor: pointer; padding: 2px 4px; display: inline-flex; align-items: center; gap: 6px; border-radius: 4px; } .tiptap-ai-preview-action:hover:not(:disabled), .tiptap-ai-preview-action:focus-visible { color: var(--color-zinc-100); outline: none; } .tiptap-ai-preview-action:disabled { cursor: not-allowed; opacity: 0.5; } /* Shared kbd pill — reused by rewrite preview actions and the /continue indicator's cancel. Mono, double-bottom border for a "key" texture, accent tint so it reads as part of the AI surface family. */ .tiptap-ai-kbd { font-family: var(--font-mono); font-size: 0.88em; font-style: normal; font-weight: 500; min-width: 1.8em; padding: 1px 5px; border: 1px solid color-mix(in oklab, var(--color-accent-500) 40%, transparent); border-bottom-width: 2px; background: color-mix(in oklab, var(--color-accent-500) 10%, transparent); border-radius: 3px; color: var(--color-zinc-200); line-height: 1.2; text-align: center; } .tiptap-ai-preview-action:hover:not(:disabled) .tiptap-ai-kbd, .tiptap-ai-preview-action:focus-visible .tiptap-ai-kbd, .tiptap-ai-generate-cancel:hover .tiptap-ai-kbd, .tiptap-ai-generate-cancel:focus-visible .tiptap-ai-kbd { background: color-mix(in oklab, var(--color-accent-500) 22%, transparent); color: var(--color-zinc-100); } .tiptap-ai-preview-accept .tiptap-ai-kbd { color: var(--color-accent-300); border-color: color-mix(in oklab, var(--color-accent-500) 55%, transparent); } /* inline-block (not inline-flex) so Firefox's caret renderer measures against the text line box, not the flex line; otherwise the native caret stretches to the tallest child and the dot drifts off the x-height. */ .tiptap-ai-generate-indicator { display: inline-block; vertical-align: baseline; color: color-mix(in oklab, var(--color-accent-400) 75%, var(--color-zinc-400)); font-style: italic; font-weight: 400; user-select: none; } /* The empty-paragraph placeholder ("Start typing, or press / …") would bleed under the ghost indicator, so suppress it while the indicator is inline. */ .tiptap > p.is-empty:has(.tiptap-ai-generate-indicator)::before { display: none; } /* Firefox measures the native caret against the paragraph's full line-box, so inline widgets stretch it to a tall bar. The "Continuing…" indicator already communicates the pending state, so hide the native caret while it's active for pixel-identical rendering across browsers. */ .tiptap > p:has(.tiptap-ai-generate-indicator) { caret-color: transparent; } .tiptap-ai-generate-indicator-dot { display: inline-block; vertical-align: middle; width: 5px; height: 5px; border-radius: 50%; margin: 0 6px 0 10px; background: currentColor; animation: tiptap-ai-generate-pulse 1.1s ease-in-out infinite; } .tiptap-ai-generate-indicator-label { margin-right: 6px; } .tiptap-ai-generate-cancel { appearance: none; border: none; background: transparent; color: color-mix(in oklab, currentColor 75%, var(--color-zinc-200)); cursor: pointer; padding: 0 2px; font-family: inherit; font-weight: inherit; font-style: normal; /* Scaled down so the kbd pill sits at the same optical size as the preview footer (~0.82em × 0.88em kbd), instead of competing with the italic label at body size. */ font-size: 0.82em; display: inline-flex; align-items: center; gap: 5px; border-radius: 4px; vertical-align: baseline; } .tiptap-ai-generate-cancel:hover, .tiptap-ai-generate-cancel:focus-visible { color: var(--color-zinc-100); outline: none; } @keyframes tiptap-ai-generate-pulse { 0%, 100% { opacity: 0.35; transform: scale(0.8); } 50% { opacity: 1; transform: scale(1); } }