@@ -4105,8 +4143,22 @@ export function ProjectView({
showTrafficSpace={false}
onBack={onBack}
backLabel={t('project.backToProjects')}
- actions={(
+ fileActionsBefore={(
<>
+
+
>
)}
+ actions={(
+ null
+ )}
>
@@ -4142,39 +4201,28 @@ export function ProjectView({
>
{project.name}
-
{projectMeta}
+ {projectMeta !== t('project.metaFreeform') ? (
+
{projectMeta}
+ ) : null}
- {(project.customInstructions ?? '').trim() ? (
+ {hasProjectInstructions ? (
- ) : (
-
- )}
+ ) : null}
@@ -4246,6 +4294,7 @@ export function ProjectView({
ref={splitRef}
className={[
projectSplitClassName(workspaceFocused),
+ leftInspectorActive && !workspaceFocused ? 'split-manual-edit' : '',
resizingChatPanel && !workspaceFocused ? 'is-resizing-chat' : '',
].filter(Boolean).join(' ')}
style={workspaceFocused
@@ -4256,7 +4305,13 @@ export function ProjectView({
}}
>
- {activeConversationId || conversationLoadError ? (
+ {commentInspectorActive ? (
+
+ ) : activeConversationId || conversationLoadError ? (
{!workspaceFocused ? (
-
+ leftInspectorActive ? (
+
+ ) : (
+
+ )
) : null}
{projectActionsToast ? (
@@ -4455,6 +4516,68 @@ export function findExistingArtifactProjectFile(
return currentRunFiles.find((file) => file.name === candidateFileName) ?? null;
}
+export function selectPrimaryProjectFile(files: ProjectFile[]): ProjectFile | null {
+ const candidates = files
+ .filter((file) => !isProcessArtifactFile(file.name))
+ .map((file) => ({ file, rank: primaryProjectFileRank(file) }))
+ .filter((candidate) => Number.isFinite(candidate.rank));
+ if (candidates.length === 0) return null;
+ candidates.sort((a, b) => a.rank - b.rank || b.file.mtime - a.file.mtime);
+ return candidates[0]?.file ?? null;
+}
+
+function isProcessArtifactFile(name: string): boolean {
+ const base = name.split('/').pop()?.toLowerCase() ?? name.toLowerCase();
+ return (
+ base === 'critique.json'
+ || base.endsWith('.log')
+ || base.endsWith('.meta.json')
+ || base.endsWith('.artifact.json')
+ || base.endsWith('.map')
+ );
+}
+
+function primaryProjectFileRank(file: ProjectFile): number {
+ if (manifestDeclaresPrimary(file)) return 0;
+ if (file.artifactManifest && file.artifactManifest.metadata?.inferred !== true) return 1;
+ if (file.kind === 'html') return 2;
+ if (file.kind === 'image') return 3;
+ if (file.kind === 'video') return 4;
+ if (file.kind === 'sketch') return 5;
+ if (file.kind === 'pdf') return 6;
+ if (file.kind === 'presentation') return 7;
+ if (file.kind === 'document') return 8;
+ if (file.kind === 'spreadsheet') return 9;
+ return Number.POSITIVE_INFINITY;
+}
+
+function manifestDeclaresPrimary(file: ProjectFile): boolean {
+ const manifest = file.artifactManifest;
+ if (!manifest) return false;
+ if (primaryValueTargetsFile(manifest.primary, file.name)) return true;
+ const metadata = manifest.metadata;
+ if (!metadata || typeof metadata !== 'object') return false;
+ if (primaryValueTargetsFile(metadata.primary, file.name)) return true;
+ const outputs = metadata.outputs;
+ if (outputs && typeof outputs === 'object' && !Array.isArray(outputs)) {
+ return primaryValueTargetsFile(
+ (outputs as { primary?: unknown }).primary,
+ file.name,
+ );
+ }
+ return false;
+}
+
+function primaryValueTargetsFile(value: unknown, fileName: string): boolean {
+ if (value === true) return true;
+ if (typeof value !== 'string') return false;
+ return normalizeProjectFileName(value) === normalizeProjectFileName(fileName);
+}
+
+function normalizeProjectFileName(value: string): string {
+ return value.replace(/\\/g, '/').replace(/^\.?\//, '').toLowerCase();
+}
+
function assistantAgentDisplayName(
agentId: string | null,
fallbackName?: string,
@@ -4470,6 +4593,10 @@ function isActiveRunStatus(status: ChatMessage['runStatus']): boolean {
return status === 'queued' || status === 'running';
}
+function compactInlinePreview(value: string): string {
+ return value.replace(/\s+/g, ' ').trim();
+}
+
export interface RetryTarget {
failedAssistant: ChatMessage;
userMsg: ChatMessage;
diff --git a/apps/web/src/components/RemixIcon.tsx b/apps/web/src/components/RemixIcon.tsx
new file mode 100644
index 000000000..e08b52a70
--- /dev/null
+++ b/apps/web/src/components/RemixIcon.tsx
@@ -0,0 +1,27 @@
+import type { CSSProperties } from 'react';
+
+interface RemixIconProps {
+ name: string;
+ size?: number;
+ className?: string;
+ style?: CSSProperties;
+}
+
+export function RemixIcon({ name, size = 14, className, style }: RemixIconProps) {
+ return (
+
+ );
+}
diff --git a/apps/web/src/edit-mode/bridge.ts b/apps/web/src/edit-mode/bridge.ts
index 6757566ab..9edc649c6 100644
--- a/apps/web/src/edit-mode/bridge.ts
+++ b/apps/web/src/edit-mode/bridge.ts
@@ -207,6 +207,76 @@ export function buildManualEditBridge(enabled: boolean): string {
}
return fallback;
}
+ function caretRangeFromClick(clickEvent){
+ try {
+ if (document.caretPositionFromPoint) {
+ var position = document.caretPositionFromPoint(clickEvent.clientX, clickEvent.clientY);
+ if (!position) return null;
+ var positionRange = document.createRange();
+ positionRange.setStart(position.offsetNode, position.offset);
+ positionRange.collapse(true);
+ return positionRange;
+ }
+ if (document.caretRangeFromPoint) {
+ return document.caretRangeFromPoint(clickEvent.clientX, clickEvent.clientY);
+ }
+ } catch (e) {}
+ return null;
+ }
+ function placeCaretFromClick(clickEvent, el){
+ var range = caretRangeFromClick(clickEvent);
+ if (!range) {
+ range = document.createRange();
+ range.selectNodeContents(el);
+ range.collapse(false);
+ }
+ try {
+ var sel = window.getSelection();
+ if (!sel) return;
+ sel.removeAllRanges();
+ sel.addRange(range);
+ } catch (e) {}
+ }
+ function makeEditable(el, clickEvent){
+ if (!el || el.getAttribute('contenteditable') === 'true') return;
+ var originalText = el.textContent || '';
+ clearSelectedTarget();
+ el.setAttribute('contenteditable', 'plaintext-only');
+ el.setAttribute('data-od-editing', 'true');
+ try { el.focus(); } catch (e) {}
+ placeCaretFromClick(clickEvent, el);
+ function finish(commit){
+ el.removeAttribute('contenteditable');
+ el.removeAttribute('data-od-editing');
+ el.removeEventListener('blur', onBlur);
+ el.removeEventListener('keydown', onKey);
+ var value = (el.textContent || '').trim();
+ if (commit && value !== originalText.trim()) {
+ window.parent.postMessage({
+ type: 'od-edit-text-commit',
+ id: stableId(el),
+ value: value
+ }, '*');
+ } else if (!commit) {
+ el.textContent = originalText;
+ }
+ }
+ function onBlur(){ finish(true); }
+ function onKey(ev){
+ if (ev.key === 'Enter' && !ev.shiftKey) {
+ ev.preventDefault();
+ finish(true);
+ try { el.blur(); } catch (e) {}
+ }
+ if (ev.key === 'Escape') {
+ ev.preventDefault();
+ finish(false);
+ try { el.blur(); } catch (e) {}
+ }
+ }
+ el.addEventListener('blur', onBlur);
+ el.addEventListener('keydown', onKey);
+ }
function camelToKebab(name){ return String(name).replace(/[A-Z]/g, function(m){ return '-' + m.toLowerCase(); }); }
function cssEscapeId(value){ if (typeof CSS !== 'undefined' && CSS.escape) return CSS.escape(value); return String(value).replace(/"/g, '\\\\"'); }
function findById(id){
@@ -270,10 +340,16 @@ export function buildManualEditBridge(enabled: boolean): string {
});
document.addEventListener('click', function(ev){
if (!enabled) return;
+ if (ev.target && ev.target.closest && ev.target.closest('[data-od-editing="true"]')) return;
var el = closestTarget(ev);
if (!el) return;
ev.preventDefault();
ev.stopPropagation();
+ var kind = inferKind(el);
+ if (kind === 'text' || kind === 'link') {
+ makeEditable(el, ev);
+ return;
+ }
window.parent.postMessage({ type: 'od-edit-select', target: targetFrom(el, true) }, '*');
}, true);
window.addEventListener('resize', postTargets);
@@ -295,5 +371,11 @@ html[data-od-edit-mode] [data-od-edit-selected] {
outline-offset: 4px;
box-shadow: 0 0 0 4px rgba(37, 99, 235, 0.16);
}
+html[data-od-edit-mode] [data-od-editing="true"] {
+ outline: 2px solid #2563eb !important;
+ outline-offset: 4px;
+ background: rgba(37, 99, 235, 0.06);
+ cursor: text !important;
+}
`;
}
diff --git a/apps/web/src/edit-mode/types.ts b/apps/web/src/edit-mode/types.ts
index be9e53629..d35cc6e88 100644
--- a/apps/web/src/edit-mode/types.ts
+++ b/apps/web/src/edit-mode/types.ts
@@ -105,10 +105,17 @@ export interface ManualEditPreviewAppliedMessage {
error?: string;
}
+export interface ManualEditTextCommitMessage {
+ type: 'od-edit-text-commit';
+ id: string;
+ value: string;
+}
+
export type ManualEditBridgeMessage =
| ManualEditTargetMessage
| ManualEditSelectMessage
- | ManualEditPreviewAppliedMessage;
+ | ManualEditPreviewAppliedMessage
+ | ManualEditTextCommitMessage;
export const MANUAL_EDIT_STYLE_PROPS: readonly (keyof ManualEditStyles)[] = [
'fontFamily', 'fontSize', 'fontWeight', 'color', 'textAlign', 'lineHeight', 'letterSpacing',
diff --git a/apps/web/src/i18n/locales/ar.ts b/apps/web/src/i18n/locales/ar.ts
index 8a00f289b..c99d73bcd 100644
--- a/apps/web/src/i18n/locales/ar.ts
+++ b/apps/web/src/i18n/locales/ar.ts
@@ -762,6 +762,10 @@ export const ar: Dict = {
'chat.comments.pinAtCoords': 'at {x}, {y}',
'chat.comments.capturedItems': '{n} captured items',
'chat.comments.clear': 'Clear',
+ 'chat.inspect.noEditableTargets': 'This page has no editable elements yet.',
+ 'chat.inspect.noCommentTargets': 'This page has no commentable elements yet.',
+ 'chat.inspect.editHint': 'Click an element in the canvas to edit its styles.',
+ 'chat.inspect.commentHint': 'Click an element in the canvas to add a comment.',
'chat.conversationsTitle': 'المحادثات',
'chat.conversationsAria': 'سجل المحادثات',
'chat.newConversation': 'محادثة جديدة',
diff --git a/apps/web/src/i18n/locales/de.ts b/apps/web/src/i18n/locales/de.ts
index a6b2ffadb..2fdd71acc 100644
--- a/apps/web/src/i18n/locales/de.ts
+++ b/apps/web/src/i18n/locales/de.ts
@@ -650,6 +650,10 @@ export const de: Dict = {
'chat.comments.pinAtCoords': 'bei {x}, {y}',
'chat.comments.capturedItems': '{n} erfasste Elemente',
'chat.comments.clear': 'Löschen',
+ 'chat.inspect.noEditableTargets': 'This page has no editable elements yet.',
+ 'chat.inspect.noCommentTargets': 'This page has no commentable elements yet.',
+ 'chat.inspect.editHint': 'Click an element in the canvas to edit its styles.',
+ 'chat.inspect.commentHint': 'Click an element in the canvas to add a comment.',
'chat.conversationsTitle': 'Konversationen',
'chat.conversationsAria': 'Konversationsverlauf',
'chat.newConversation': 'Neue Konversation',
diff --git a/apps/web/src/i18n/locales/en.ts b/apps/web/src/i18n/locales/en.ts
index 2f5239afd..49ac1ba70 100644
--- a/apps/web/src/i18n/locales/en.ts
+++ b/apps/web/src/i18n/locales/en.ts
@@ -483,6 +483,9 @@ export const en: Dict = {
'workingDirPicker.replace': 'Clear and replace directory…',
'workingDirPicker.recent': 'Recent directories',
'handoff.toTarget': 'Hand off to {target}',
+ 'handoff.openInTarget': 'Open in {target}',
+ 'handoff.openAction': 'Open',
+ 'handoff.menuTitle': 'Open in which editor?',
'handoff.action': 'Hand off',
'handoff.fallbackTitle': 'No editors found on $PATH - opens in {target}',
'handoff.chooseTargetAria': 'Choose hand-off target',
@@ -1371,6 +1374,10 @@ export const en: Dict = {
'chat.openFile': 'Open {name}',
'chat.copyPrompt': 'Copy prompt',
'chat.copyDone': 'Copied!',
+ 'chat.inspect.noEditableTargets': 'No editable text or style targets found.',
+ 'chat.inspect.noCommentTargets': 'No commentable text or visual targets found.',
+ 'chat.inspect.editHint': 'Select a text or style target in the preview to edit it.',
+ 'chat.inspect.commentHint': 'Select text or an area in the preview to comment on it.',
'chat.composerPlaceholder': "Describe what you want to generate…",
'chat.composerHint': "⌘/Ctrl + Enter to send · include goals, content, style, and format",
'chat.cliSettingsTitle': 'CLI & model settings',
diff --git a/apps/web/src/i18n/locales/es-ES.ts b/apps/web/src/i18n/locales/es-ES.ts
index ea940eca4..9234163c4 100644
--- a/apps/web/src/i18n/locales/es-ES.ts
+++ b/apps/web/src/i18n/locales/es-ES.ts
@@ -651,6 +651,10 @@ export const esES: Dict = {
'chat.comments.pinAtCoords': 'at {x}, {y}',
'chat.comments.capturedItems': '{n} captured items',
'chat.comments.clear': 'Clear',
+ 'chat.inspect.noEditableTargets': 'This page has no editable elements yet.',
+ 'chat.inspect.noCommentTargets': 'This page has no commentable elements yet.',
+ 'chat.inspect.editHint': 'Click an element in the canvas to edit its styles.',
+ 'chat.inspect.commentHint': 'Click an element in the canvas to add a comment.',
'chat.conversationsTitle': 'Conversaciones',
'chat.conversationsAria': 'Historial de conversaciones',
'chat.newConversation': 'Nueva conversación',
diff --git a/apps/web/src/i18n/locales/fa.ts b/apps/web/src/i18n/locales/fa.ts
index 6eff8103c..58b0d3715 100644
--- a/apps/web/src/i18n/locales/fa.ts
+++ b/apps/web/src/i18n/locales/fa.ts
@@ -784,6 +784,10 @@ export const fa: Dict = {
'chat.comments.pinAtCoords': 'at {x}, {y}',
'chat.comments.capturedItems': '{n} captured items',
'chat.comments.clear': 'Clear',
+ 'chat.inspect.noEditableTargets': 'This page has no editable elements yet.',
+ 'chat.inspect.noCommentTargets': 'This page has no commentable elements yet.',
+ 'chat.inspect.editHint': 'Click an element in the canvas to edit its styles.',
+ 'chat.inspect.commentHint': 'Click an element in the canvas to add a comment.',
'chat.conversationsTitle': 'مکالمات',
'chat.conversationsAria': 'تاریخچه مکالمات',
'chat.newConversation': 'مکالمه جدید',
diff --git a/apps/web/src/i18n/locales/fr.ts b/apps/web/src/i18n/locales/fr.ts
index 4458b1baa..64e65297a 100644
--- a/apps/web/src/i18n/locales/fr.ts
+++ b/apps/web/src/i18n/locales/fr.ts
@@ -778,6 +778,10 @@ export const fr: Dict = {
'chat.comments.pinAtCoords': 'à {x}, {y}',
'chat.comments.capturedItems': '{n} élément(s) capturé(s)',
'chat.comments.clear': 'Effacer',
+ 'chat.inspect.noEditableTargets': 'This page has no editable elements yet.',
+ 'chat.inspect.noCommentTargets': 'This page has no commentable elements yet.',
+ 'chat.inspect.editHint': 'Click an element in the canvas to edit its styles.',
+ 'chat.inspect.commentHint': 'Click an element in the canvas to add a comment.',
'chat.conversationsTitle': 'Conversations',
'chat.conversationsAria': 'Historique des conversations',
'chat.newConversation': 'Nouvelle conversation',
diff --git a/apps/web/src/i18n/locales/hu.ts b/apps/web/src/i18n/locales/hu.ts
index 2a23168aa..eba204b7c 100644
--- a/apps/web/src/i18n/locales/hu.ts
+++ b/apps/web/src/i18n/locales/hu.ts
@@ -762,6 +762,10 @@ export const hu: Dict = {
'chat.comments.pinAtCoords': 'at {x}, {y}',
'chat.comments.capturedItems': '{n} captured items',
'chat.comments.clear': 'Clear',
+ 'chat.inspect.noEditableTargets': 'This page has no editable elements yet.',
+ 'chat.inspect.noCommentTargets': 'This page has no commentable elements yet.',
+ 'chat.inspect.editHint': 'Click an element in the canvas to edit its styles.',
+ 'chat.inspect.commentHint': 'Click an element in the canvas to add a comment.',
'chat.conversationsTitle': 'Beszélgetések',
'chat.conversationsAria': 'Beszélgetések előzménye',
'chat.newConversation': 'Új beszélgetés',
diff --git a/apps/web/src/i18n/locales/id.ts b/apps/web/src/i18n/locales/id.ts
index 6dade1eff..4f957c8fc 100644
--- a/apps/web/src/i18n/locales/id.ts
+++ b/apps/web/src/i18n/locales/id.ts
@@ -876,6 +876,10 @@ export const id: Dict = {
'chat.comments.pinAtCoords': 'at {x}, {y}',
'chat.comments.capturedItems': '{n} captured items',
'chat.comments.clear': 'Clear',
+ 'chat.inspect.noEditableTargets': 'This page has no editable elements yet.',
+ 'chat.inspect.noCommentTargets': 'This page has no commentable elements yet.',
+ 'chat.inspect.editHint': 'Click an element in the canvas to edit its styles.',
+ 'chat.inspect.commentHint': 'Click an element in the canvas to add a comment.',
'chat.conversationsTitle': 'Percakapan',
'chat.conversationsAria': 'Buka percakapan',
'chat.newConversation': 'Percakapan baru',
diff --git a/apps/web/src/i18n/locales/it.ts b/apps/web/src/i18n/locales/it.ts
index cc9748789..e3b09e4c4 100644
--- a/apps/web/src/i18n/locales/it.ts
+++ b/apps/web/src/i18n/locales/it.ts
@@ -680,6 +680,10 @@ export const it: Dict = {
'chat.comments.updateSend': 'Aggiorna e invia',
'chat.comments.removeAttachment': 'Rimuovi commento allegato',
'chat.comments.removeAttachmentAria': 'Rimuovi commento allegato per {name}',
+ 'chat.inspect.noEditableTargets': 'This page has no editable elements yet.',
+ 'chat.inspect.noCommentTargets': 'This page has no commentable elements yet.',
+ 'chat.inspect.editHint': 'Click an element in the canvas to edit its styles.',
+ 'chat.inspect.commentHint': 'Click an element in the canvas to add a comment.',
'chat.conversationsTitle': 'Conversazioni',
'chat.conversationsAria': 'Cronologia delle conversazioni',
'chat.newConversation': 'Nuova conversazione',
diff --git a/apps/web/src/i18n/locales/ja.ts b/apps/web/src/i18n/locales/ja.ts
index 189742e71..963c46f4e 100644
--- a/apps/web/src/i18n/locales/ja.ts
+++ b/apps/web/src/i18n/locales/ja.ts
@@ -649,6 +649,10 @@ export const ja: Dict = {
'chat.comments.pinAtCoords': 'at {x}, {y}',
'chat.comments.capturedItems': '{n} captured items',
'chat.comments.clear': 'Clear',
+ 'chat.inspect.noEditableTargets': 'This page has no editable elements yet.',
+ 'chat.inspect.noCommentTargets': 'This page has no commentable elements yet.',
+ 'chat.inspect.editHint': 'Click an element in the canvas to edit its styles.',
+ 'chat.inspect.commentHint': 'Click an element in the canvas to add a comment.',
'chat.conversationsTitle': '会話',
'chat.conversationsAria': '会話履歴',
'chat.newConversation': '新しい会話',
diff --git a/apps/web/src/i18n/locales/ko.ts b/apps/web/src/i18n/locales/ko.ts
index 3aece1690..05ef1626f 100644
--- a/apps/web/src/i18n/locales/ko.ts
+++ b/apps/web/src/i18n/locales/ko.ts
@@ -762,6 +762,10 @@ export const ko: Dict = {
'chat.comments.pinAtCoords': 'at {x}, {y}',
'chat.comments.capturedItems': '{n} captured items',
'chat.comments.clear': 'Clear',
+ 'chat.inspect.noEditableTargets': 'This page has no editable elements yet.',
+ 'chat.inspect.noCommentTargets': 'This page has no commentable elements yet.',
+ 'chat.inspect.editHint': 'Click an element in the canvas to edit its styles.',
+ 'chat.inspect.commentHint': 'Click an element in the canvas to add a comment.',
'chat.conversationsTitle': '대화 목록',
'chat.conversationsAria': '대화 내역',
'chat.newConversation': '새 대화 시작',
diff --git a/apps/web/src/i18n/locales/pl.ts b/apps/web/src/i18n/locales/pl.ts
index 17a328fea..2284d0c6b 100644
--- a/apps/web/src/i18n/locales/pl.ts
+++ b/apps/web/src/i18n/locales/pl.ts
@@ -762,6 +762,10 @@ export const pl: Dict = {
'chat.comments.pinAtCoords': 'at {x}, {y}',
'chat.comments.capturedItems': '{n} captured items',
'chat.comments.clear': 'Clear',
+ 'chat.inspect.noEditableTargets': 'This page has no editable elements yet.',
+ 'chat.inspect.noCommentTargets': 'This page has no commentable elements yet.',
+ 'chat.inspect.editHint': 'Click an element in the canvas to edit its styles.',
+ 'chat.inspect.commentHint': 'Click an element in the canvas to add a comment.',
'chat.conversationsTitle': 'Rozmowy',
'chat.conversationsAria': 'Historia rozmów',
'chat.newConversation': 'Nowa rozmowa',
diff --git a/apps/web/src/i18n/locales/pt-BR.ts b/apps/web/src/i18n/locales/pt-BR.ts
index 4483f03c1..095d38448 100644
--- a/apps/web/src/i18n/locales/pt-BR.ts
+++ b/apps/web/src/i18n/locales/pt-BR.ts
@@ -783,6 +783,10 @@ export const ptBR: Dict = {
'chat.comments.pinAtCoords': 'at {x}, {y}',
'chat.comments.capturedItems': '{n} captured items',
'chat.comments.clear': 'Clear',
+ 'chat.inspect.noEditableTargets': 'This page has no editable elements yet.',
+ 'chat.inspect.noCommentTargets': 'This page has no commentable elements yet.',
+ 'chat.inspect.editHint': 'Click an element in the canvas to edit its styles.',
+ 'chat.inspect.commentHint': 'Click an element in the canvas to add a comment.',
'chat.conversationsTitle': 'Conversas',
'chat.conversationsAria': 'Histórico de conversas',
'chat.newConversation': 'Nova conversa',
diff --git a/apps/web/src/i18n/locales/ru.ts b/apps/web/src/i18n/locales/ru.ts
index b91621c0a..d3f17b327 100644
--- a/apps/web/src/i18n/locales/ru.ts
+++ b/apps/web/src/i18n/locales/ru.ts
@@ -783,6 +783,10 @@ export const ru: Dict = {
'chat.comments.pinAtCoords': 'at {x}, {y}',
'chat.comments.capturedItems': '{n} captured items',
'chat.comments.clear': 'Clear',
+ 'chat.inspect.noEditableTargets': 'This page has no editable elements yet.',
+ 'chat.inspect.noCommentTargets': 'This page has no commentable elements yet.',
+ 'chat.inspect.editHint': 'Click an element in the canvas to edit its styles.',
+ 'chat.inspect.commentHint': 'Click an element in the canvas to add a comment.',
'chat.conversationsTitle': 'Разговоры',
'chat.conversationsAria': 'История разговоров',
'chat.newConversation': 'Новый разговор',
diff --git a/apps/web/src/i18n/locales/th.ts b/apps/web/src/i18n/locales/th.ts
index e4908ba50..a6a4cc8b4 100644
--- a/apps/web/src/i18n/locales/th.ts
+++ b/apps/web/src/i18n/locales/th.ts
@@ -718,6 +718,10 @@ export const th: Dict = {
'chat.comments.pinAtCoords': 'at {x}, {y}',
'chat.comments.capturedItems': '{n} captured items',
'chat.comments.clear': 'Clear',
+ 'chat.inspect.noEditableTargets': 'This page has no editable elements yet.',
+ 'chat.inspect.noCommentTargets': 'This page has no commentable elements yet.',
+ 'chat.inspect.editHint': 'Click an element in the canvas to edit its styles.',
+ 'chat.inspect.commentHint': 'Click an element in the canvas to add a comment.',
'chat.conversationsTitle': 'การสนทนา',
'chat.conversationsAria': 'ประวัติ',
'chat.newConversation': 'สนทนาใหม่',
diff --git a/apps/web/src/i18n/locales/tr.ts b/apps/web/src/i18n/locales/tr.ts
index 4d13d9fe7..8b7bcc4f0 100644
--- a/apps/web/src/i18n/locales/tr.ts
+++ b/apps/web/src/i18n/locales/tr.ts
@@ -751,6 +751,10 @@ export const tr: Dict = {
'chat.comments.pinAtCoords': 'at {x}, {y}',
'chat.comments.capturedItems': '{n} captured items',
'chat.comments.clear': 'Clear',
+ 'chat.inspect.noEditableTargets': 'This page has no editable elements yet.',
+ 'chat.inspect.noCommentTargets': 'This page has no commentable elements yet.',
+ 'chat.inspect.editHint': 'Click an element in the canvas to edit its styles.',
+ 'chat.inspect.commentHint': 'Click an element in the canvas to add a comment.',
'chat.conversationsTitle': 'Konuşmalar',
'chat.conversationsAria': 'Konuşma geçmişi',
'chat.newConversation': 'Yeni konuşma',
diff --git a/apps/web/src/i18n/locales/uk.ts b/apps/web/src/i18n/locales/uk.ts
index 013654174..7a445f319 100644
--- a/apps/web/src/i18n/locales/uk.ts
+++ b/apps/web/src/i18n/locales/uk.ts
@@ -784,6 +784,10 @@ export const uk: Dict = {
'chat.comments.pinAtCoords': 'at {x}, {y}',
'chat.comments.capturedItems': '{n} captured items',
'chat.comments.clear': 'Clear',
+ 'chat.inspect.noEditableTargets': 'This page has no editable elements yet.',
+ 'chat.inspect.noCommentTargets': 'This page has no commentable elements yet.',
+ 'chat.inspect.editHint': 'Click an element in the canvas to edit its styles.',
+ 'chat.inspect.commentHint': 'Click an element in the canvas to add a comment.',
'chat.conversationsTitle': 'Розмови',
'chat.conversationsAria': 'Історія розмов',
'chat.newConversation': 'Нова розмова',
diff --git a/apps/web/src/i18n/locales/zh-CN.ts b/apps/web/src/i18n/locales/zh-CN.ts
index ea257e4a7..50732a343 100644
--- a/apps/web/src/i18n/locales/zh-CN.ts
+++ b/apps/web/src/i18n/locales/zh-CN.ts
@@ -483,6 +483,9 @@ export const zhCN: Dict = {
'workingDirPicker.replace': '清空并替换目录…',
'workingDirPicker.recent': '最近使用的目录',
'handoff.toTarget': '交付给 {target}',
+ 'handoff.openInTarget': '在 {target} 中打开',
+ 'handoff.openAction': '打开',
+ 'handoff.menuTitle': '在哪个编辑器中打开?',
'handoff.action': '交付',
'handoff.fallbackTitle': '未找到编辑器 - 使用 {target} 打开',
'handoff.chooseTargetAria': '选择交付目标',
@@ -1362,6 +1365,10 @@ export const zhCN: Dict = {
'chat.openFile': '打开 {name}',
'chat.copyPrompt': '复制提示词',
'chat.copyDone': '已复制!',
+ 'chat.inspect.noEditableTargets': '未找到可编辑的文本或样式目标。',
+ 'chat.inspect.noCommentTargets': '未找到可评论的文本或视觉目标。',
+ 'chat.inspect.editHint': '在预览中选择文本或样式目标进行编辑。',
+ 'chat.inspect.commentHint': '在预览中选择文本或区域进行评论。',
'chat.composerPlaceholder': "描述你想生成的内容…",
'chat.composerHint': "⌘/Ctrl + Enter 发送 · 说清目标、内容、风格和格式",
'chat.cliSettingsTitle': 'CLI 与模型设置',
@@ -1563,7 +1570,7 @@ export const zhCN: Dict = {
'fileViewer.jsxModuleTitle': '无独立预览',
'fileViewer.jsxModuleBody': '此文件是由其他页面加载的组件模块。',
'fileViewer.jsxModuleCta': '请打开渲染它的页面:',
- 'fileViewer.comment': '评论',
+ 'fileViewer.comment': '注释',
'fileViewer.edit': '编辑',
'fileViewer.draw': '绘制',
'manualEdit.layers': '图层',
diff --git a/apps/web/src/i18n/locales/zh-TW.ts b/apps/web/src/i18n/locales/zh-TW.ts
index d24f631eb..442af51e6 100644
--- a/apps/web/src/i18n/locales/zh-TW.ts
+++ b/apps/web/src/i18n/locales/zh-TW.ts
@@ -16,6 +16,9 @@ export const zhTW: Dict = {
'workingDirPicker.replace': "清空並替換目錄…",
'workingDirPicker.recent': "最近使用的目錄",
'handoff.toTarget': '交付給 {target}',
+ 'handoff.openInTarget': '在 {target} 中開啟',
+ 'handoff.openAction': '開啟',
+ 'handoff.menuTitle': '在哪個編輯器中開啟?',
'handoff.action': '交付',
'handoff.fallbackTitle': '未找到編輯器 - 使用 {target} 開啟',
'handoff.chooseTargetAria': '選擇交付目標',
@@ -974,6 +977,10 @@ export const zhTW: Dict = {
'chat.openFile': '開啟 {name}',
'chat.copyPrompt': '複製提示詞',
'chat.copyDone': '已複製!',
+ 'chat.inspect.noEditableTargets': '未找到可編輯的文字或樣式目標。',
+ 'chat.inspect.noCommentTargets': '未找到可評論的文字或視覺目標。',
+ 'chat.inspect.editHint': '在預覽中選擇文字或樣式目標進行編輯。',
+ 'chat.inspect.commentHint': '在預覽中選擇文字或區域進行評論。',
'chat.composerPlaceholder': "描述你想生成的內容…",
'chat.composerHint': "⌘/Ctrl + Enter 傳送 · 說清目標、內容、風格和格式",
'chat.cliSettingsTitle': 'CLI 與模型設定',
@@ -1172,7 +1179,7 @@ export const zhTW: Dict = {
'fileViewer.jsxModuleTitle': '無獨立預覽',
'fileViewer.jsxModuleBody': '此檔案是由其他頁面載入的元件模組。',
'fileViewer.jsxModuleCta': '請開啟轉譯它的頁面:',
- 'fileViewer.comment': '評論',
+ 'fileViewer.comment': '註釋',
'fileViewer.edit': '編輯',
'fileViewer.draw': '繪製',
'manualEdit.layers': "Layers",
diff --git a/apps/web/src/i18n/types.ts b/apps/web/src/i18n/types.ts
index 877b272df..c9ce3b2f5 100644
--- a/apps/web/src/i18n/types.ts
+++ b/apps/web/src/i18n/types.ts
@@ -793,6 +793,9 @@ export interface Dict {
'workingDirPicker.replace': string;
'workingDirPicker.recent': string;
'handoff.toTarget': string;
+ 'handoff.openInTarget': string;
+ 'handoff.openAction': string;
+ 'handoff.menuTitle': string;
'handoff.action': string;
'handoff.fallbackTitle': string;
'handoff.chooseTargetAria': string;
@@ -1662,6 +1665,10 @@ export interface Dict {
'chat.comments.pinAtCoords': string;
'chat.comments.capturedItems': string;
'chat.comments.clear': string;
+ 'chat.inspect.noEditableTargets': string;
+ 'chat.inspect.noCommentTargets': string;
+ 'chat.inspect.editHint': string;
+ 'chat.inspect.commentHint': string;
'chat.conversationsTitle': string;
'chat.conversationsAria': string;
'chat.newConversation': string;
diff --git a/apps/web/src/index.css b/apps/web/src/index.css
index 875e9638c..5e14150cd 100644
--- a/apps/web/src/index.css
+++ b/apps/web/src/index.css
@@ -1,4 +1,5 @@
@import url('https://fonts.googleapis.com/css2?family=Cairo:wght@400;500;600;700&display=swap');
+@import './styles/remixicon/remixicon.css';
@import './styles/design-system-flow.css';
@import './styles/tokens.css';
@import './styles/base.css';
diff --git a/apps/web/src/runtime/markdown.tsx b/apps/web/src/runtime/markdown.tsx
index 16f5e5dd3..e04956626 100644
--- a/apps/web/src/runtime/markdown.tsx
+++ b/apps/web/src/runtime/markdown.tsx
@@ -11,10 +11,9 @@
* Output is a React fragment of typed elements — no dangerouslySetInnerHTML,
* so untrusted text can't smuggle markup through.
*/
-import { Fragment, useEffect, useRef, useState, type ReactNode } from 'react';
+import { Fragment, useEffect, useRef, useState, type MouseEvent, type ReactNode } from 'react';
import { useT } from '../i18n';
import { copyToClipboard } from '../lib/copy-to-clipboard';
-import type { MouseEvent } from 'react';
export type MarkdownLinkClickHandler = (
href: string,
diff --git a/apps/web/src/styles/chat.css b/apps/web/src/styles/chat.css
index 89eab9f1c..517893d8d 100644
--- a/apps/web/src/styles/chat.css
+++ b/apps/web/src/styles/chat.css
@@ -529,6 +529,118 @@
margin: 0 8px;
}
+.chat-queued-send-strip {
+ display: flex;
+ flex-direction: column;
+ gap: 6px;
+ padding: 8px;
+ border: 1px solid var(--border);
+ border-radius: var(--radius);
+ background: var(--bg);
+ box-shadow: var(--shadow-xs);
+}
+
+.chat-queued-send-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ min-height: 20px;
+}
+
+.chat-queued-send-heading {
+ display: inline-flex;
+ align-items: center;
+ gap: 4px;
+ min-width: 0;
+ color: var(--text-muted);
+ font-size: 11.5px;
+ line-height: 1.2;
+ white-space: nowrap;
+}
+
+.chat-queued-send-heading strong {
+ color: var(--text);
+ font-weight: 650;
+}
+
+.chat-queued-send-row {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ min-width: 0;
+ padding: 6px 6px 6px 10px;
+ border: 1px solid transparent;
+ border-radius: var(--radius-sm);
+ background: transparent;
+}
+
+.chat-queued-send-row-active {
+ border-color: var(--border);
+ background: var(--bg-subtle);
+}
+
+.chat-queued-send-title {
+ min-width: 0;
+ flex: 1;
+ overflow: hidden;
+ color: var(--text);
+ font-size: 12.5px;
+ line-height: 1.35;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.chat-queued-send-actions {
+ display: inline-flex;
+ align-items: center;
+ gap: 3px;
+ flex: 0 0 auto;
+}
+
+.chat-queued-send-action {
+ width: 26px;
+ height: 26px;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ padding: 0;
+ border: 1px solid transparent;
+ border-radius: 6px;
+ background: transparent;
+ color: var(--text-muted);
+}
+
+.chat-queued-send-action:hover:not(:disabled) {
+ border-color: var(--border);
+ background: var(--bg-panel);
+ color: var(--text);
+}
+
+.chat-queued-send-action:disabled {
+ cursor: not-allowed;
+ opacity: 0.45;
+}
+
+.chat-queued-send-overflow {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ color: var(--text-faint);
+ font-size: 11.5px;
+ line-height: 1.2;
+}
+
+.chat-queued-send-overflow-line {
+ flex: 1;
+ height: 1px;
+ background: var(--border);
+}
+
+.chat-queued-send-extra {
+ color: var(--text-muted);
+ font-weight: 600;
+}
+
.preview-draw-note-input::placeholder {
color: rgba(255, 225, 210, 0.86);
}
diff --git a/apps/web/src/styles/remixicon/remixicon.css b/apps/web/src/styles/remixicon/remixicon.css
new file mode 100644
index 000000000..4c9025fff
--- /dev/null
+++ b/apps/web/src/styles/remixicon/remixicon.css
@@ -0,0 +1,3270 @@
+/*
+* Remix Icon v4.9.1
+* https://remixicon.com
+* https://github.com/Remix-Design/RemixIcon
+*
+* Copyright RemixIcon.com
+* Released under the Remix Icon License 1.0
+*
+* Date: 2026-01-29
+*/
+@font-face {
+ font-family: "remixicon";
+ src: url("./remixicon.woff2") format("woff2");
+ font-display: swap;
+}
+
+[class^="ri-"], [class*=" ri-"] {
+ font-family: 'remixicon' !important;
+ font-style: normal;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+.ri-lg { font-size: 1.3333em; line-height: 0.75em; vertical-align: -.0667em; }
+.ri-xl { font-size: 1.5em; line-height: 0.6666em; vertical-align: -.075em; }
+.ri-xxs { font-size: .5em; }
+.ri-xs { font-size: .75em; }
+.ri-sm { font-size: .875em }
+.ri-1x { font-size: 1em; }
+.ri-2x { font-size: 2em; }
+.ri-3x { font-size: 3em; }
+.ri-4x { font-size: 4em; }
+.ri-5x { font-size: 5em; }
+.ri-6x { font-size: 6em; }
+.ri-7x { font-size: 7em; }
+.ri-8x { font-size: 8em; }
+.ri-9x { font-size: 9em; }
+.ri-10x { font-size: 10em; }
+.ri-fw { text-align: center; width: 1.25em; }
+
+.ri-24-hours-fill:before { content: "\ea01"; }
+.ri-24-hours-line:before { content: "\ea02"; }
+.ri-4k-fill:before { content: "\ea03"; }
+.ri-4k-line:before { content: "\ea04"; }
+.ri-a-b:before { content: "\ea05"; }
+.ri-account-box-fill:before { content: "\ea06"; }
+.ri-account-box-line:before { content: "\ea07"; }
+.ri-account-circle-fill:before { content: "\ea08"; }
+.ri-account-circle-line:before { content: "\ea09"; }
+.ri-account-pin-box-fill:before { content: "\ea0a"; }
+.ri-account-pin-box-line:before { content: "\ea0b"; }
+.ri-account-pin-circle-fill:before { content: "\ea0c"; }
+.ri-account-pin-circle-line:before { content: "\ea0d"; }
+.ri-add-box-fill:before { content: "\ea0e"; }
+.ri-add-box-line:before { content: "\ea0f"; }
+.ri-add-circle-fill:before { content: "\ea10"; }
+.ri-add-circle-line:before { content: "\ea11"; }
+.ri-add-fill:before { content: "\ea12"; }
+.ri-add-line:before { content: "\ea13"; }
+.ri-admin-fill:before { content: "\ea14"; }
+.ri-admin-line:before { content: "\ea15"; }
+.ri-advertisement-fill:before { content: "\ea16"; }
+.ri-advertisement-line:before { content: "\ea17"; }
+.ri-airplay-fill:before { content: "\ea18"; }
+.ri-airplay-line:before { content: "\ea19"; }
+.ri-alarm-fill:before { content: "\ea1a"; }
+.ri-alarm-line:before { content: "\ea1b"; }
+.ri-alarm-warning-fill:before { content: "\ea1c"; }
+.ri-alarm-warning-line:before { content: "\ea1d"; }
+.ri-album-fill:before { content: "\ea1e"; }
+.ri-album-line:before { content: "\ea1f"; }
+.ri-alert-fill:before { content: "\ea20"; }
+.ri-alert-line:before { content: "\ea21"; }
+.ri-aliens-fill:before { content: "\ea22"; }
+.ri-aliens-line:before { content: "\ea23"; }
+.ri-align-bottom:before { content: "\ea24"; }
+.ri-align-center:before { content: "\ea25"; }
+.ri-align-justify:before { content: "\ea26"; }
+.ri-align-left:before { content: "\ea27"; }
+.ri-align-right:before { content: "\ea28"; }
+.ri-align-top:before { content: "\ea29"; }
+.ri-align-vertically:before { content: "\ea2a"; }
+.ri-alipay-fill:before { content: "\ea2b"; }
+.ri-alipay-line:before { content: "\ea2c"; }
+.ri-amazon-fill:before { content: "\ea2d"; }
+.ri-amazon-line:before { content: "\ea2e"; }
+.ri-anchor-fill:before { content: "\ea2f"; }
+.ri-anchor-line:before { content: "\ea30"; }
+.ri-ancient-gate-fill:before { content: "\ea31"; }
+.ri-ancient-gate-line:before { content: "\ea32"; }
+.ri-ancient-pavilion-fill:before { content: "\ea33"; }
+.ri-ancient-pavilion-line:before { content: "\ea34"; }
+.ri-android-fill:before { content: "\ea35"; }
+.ri-android-line:before { content: "\ea36"; }
+.ri-angularjs-fill:before { content: "\ea37"; }
+.ri-angularjs-line:before { content: "\ea38"; }
+.ri-anticlockwise-2-fill:before { content: "\ea39"; }
+.ri-anticlockwise-2-line:before { content: "\ea3a"; }
+.ri-anticlockwise-fill:before { content: "\ea3b"; }
+.ri-anticlockwise-line:before { content: "\ea3c"; }
+.ri-app-store-fill:before { content: "\ea3d"; }
+.ri-app-store-line:before { content: "\ea3e"; }
+.ri-apple-fill:before { content: "\ea3f"; }
+.ri-apple-line:before { content: "\ea40"; }
+.ri-apps-2-fill:before { content: "\ea41"; }
+.ri-apps-2-line:before { content: "\ea42"; }
+.ri-apps-fill:before { content: "\ea43"; }
+.ri-apps-line:before { content: "\ea44"; }
+.ri-archive-drawer-fill:before { content: "\ea45"; }
+.ri-archive-drawer-line:before { content: "\ea46"; }
+.ri-archive-fill:before { content: "\ea47"; }
+.ri-archive-line:before { content: "\ea48"; }
+.ri-arrow-down-circle-fill:before { content: "\ea49"; }
+.ri-arrow-down-circle-line:before { content: "\ea4a"; }
+.ri-arrow-down-fill:before { content: "\ea4b"; }
+.ri-arrow-down-line:before { content: "\ea4c"; }
+.ri-arrow-down-s-fill:before { content: "\ea4d"; }
+.ri-arrow-down-s-line:before { content: "\ea4e"; }
+.ri-arrow-drop-down-fill:before { content: "\ea4f"; }
+.ri-arrow-drop-down-line:before { content: "\ea50"; }
+.ri-arrow-drop-left-fill:before { content: "\ea51"; }
+.ri-arrow-drop-left-line:before { content: "\ea52"; }
+.ri-arrow-drop-right-fill:before { content: "\ea53"; }
+.ri-arrow-drop-right-line:before { content: "\ea54"; }
+.ri-arrow-drop-up-fill:before { content: "\ea55"; }
+.ri-arrow-drop-up-line:before { content: "\ea56"; }
+.ri-arrow-go-back-fill:before { content: "\ea57"; }
+.ri-arrow-go-back-line:before { content: "\ea58"; }
+.ri-arrow-go-forward-fill:before { content: "\ea59"; }
+.ri-arrow-go-forward-line:before { content: "\ea5a"; }
+.ri-arrow-left-circle-fill:before { content: "\ea5b"; }
+.ri-arrow-left-circle-line:before { content: "\ea5c"; }
+.ri-arrow-left-down-fill:before { content: "\ea5d"; }
+.ri-arrow-left-down-line:before { content: "\ea5e"; }
+.ri-arrow-left-fill:before { content: "\ea5f"; }
+.ri-arrow-left-line:before { content: "\ea60"; }
+.ri-arrow-left-right-fill:before { content: "\ea61"; }
+.ri-arrow-left-right-line:before { content: "\ea62"; }
+.ri-arrow-left-s-fill:before { content: "\ea63"; }
+.ri-arrow-left-s-line:before { content: "\ea64"; }
+.ri-arrow-left-up-fill:before { content: "\ea65"; }
+.ri-arrow-left-up-line:before { content: "\ea66"; }
+.ri-arrow-right-circle-fill:before { content: "\ea67"; }
+.ri-arrow-right-circle-line:before { content: "\ea68"; }
+.ri-arrow-right-down-fill:before { content: "\ea69"; }
+.ri-arrow-right-down-line:before { content: "\ea6a"; }
+.ri-arrow-right-fill:before { content: "\ea6b"; }
+.ri-arrow-right-line:before { content: "\ea6c"; }
+.ri-arrow-right-s-fill:before { content: "\ea6d"; }
+.ri-arrow-right-s-line:before { content: "\ea6e"; }
+.ri-arrow-right-up-fill:before { content: "\ea6f"; }
+.ri-arrow-right-up-line:before { content: "\ea70"; }
+.ri-arrow-up-circle-fill:before { content: "\ea71"; }
+.ri-arrow-up-circle-line:before { content: "\ea72"; }
+.ri-arrow-up-down-fill:before { content: "\ea73"; }
+.ri-arrow-up-down-line:before { content: "\ea74"; }
+.ri-arrow-up-fill:before { content: "\ea75"; }
+.ri-arrow-up-line:before { content: "\ea76"; }
+.ri-arrow-up-s-fill:before { content: "\ea77"; }
+.ri-arrow-up-s-line:before { content: "\ea78"; }
+.ri-artboard-2-fill:before { content: "\ea79"; }
+.ri-artboard-2-line:before { content: "\ea7a"; }
+.ri-artboard-fill:before { content: "\ea7b"; }
+.ri-artboard-line:before { content: "\ea7c"; }
+.ri-article-fill:before { content: "\ea7d"; }
+.ri-article-line:before { content: "\ea7e"; }
+.ri-aspect-ratio-fill:before { content: "\ea7f"; }
+.ri-aspect-ratio-line:before { content: "\ea80"; }
+.ri-asterisk:before { content: "\ea81"; }
+.ri-at-fill:before { content: "\ea82"; }
+.ri-at-line:before { content: "\ea83"; }
+.ri-attachment-2:before { content: "\ea84"; }
+.ri-attachment-fill:before { content: "\ea85"; }
+.ri-attachment-line:before { content: "\ea86"; }
+.ri-auction-fill:before { content: "\ea87"; }
+.ri-auction-line:before { content: "\ea88"; }
+.ri-award-fill:before { content: "\ea89"; }
+.ri-award-line:before { content: "\ea8a"; }
+.ri-baidu-fill:before { content: "\ea8b"; }
+.ri-baidu-line:before { content: "\ea8c"; }
+.ri-ball-pen-fill:before { content: "\ea8d"; }
+.ri-ball-pen-line:before { content: "\ea8e"; }
+.ri-bank-card-2-fill:before { content: "\ea8f"; }
+.ri-bank-card-2-line:before { content: "\ea90"; }
+.ri-bank-card-fill:before { content: "\ea91"; }
+.ri-bank-card-line:before { content: "\ea92"; }
+.ri-bank-fill:before { content: "\ea93"; }
+.ri-bank-line:before { content: "\ea94"; }
+.ri-bar-chart-2-fill:before { content: "\ea95"; }
+.ri-bar-chart-2-line:before { content: "\ea96"; }
+.ri-bar-chart-box-fill:before { content: "\ea97"; }
+.ri-bar-chart-box-line:before { content: "\ea98"; }
+.ri-bar-chart-fill:before { content: "\ea99"; }
+.ri-bar-chart-grouped-fill:before { content: "\ea9a"; }
+.ri-bar-chart-grouped-line:before { content: "\ea9b"; }
+.ri-bar-chart-horizontal-fill:before { content: "\ea9c"; }
+.ri-bar-chart-horizontal-line:before { content: "\ea9d"; }
+.ri-bar-chart-line:before { content: "\ea9e"; }
+.ri-barcode-box-fill:before { content: "\ea9f"; }
+.ri-barcode-box-line:before { content: "\eaa0"; }
+.ri-barcode-fill:before { content: "\eaa1"; }
+.ri-barcode-line:before { content: "\eaa2"; }
+.ri-barricade-fill:before { content: "\eaa3"; }
+.ri-barricade-line:before { content: "\eaa4"; }
+.ri-base-station-fill:before { content: "\eaa5"; }
+.ri-base-station-line:before { content: "\eaa6"; }
+.ri-basketball-fill:before { content: "\eaa7"; }
+.ri-basketball-line:before { content: "\eaa8"; }
+.ri-battery-2-charge-fill:before { content: "\eaa9"; }
+.ri-battery-2-charge-line:before { content: "\eaaa"; }
+.ri-battery-2-fill:before { content: "\eaab"; }
+.ri-battery-2-line:before { content: "\eaac"; }
+.ri-battery-charge-fill:before { content: "\eaad"; }
+.ri-battery-charge-line:before { content: "\eaae"; }
+.ri-battery-fill:before { content: "\eaaf"; }
+.ri-battery-line:before { content: "\eab0"; }
+.ri-battery-low-fill:before { content: "\eab1"; }
+.ri-battery-low-line:before { content: "\eab2"; }
+.ri-battery-saver-fill:before { content: "\eab3"; }
+.ri-battery-saver-line:before { content: "\eab4"; }
+.ri-battery-share-fill:before { content: "\eab5"; }
+.ri-battery-share-line:before { content: "\eab6"; }
+.ri-bear-smile-fill:before { content: "\eab7"; }
+.ri-bear-smile-line:before { content: "\eab8"; }
+.ri-behance-fill:before { content: "\eab9"; }
+.ri-behance-line:before { content: "\eaba"; }
+.ri-bell-fill:before { content: "\eabb"; }
+.ri-bell-line:before { content: "\eabc"; }
+.ri-bike-fill:before { content: "\eabd"; }
+.ri-bike-line:before { content: "\eabe"; }
+.ri-bilibili-fill:before { content: "\eabf"; }
+.ri-bilibili-line:before { content: "\eac0"; }
+.ri-bill-fill:before { content: "\eac1"; }
+.ri-bill-line:before { content: "\eac2"; }
+.ri-billiards-fill:before { content: "\eac3"; }
+.ri-billiards-line:before { content: "\eac4"; }
+.ri-bit-coin-fill:before { content: "\eac5"; }
+.ri-bit-coin-line:before { content: "\eac6"; }
+.ri-blaze-fill:before { content: "\eac7"; }
+.ri-blaze-line:before { content: "\eac8"; }
+.ri-bluetooth-connect-fill:before { content: "\eac9"; }
+.ri-bluetooth-connect-line:before { content: "\eaca"; }
+.ri-bluetooth-fill:before { content: "\eacb"; }
+.ri-bluetooth-line:before { content: "\eacc"; }
+.ri-blur-off-fill:before { content: "\eacd"; }
+.ri-blur-off-line:before { content: "\eace"; }
+.ri-body-scan-fill:before { content: "\eacf"; }
+.ri-body-scan-line:before { content: "\ead0"; }
+.ri-bold:before { content: "\ead1"; }
+.ri-book-2-fill:before { content: "\ead2"; }
+.ri-book-2-line:before { content: "\ead3"; }
+.ri-book-3-fill:before { content: "\ead4"; }
+.ri-book-3-line:before { content: "\ead5"; }
+.ri-book-fill:before { content: "\ead6"; }
+.ri-book-line:before { content: "\ead7"; }
+.ri-book-marked-fill:before { content: "\ead8"; }
+.ri-book-marked-line:before { content: "\ead9"; }
+.ri-book-open-fill:before { content: "\eada"; }
+.ri-book-open-line:before { content: "\eadb"; }
+.ri-book-read-fill:before { content: "\eadc"; }
+.ri-book-read-line:before { content: "\eadd"; }
+.ri-booklet-fill:before { content: "\eade"; }
+.ri-booklet-line:before { content: "\eadf"; }
+.ri-bookmark-2-fill:before { content: "\eae0"; }
+.ri-bookmark-2-line:before { content: "\eae1"; }
+.ri-bookmark-3-fill:before { content: "\eae2"; }
+.ri-bookmark-3-line:before { content: "\eae3"; }
+.ri-bookmark-fill:before { content: "\eae4"; }
+.ri-bookmark-line:before { content: "\eae5"; }
+.ri-boxing-fill:before { content: "\eae6"; }
+.ri-boxing-line:before { content: "\eae7"; }
+.ri-braces-fill:before { content: "\eae8"; }
+.ri-braces-line:before { content: "\eae9"; }
+.ri-brackets-fill:before { content: "\eaea"; }
+.ri-brackets-line:before { content: "\eaeb"; }
+.ri-briefcase-2-fill:before { content: "\eaec"; }
+.ri-briefcase-2-line:before { content: "\eaed"; }
+.ri-briefcase-3-fill:before { content: "\eaee"; }
+.ri-briefcase-3-line:before { content: "\eaef"; }
+.ri-briefcase-4-fill:before { content: "\eaf0"; }
+.ri-briefcase-4-line:before { content: "\eaf1"; }
+.ri-briefcase-5-fill:before { content: "\eaf2"; }
+.ri-briefcase-5-line:before { content: "\eaf3"; }
+.ri-briefcase-fill:before { content: "\eaf4"; }
+.ri-briefcase-line:before { content: "\eaf5"; }
+.ri-bring-forward:before { content: "\eaf6"; }
+.ri-bring-to-front:before { content: "\eaf7"; }
+.ri-broadcast-fill:before { content: "\eaf8"; }
+.ri-broadcast-line:before { content: "\eaf9"; }
+.ri-brush-2-fill:before { content: "\eafa"; }
+.ri-brush-2-line:before { content: "\eafb"; }
+.ri-brush-3-fill:before { content: "\eafc"; }
+.ri-brush-3-line:before { content: "\eafd"; }
+.ri-brush-4-fill:before { content: "\eafe"; }
+.ri-brush-4-line:before { content: "\eaff"; }
+.ri-brush-fill:before { content: "\eb00"; }
+.ri-brush-line:before { content: "\eb01"; }
+.ri-bubble-chart-fill:before { content: "\eb02"; }
+.ri-bubble-chart-line:before { content: "\eb03"; }
+.ri-bug-2-fill:before { content: "\eb04"; }
+.ri-bug-2-line:before { content: "\eb05"; }
+.ri-bug-fill:before { content: "\eb06"; }
+.ri-bug-line:before { content: "\eb07"; }
+.ri-building-2-fill:before { content: "\eb08"; }
+.ri-building-2-line:before { content: "\eb09"; }
+.ri-building-3-fill:before { content: "\eb0a"; }
+.ri-building-3-line:before { content: "\eb0b"; }
+.ri-building-4-fill:before { content: "\eb0c"; }
+.ri-building-4-line:before { content: "\eb0d"; }
+.ri-building-fill:before { content: "\eb0e"; }
+.ri-building-line:before { content: "\eb0f"; }
+.ri-bus-2-fill:before { content: "\eb10"; }
+.ri-bus-2-line:before { content: "\eb11"; }
+.ri-bus-fill:before { content: "\eb12"; }
+.ri-bus-line:before { content: "\eb13"; }
+.ri-bus-wifi-fill:before { content: "\eb14"; }
+.ri-bus-wifi-line:before { content: "\eb15"; }
+.ri-cactus-fill:before { content: "\eb16"; }
+.ri-cactus-line:before { content: "\eb17"; }
+.ri-cake-2-fill:before { content: "\eb18"; }
+.ri-cake-2-line:before { content: "\eb19"; }
+.ri-cake-3-fill:before { content: "\eb1a"; }
+.ri-cake-3-line:before { content: "\eb1b"; }
+.ri-cake-fill:before { content: "\eb1c"; }
+.ri-cake-line:before { content: "\eb1d"; }
+.ri-calculator-fill:before { content: "\eb1e"; }
+.ri-calculator-line:before { content: "\eb1f"; }
+.ri-calendar-2-fill:before { content: "\eb20"; }
+.ri-calendar-2-line:before { content: "\eb21"; }
+.ri-calendar-check-fill:before { content: "\eb22"; }
+.ri-calendar-check-line:before { content: "\eb23"; }
+.ri-calendar-event-fill:before { content: "\eb24"; }
+.ri-calendar-event-line:before { content: "\eb25"; }
+.ri-calendar-fill:before { content: "\eb26"; }
+.ri-calendar-line:before { content: "\eb27"; }
+.ri-calendar-todo-fill:before { content: "\eb28"; }
+.ri-calendar-todo-line:before { content: "\eb29"; }
+.ri-camera-2-fill:before { content: "\eb2a"; }
+.ri-camera-2-line:before { content: "\eb2b"; }
+.ri-camera-3-fill:before { content: "\eb2c"; }
+.ri-camera-3-line:before { content: "\eb2d"; }
+.ri-camera-fill:before { content: "\eb2e"; }
+.ri-camera-lens-fill:before { content: "\eb2f"; }
+.ri-camera-lens-line:before { content: "\eb30"; }
+.ri-camera-line:before { content: "\eb31"; }
+.ri-camera-off-fill:before { content: "\eb32"; }
+.ri-camera-off-line:before { content: "\eb33"; }
+.ri-camera-switch-fill:before { content: "\eb34"; }
+.ri-camera-switch-line:before { content: "\eb35"; }
+.ri-capsule-fill:before { content: "\eb36"; }
+.ri-capsule-line:before { content: "\eb37"; }
+.ri-car-fill:before { content: "\eb38"; }
+.ri-car-line:before { content: "\eb39"; }
+.ri-car-washing-fill:before { content: "\eb3a"; }
+.ri-car-washing-line:before { content: "\eb3b"; }
+.ri-caravan-fill:before { content: "\eb3c"; }
+.ri-caravan-line:before { content: "\eb3d"; }
+.ri-cast-fill:before { content: "\eb3e"; }
+.ri-cast-line:before { content: "\eb3f"; }
+.ri-cellphone-fill:before { content: "\eb40"; }
+.ri-cellphone-line:before { content: "\eb41"; }
+.ri-celsius-fill:before { content: "\eb42"; }
+.ri-celsius-line:before { content: "\eb43"; }
+.ri-centos-fill:before { content: "\eb44"; }
+.ri-centos-line:before { content: "\eb45"; }
+.ri-character-recognition-fill:before { content: "\eb46"; }
+.ri-character-recognition-line:before { content: "\eb47"; }
+.ri-charging-pile-2-fill:before { content: "\eb48"; }
+.ri-charging-pile-2-line:before { content: "\eb49"; }
+.ri-charging-pile-fill:before { content: "\eb4a"; }
+.ri-charging-pile-line:before { content: "\eb4b"; }
+.ri-chat-1-fill:before { content: "\eb4c"; }
+.ri-chat-1-line:before { content: "\eb4d"; }
+.ri-chat-2-fill:before { content: "\eb4e"; }
+.ri-chat-2-line:before { content: "\eb4f"; }
+.ri-chat-3-fill:before { content: "\eb50"; }
+.ri-chat-3-line:before { content: "\eb51"; }
+.ri-chat-4-fill:before { content: "\eb52"; }
+.ri-chat-4-line:before { content: "\eb53"; }
+.ri-chat-check-fill:before { content: "\eb54"; }
+.ri-chat-check-line:before { content: "\eb55"; }
+.ri-chat-delete-fill:before { content: "\eb56"; }
+.ri-chat-delete-line:before { content: "\eb57"; }
+.ri-chat-download-fill:before { content: "\eb58"; }
+.ri-chat-download-line:before { content: "\eb59"; }
+.ri-chat-follow-up-fill:before { content: "\eb5a"; }
+.ri-chat-follow-up-line:before { content: "\eb5b"; }
+.ri-chat-forward-fill:before { content: "\eb5c"; }
+.ri-chat-forward-line:before { content: "\eb5d"; }
+.ri-chat-heart-fill:before { content: "\eb5e"; }
+.ri-chat-heart-line:before { content: "\eb5f"; }
+.ri-chat-history-fill:before { content: "\eb60"; }
+.ri-chat-history-line:before { content: "\eb61"; }
+.ri-chat-new-fill:before { content: "\eb62"; }
+.ri-chat-new-line:before { content: "\eb63"; }
+.ri-chat-off-fill:before { content: "\eb64"; }
+.ri-chat-off-line:before { content: "\eb65"; }
+.ri-chat-poll-fill:before { content: "\eb66"; }
+.ri-chat-poll-line:before { content: "\eb67"; }
+.ri-chat-private-fill:before { content: "\eb68"; }
+.ri-chat-private-line:before { content: "\eb69"; }
+.ri-chat-quote-fill:before { content: "\eb6a"; }
+.ri-chat-quote-line:before { content: "\eb6b"; }
+.ri-chat-settings-fill:before { content: "\eb6c"; }
+.ri-chat-settings-line:before { content: "\eb6d"; }
+.ri-chat-smile-2-fill:before { content: "\eb6e"; }
+.ri-chat-smile-2-line:before { content: "\eb6f"; }
+.ri-chat-smile-3-fill:before { content: "\eb70"; }
+.ri-chat-smile-3-line:before { content: "\eb71"; }
+.ri-chat-smile-fill:before { content: "\eb72"; }
+.ri-chat-smile-line:before { content: "\eb73"; }
+.ri-chat-upload-fill:before { content: "\eb74"; }
+.ri-chat-upload-line:before { content: "\eb75"; }
+.ri-chat-voice-fill:before { content: "\eb76"; }
+.ri-chat-voice-line:before { content: "\eb77"; }
+.ri-check-double-fill:before { content: "\eb78"; }
+.ri-check-double-line:before { content: "\eb79"; }
+.ri-check-fill:before { content: "\eb7a"; }
+.ri-check-line:before { content: "\eb7b"; }
+.ri-checkbox-blank-circle-fill:before { content: "\eb7c"; }
+.ri-checkbox-blank-circle-line:before { content: "\eb7d"; }
+.ri-checkbox-blank-fill:before { content: "\eb7e"; }
+.ri-checkbox-blank-line:before { content: "\eb7f"; }
+.ri-checkbox-circle-fill:before { content: "\eb80"; }
+.ri-checkbox-circle-line:before { content: "\eb81"; }
+.ri-checkbox-fill:before { content: "\eb82"; }
+.ri-checkbox-indeterminate-fill:before { content: "\eb83"; }
+.ri-checkbox-indeterminate-line:before { content: "\eb84"; }
+.ri-checkbox-line:before { content: "\eb85"; }
+.ri-checkbox-multiple-blank-fill:before { content: "\eb86"; }
+.ri-checkbox-multiple-blank-line:before { content: "\eb87"; }
+.ri-checkbox-multiple-fill:before { content: "\eb88"; }
+.ri-checkbox-multiple-line:before { content: "\eb89"; }
+.ri-china-railway-fill:before { content: "\eb8a"; }
+.ri-china-railway-line:before { content: "\eb8b"; }
+.ri-chrome-fill:before { content: "\eb8c"; }
+.ri-chrome-line:before { content: "\eb8d"; }
+.ri-clapperboard-fill:before { content: "\eb8e"; }
+.ri-clapperboard-line:before { content: "\eb8f"; }
+.ri-clipboard-fill:before { content: "\eb90"; }
+.ri-clipboard-line:before { content: "\eb91"; }
+.ri-clockwise-2-fill:before { content: "\eb92"; }
+.ri-clockwise-2-line:before { content: "\eb93"; }
+.ri-clockwise-fill:before { content: "\eb94"; }
+.ri-clockwise-line:before { content: "\eb95"; }
+.ri-close-circle-fill:before { content: "\eb96"; }
+.ri-close-circle-line:before { content: "\eb97"; }
+.ri-close-fill:before { content: "\eb98"; }
+.ri-close-line:before { content: "\eb99"; }
+.ri-closed-captioning-fill:before { content: "\eb9a"; }
+.ri-closed-captioning-line:before { content: "\eb9b"; }
+.ri-cloud-fill:before { content: "\eb9c"; }
+.ri-cloud-line:before { content: "\eb9d"; }
+.ri-cloud-off-fill:before { content: "\eb9e"; }
+.ri-cloud-off-line:before { content: "\eb9f"; }
+.ri-cloud-windy-fill:before { content: "\eba0"; }
+.ri-cloud-windy-line:before { content: "\eba1"; }
+.ri-cloudy-2-fill:before { content: "\eba2"; }
+.ri-cloudy-2-line:before { content: "\eba3"; }
+.ri-cloudy-fill:before { content: "\eba4"; }
+.ri-cloudy-line:before { content: "\eba5"; }
+.ri-code-box-fill:before { content: "\eba6"; }
+.ri-code-box-line:before { content: "\eba7"; }
+.ri-code-fill:before { content: "\eba8"; }
+.ri-code-line:before { content: "\eba9"; }
+.ri-code-s-fill:before { content: "\ebaa"; }
+.ri-code-s-line:before { content: "\ebab"; }
+.ri-code-s-slash-fill:before { content: "\ebac"; }
+.ri-code-s-slash-line:before { content: "\ebad"; }
+.ri-code-view:before { content: "\ebae"; }
+.ri-codepen-fill:before { content: "\ebaf"; }
+.ri-codepen-line:before { content: "\ebb0"; }
+.ri-coin-fill:before { content: "\ebb1"; }
+.ri-coin-line:before { content: "\ebb2"; }
+.ri-coins-fill:before { content: "\ebb3"; }
+.ri-coins-line:before { content: "\ebb4"; }
+.ri-collage-fill:before { content: "\ebb5"; }
+.ri-collage-line:before { content: "\ebb6"; }
+.ri-command-fill:before { content: "\ebb7"; }
+.ri-command-line:before { content: "\ebb8"; }
+.ri-community-fill:before { content: "\ebb9"; }
+.ri-community-line:before { content: "\ebba"; }
+.ri-compass-2-fill:before { content: "\ebbb"; }
+.ri-compass-2-line:before { content: "\ebbc"; }
+.ri-compass-3-fill:before { content: "\ebbd"; }
+.ri-compass-3-line:before { content: "\ebbe"; }
+.ri-compass-4-fill:before { content: "\ebbf"; }
+.ri-compass-4-line:before { content: "\ebc0"; }
+.ri-compass-discover-fill:before { content: "\ebc1"; }
+.ri-compass-discover-line:before { content: "\ebc2"; }
+.ri-compass-fill:before { content: "\ebc3"; }
+.ri-compass-line:before { content: "\ebc4"; }
+.ri-compasses-2-fill:before { content: "\ebc5"; }
+.ri-compasses-2-line:before { content: "\ebc6"; }
+.ri-compasses-fill:before { content: "\ebc7"; }
+.ri-compasses-line:before { content: "\ebc8"; }
+.ri-computer-fill:before { content: "\ebc9"; }
+.ri-computer-line:before { content: "\ebca"; }
+.ri-contacts-book-2-fill:before { content: "\ebcb"; }
+.ri-contacts-book-2-line:before { content: "\ebcc"; }
+.ri-contacts-book-fill:before { content: "\ebcd"; }
+.ri-contacts-book-line:before { content: "\ebce"; }
+.ri-contacts-book-upload-fill:before { content: "\ebcf"; }
+.ri-contacts-book-upload-line:before { content: "\ebd0"; }
+.ri-contacts-fill:before { content: "\ebd1"; }
+.ri-contacts-line:before { content: "\ebd2"; }
+.ri-contrast-2-fill:before { content: "\ebd3"; }
+.ri-contrast-2-line:before { content: "\ebd4"; }
+.ri-contrast-drop-2-fill:before { content: "\ebd5"; }
+.ri-contrast-drop-2-line:before { content: "\ebd6"; }
+.ri-contrast-drop-fill:before { content: "\ebd7"; }
+.ri-contrast-drop-line:before { content: "\ebd8"; }
+.ri-contrast-fill:before { content: "\ebd9"; }
+.ri-contrast-line:before { content: "\ebda"; }
+.ri-copper-coin-fill:before { content: "\ebdb"; }
+.ri-copper-coin-line:before { content: "\ebdc"; }
+.ri-copper-diamond-fill:before { content: "\ebdd"; }
+.ri-copper-diamond-line:before { content: "\ebde"; }
+.ri-copyleft-fill:before { content: "\ebdf"; }
+.ri-copyleft-line:before { content: "\ebe0"; }
+.ri-copyright-fill:before { content: "\ebe1"; }
+.ri-copyright-line:before { content: "\ebe2"; }
+.ri-coreos-fill:before { content: "\ebe3"; }
+.ri-coreos-line:before { content: "\ebe4"; }
+.ri-coupon-2-fill:before { content: "\ebe5"; }
+.ri-coupon-2-line:before { content: "\ebe6"; }
+.ri-coupon-3-fill:before { content: "\ebe7"; }
+.ri-coupon-3-line:before { content: "\ebe8"; }
+.ri-coupon-4-fill:before { content: "\ebe9"; }
+.ri-coupon-4-line:before { content: "\ebea"; }
+.ri-coupon-5-fill:before { content: "\ebeb"; }
+.ri-coupon-5-line:before { content: "\ebec"; }
+.ri-coupon-fill:before { content: "\ebed"; }
+.ri-coupon-line:before { content: "\ebee"; }
+.ri-cpu-fill:before { content: "\ebef"; }
+.ri-cpu-line:before { content: "\ebf0"; }
+.ri-creative-commons-by-fill:before { content: "\ebf1"; }
+.ri-creative-commons-by-line:before { content: "\ebf2"; }
+.ri-creative-commons-fill:before { content: "\ebf3"; }
+.ri-creative-commons-line:before { content: "\ebf4"; }
+.ri-creative-commons-nc-fill:before { content: "\ebf5"; }
+.ri-creative-commons-nc-line:before { content: "\ebf6"; }
+.ri-creative-commons-nd-fill:before { content: "\ebf7"; }
+.ri-creative-commons-nd-line:before { content: "\ebf8"; }
+.ri-creative-commons-sa-fill:before { content: "\ebf9"; }
+.ri-creative-commons-sa-line:before { content: "\ebfa"; }
+.ri-creative-commons-zero-fill:before { content: "\ebfb"; }
+.ri-creative-commons-zero-line:before { content: "\ebfc"; }
+.ri-criminal-fill:before { content: "\ebfd"; }
+.ri-criminal-line:before { content: "\ebfe"; }
+.ri-crop-2-fill:before { content: "\ebff"; }
+.ri-crop-2-line:before { content: "\ec00"; }
+.ri-crop-fill:before { content: "\ec01"; }
+.ri-crop-line:before { content: "\ec02"; }
+.ri-css3-fill:before { content: "\ec03"; }
+.ri-css3-line:before { content: "\ec04"; }
+.ri-cup-fill:before { content: "\ec05"; }
+.ri-cup-line:before { content: "\ec06"; }
+.ri-currency-fill:before { content: "\ec07"; }
+.ri-currency-line:before { content: "\ec08"; }
+.ri-cursor-fill:before { content: "\ec09"; }
+.ri-cursor-line:before { content: "\ec0a"; }
+.ri-customer-service-2-fill:before { content: "\ec0b"; }
+.ri-customer-service-2-line:before { content: "\ec0c"; }
+.ri-customer-service-fill:before { content: "\ec0d"; }
+.ri-customer-service-line:before { content: "\ec0e"; }
+.ri-dashboard-2-fill:before { content: "\ec0f"; }
+.ri-dashboard-2-line:before { content: "\ec10"; }
+.ri-dashboard-3-fill:before { content: "\ec11"; }
+.ri-dashboard-3-line:before { content: "\ec12"; }
+.ri-dashboard-fill:before { content: "\ec13"; }
+.ri-dashboard-line:before { content: "\ec14"; }
+.ri-database-2-fill:before { content: "\ec15"; }
+.ri-database-2-line:before { content: "\ec16"; }
+.ri-database-fill:before { content: "\ec17"; }
+.ri-database-line:before { content: "\ec18"; }
+.ri-delete-back-2-fill:before { content: "\ec19"; }
+.ri-delete-back-2-line:before { content: "\ec1a"; }
+.ri-delete-back-fill:before { content: "\ec1b"; }
+.ri-delete-back-line:before { content: "\ec1c"; }
+.ri-delete-bin-2-fill:before { content: "\ec1d"; }
+.ri-delete-bin-2-line:before { content: "\ec1e"; }
+.ri-delete-bin-3-fill:before { content: "\ec1f"; }
+.ri-delete-bin-3-line:before { content: "\ec20"; }
+.ri-delete-bin-4-fill:before { content: "\ec21"; }
+.ri-delete-bin-4-line:before { content: "\ec22"; }
+.ri-delete-bin-5-fill:before { content: "\ec23"; }
+.ri-delete-bin-5-line:before { content: "\ec24"; }
+.ri-delete-bin-6-fill:before { content: "\ec25"; }
+.ri-delete-bin-6-line:before { content: "\ec26"; }
+.ri-delete-bin-7-fill:before { content: "\ec27"; }
+.ri-delete-bin-7-line:before { content: "\ec28"; }
+.ri-delete-bin-fill:before { content: "\ec29"; }
+.ri-delete-bin-line:before { content: "\ec2a"; }
+.ri-delete-column:before { content: "\ec2b"; }
+.ri-delete-row:before { content: "\ec2c"; }
+.ri-device-fill:before { content: "\ec2d"; }
+.ri-device-line:before { content: "\ec2e"; }
+.ri-device-recover-fill:before { content: "\ec2f"; }
+.ri-device-recover-line:before { content: "\ec30"; }
+.ri-dingding-fill:before { content: "\ec31"; }
+.ri-dingding-line:before { content: "\ec32"; }
+.ri-direction-fill:before { content: "\ec33"; }
+.ri-direction-line:before { content: "\ec34"; }
+.ri-disc-fill:before { content: "\ec35"; }
+.ri-disc-line:before { content: "\ec36"; }
+.ri-discord-fill:before { content: "\ec37"; }
+.ri-discord-line:before { content: "\ec38"; }
+.ri-discuss-fill:before { content: "\ec39"; }
+.ri-discuss-line:before { content: "\ec3a"; }
+.ri-dislike-fill:before { content: "\ec3b"; }
+.ri-dislike-line:before { content: "\ec3c"; }
+.ri-disqus-fill:before { content: "\ec3d"; }
+.ri-disqus-line:before { content: "\ec3e"; }
+.ri-divide-fill:before { content: "\ec3f"; }
+.ri-divide-line:before { content: "\ec40"; }
+.ri-donut-chart-fill:before { content: "\ec41"; }
+.ri-donut-chart-line:before { content: "\ec42"; }
+.ri-door-closed-fill:before { content: "\ec43"; }
+.ri-door-closed-line:before { content: "\ec44"; }
+.ri-door-fill:before { content: "\ec45"; }
+.ri-door-line:before { content: "\ec46"; }
+.ri-door-lock-box-fill:before { content: "\ec47"; }
+.ri-door-lock-box-line:before { content: "\ec48"; }
+.ri-door-lock-fill:before { content: "\ec49"; }
+.ri-door-lock-line:before { content: "\ec4a"; }
+.ri-door-open-fill:before { content: "\ec4b"; }
+.ri-door-open-line:before { content: "\ec4c"; }
+.ri-dossier-fill:before { content: "\ec4d"; }
+.ri-dossier-line:before { content: "\ec4e"; }
+.ri-douban-fill:before { content: "\ec4f"; }
+.ri-douban-line:before { content: "\ec50"; }
+.ri-double-quotes-l:before { content: "\ec51"; }
+.ri-double-quotes-r:before { content: "\ec52"; }
+.ri-download-2-fill:before { content: "\ec53"; }
+.ri-download-2-line:before { content: "\ec54"; }
+.ri-download-cloud-2-fill:before { content: "\ec55"; }
+.ri-download-cloud-2-line:before { content: "\ec56"; }
+.ri-download-cloud-fill:before { content: "\ec57"; }
+.ri-download-cloud-line:before { content: "\ec58"; }
+.ri-download-fill:before { content: "\ec59"; }
+.ri-download-line:before { content: "\ec5a"; }
+.ri-draft-fill:before { content: "\ec5b"; }
+.ri-draft-line:before { content: "\ec5c"; }
+.ri-drag-drop-fill:before { content: "\ec5d"; }
+.ri-drag-drop-line:before { content: "\ec5e"; }
+.ri-drag-move-2-fill:before { content: "\ec5f"; }
+.ri-drag-move-2-line:before { content: "\ec60"; }
+.ri-drag-move-fill:before { content: "\ec61"; }
+.ri-drag-move-line:before { content: "\ec62"; }
+.ri-dribbble-fill:before { content: "\ec63"; }
+.ri-dribbble-line:before { content: "\ec64"; }
+.ri-drive-fill:before { content: "\ec65"; }
+.ri-drive-line:before { content: "\ec66"; }
+.ri-drizzle-fill:before { content: "\ec67"; }
+.ri-drizzle-line:before { content: "\ec68"; }
+.ri-drop-fill:before { content: "\ec69"; }
+.ri-drop-line:before { content: "\ec6a"; }
+.ri-dropbox-fill:before { content: "\ec6b"; }
+.ri-dropbox-line:before { content: "\ec6c"; }
+.ri-dual-sim-1-fill:before { content: "\ec6d"; }
+.ri-dual-sim-1-line:before { content: "\ec6e"; }
+.ri-dual-sim-2-fill:before { content: "\ec6f"; }
+.ri-dual-sim-2-line:before { content: "\ec70"; }
+.ri-dv-fill:before { content: "\ec71"; }
+.ri-dv-line:before { content: "\ec72"; }
+.ri-dvd-fill:before { content: "\ec73"; }
+.ri-dvd-line:before { content: "\ec74"; }
+.ri-e-bike-2-fill:before { content: "\ec75"; }
+.ri-e-bike-2-line:before { content: "\ec76"; }
+.ri-e-bike-fill:before { content: "\ec77"; }
+.ri-e-bike-line:before { content: "\ec78"; }
+.ri-earth-fill:before { content: "\ec79"; }
+.ri-earth-line:before { content: "\ec7a"; }
+.ri-earthquake-fill:before { content: "\ec7b"; }
+.ri-earthquake-line:before { content: "\ec7c"; }
+.ri-edge-fill:before { content: "\ec7d"; }
+.ri-edge-line:before { content: "\ec7e"; }
+.ri-edit-2-fill:before { content: "\ec7f"; }
+.ri-edit-2-line:before { content: "\ec80"; }
+.ri-edit-box-fill:before { content: "\ec81"; }
+.ri-edit-box-line:before { content: "\ec82"; }
+.ri-edit-circle-fill:before { content: "\ec83"; }
+.ri-edit-circle-line:before { content: "\ec84"; }
+.ri-edit-fill:before { content: "\ec85"; }
+.ri-edit-line:before { content: "\ec86"; }
+.ri-eject-fill:before { content: "\ec87"; }
+.ri-eject-line:before { content: "\ec88"; }
+.ri-emotion-2-fill:before { content: "\ec89"; }
+.ri-emotion-2-line:before { content: "\ec8a"; }
+.ri-emotion-fill:before { content: "\ec8b"; }
+.ri-emotion-happy-fill:before { content: "\ec8c"; }
+.ri-emotion-happy-line:before { content: "\ec8d"; }
+.ri-emotion-laugh-fill:before { content: "\ec8e"; }
+.ri-emotion-laugh-line:before { content: "\ec8f"; }
+.ri-emotion-line:before { content: "\ec90"; }
+.ri-emotion-normal-fill:before { content: "\ec91"; }
+.ri-emotion-normal-line:before { content: "\ec92"; }
+.ri-emotion-sad-fill:before { content: "\ec93"; }
+.ri-emotion-sad-line:before { content: "\ec94"; }
+.ri-emotion-unhappy-fill:before { content: "\ec95"; }
+.ri-emotion-unhappy-line:before { content: "\ec96"; }
+.ri-empathize-fill:before { content: "\ec97"; }
+.ri-empathize-line:before { content: "\ec98"; }
+.ri-emphasis-cn:before { content: "\ec99"; }
+.ri-emphasis:before { content: "\ec9a"; }
+.ri-english-input:before { content: "\ec9b"; }
+.ri-equalizer-fill:before { content: "\ec9c"; }
+.ri-equalizer-line:before { content: "\ec9d"; }
+.ri-eraser-fill:before { content: "\ec9e"; }
+.ri-eraser-line:before { content: "\ec9f"; }
+.ri-error-warning-fill:before { content: "\eca0"; }
+.ri-error-warning-line:before { content: "\eca1"; }
+.ri-evernote-fill:before { content: "\eca2"; }
+.ri-evernote-line:before { content: "\eca3"; }
+.ri-exchange-box-fill:before { content: "\eca4"; }
+.ri-exchange-box-line:before { content: "\eca5"; }
+.ri-exchange-cny-fill:before { content: "\eca6"; }
+.ri-exchange-cny-line:before { content: "\eca7"; }
+.ri-exchange-dollar-fill:before { content: "\eca8"; }
+.ri-exchange-dollar-line:before { content: "\eca9"; }
+.ri-exchange-fill:before { content: "\ecaa"; }
+.ri-exchange-funds-fill:before { content: "\ecab"; }
+.ri-exchange-funds-line:before { content: "\ecac"; }
+.ri-exchange-line:before { content: "\ecad"; }
+.ri-external-link-fill:before { content: "\ecae"; }
+.ri-external-link-line:before { content: "\ecaf"; }
+.ri-eye-2-fill:before { content: "\ecb0"; }
+.ri-eye-2-line:before { content: "\ecb1"; }
+.ri-eye-close-fill:before { content: "\ecb2"; }
+.ri-eye-close-line:before { content: "\ecb3"; }
+.ri-eye-fill:before { content: "\ecb4"; }
+.ri-eye-line:before { content: "\ecb5"; }
+.ri-eye-off-fill:before { content: "\ecb6"; }
+.ri-eye-off-line:before { content: "\ecb7"; }
+.ri-facebook-box-fill:before { content: "\ecb8"; }
+.ri-facebook-box-line:before { content: "\ecb9"; }
+.ri-facebook-circle-fill:before { content: "\ecba"; }
+.ri-facebook-circle-line:before { content: "\ecbb"; }
+.ri-facebook-fill:before { content: "\ecbc"; }
+.ri-facebook-line:before { content: "\ecbd"; }
+.ri-fahrenheit-fill:before { content: "\ecbe"; }
+.ri-fahrenheit-line:before { content: "\ecbf"; }
+.ri-feedback-fill:before { content: "\ecc0"; }
+.ri-feedback-line:before { content: "\ecc1"; }
+.ri-file-2-fill:before { content: "\ecc2"; }
+.ri-file-2-line:before { content: "\ecc3"; }
+.ri-file-3-fill:before { content: "\ecc4"; }
+.ri-file-3-line:before { content: "\ecc5"; }
+.ri-file-4-fill:before { content: "\ecc6"; }
+.ri-file-4-line:before { content: "\ecc7"; }
+.ri-file-add-fill:before { content: "\ecc8"; }
+.ri-file-add-line:before { content: "\ecc9"; }
+.ri-file-chart-2-fill:before { content: "\ecca"; }
+.ri-file-chart-2-line:before { content: "\eccb"; }
+.ri-file-chart-fill:before { content: "\eccc"; }
+.ri-file-chart-line:before { content: "\eccd"; }
+.ri-file-cloud-fill:before { content: "\ecce"; }
+.ri-file-cloud-line:before { content: "\eccf"; }
+.ri-file-code-fill:before { content: "\ecd0"; }
+.ri-file-code-line:before { content: "\ecd1"; }
+.ri-file-copy-2-fill:before { content: "\ecd2"; }
+.ri-file-copy-2-line:before { content: "\ecd3"; }
+.ri-file-copy-fill:before { content: "\ecd4"; }
+.ri-file-copy-line:before { content: "\ecd5"; }
+.ri-file-damage-fill:before { content: "\ecd6"; }
+.ri-file-damage-line:before { content: "\ecd7"; }
+.ri-file-download-fill:before { content: "\ecd8"; }
+.ri-file-download-line:before { content: "\ecd9"; }
+.ri-file-edit-fill:before { content: "\ecda"; }
+.ri-file-edit-line:before { content: "\ecdb"; }
+.ri-file-excel-2-fill:before { content: "\ecdc"; }
+.ri-file-excel-2-line:before { content: "\ecdd"; }
+.ri-file-excel-fill:before { content: "\ecde"; }
+.ri-file-excel-line:before { content: "\ecdf"; }
+.ri-file-fill:before { content: "\ece0"; }
+.ri-file-forbid-fill:before { content: "\ece1"; }
+.ri-file-forbid-line:before { content: "\ece2"; }
+.ri-file-gif-fill:before { content: "\ece3"; }
+.ri-file-gif-line:before { content: "\ece4"; }
+.ri-file-history-fill:before { content: "\ece5"; }
+.ri-file-history-line:before { content: "\ece6"; }
+.ri-file-hwp-fill:before { content: "\ece7"; }
+.ri-file-hwp-line:before { content: "\ece8"; }
+.ri-file-info-fill:before { content: "\ece9"; }
+.ri-file-info-line:before { content: "\ecea"; }
+.ri-file-line:before { content: "\eceb"; }
+.ri-file-list-2-fill:before { content: "\ecec"; }
+.ri-file-list-2-line:before { content: "\eced"; }
+.ri-file-list-3-fill:before { content: "\ecee"; }
+.ri-file-list-3-line:before { content: "\ecef"; }
+.ri-file-list-fill:before { content: "\ecf0"; }
+.ri-file-list-line:before { content: "\ecf1"; }
+.ri-file-lock-fill:before { content: "\ecf2"; }
+.ri-file-lock-line:before { content: "\ecf3"; }
+.ri-file-marked-fill:before { content: "\ecf4"; }
+.ri-file-marked-line:before { content: "\ecf5"; }
+.ri-file-music-fill:before { content: "\ecf6"; }
+.ri-file-music-line:before { content: "\ecf7"; }
+.ri-file-paper-2-fill:before { content: "\ecf8"; }
+.ri-file-paper-2-line:before { content: "\ecf9"; }
+.ri-file-paper-fill:before { content: "\ecfa"; }
+.ri-file-paper-line:before { content: "\ecfb"; }
+.ri-file-pdf-fill:before { content: "\ecfc"; }
+.ri-file-pdf-line:before { content: "\ecfd"; }
+.ri-file-ppt-2-fill:before { content: "\ecfe"; }
+.ri-file-ppt-2-line:before { content: "\ecff"; }
+.ri-file-ppt-fill:before { content: "\ed00"; }
+.ri-file-ppt-line:before { content: "\ed01"; }
+.ri-file-reduce-fill:before { content: "\ed02"; }
+.ri-file-reduce-line:before { content: "\ed03"; }
+.ri-file-search-fill:before { content: "\ed04"; }
+.ri-file-search-line:before { content: "\ed05"; }
+.ri-file-settings-fill:before { content: "\ed06"; }
+.ri-file-settings-line:before { content: "\ed07"; }
+.ri-file-shield-2-fill:before { content: "\ed08"; }
+.ri-file-shield-2-line:before { content: "\ed09"; }
+.ri-file-shield-fill:before { content: "\ed0a"; }
+.ri-file-shield-line:before { content: "\ed0b"; }
+.ri-file-shred-fill:before { content: "\ed0c"; }
+.ri-file-shred-line:before { content: "\ed0d"; }
+.ri-file-text-fill:before { content: "\ed0e"; }
+.ri-file-text-line:before { content: "\ed0f"; }
+.ri-file-transfer-fill:before { content: "\ed10"; }
+.ri-file-transfer-line:before { content: "\ed11"; }
+.ri-file-unknow-fill:before { content: "\ed12"; }
+.ri-file-unknow-line:before { content: "\ed13"; }
+.ri-file-upload-fill:before { content: "\ed14"; }
+.ri-file-upload-line:before { content: "\ed15"; }
+.ri-file-user-fill:before { content: "\ed16"; }
+.ri-file-user-line:before { content: "\ed17"; }
+.ri-file-warning-fill:before { content: "\ed18"; }
+.ri-file-warning-line:before { content: "\ed19"; }
+.ri-file-word-2-fill:before { content: "\ed1a"; }
+.ri-file-word-2-line:before { content: "\ed1b"; }
+.ri-file-word-fill:before { content: "\ed1c"; }
+.ri-file-word-line:before { content: "\ed1d"; }
+.ri-file-zip-fill:before { content: "\ed1e"; }
+.ri-file-zip-line:before { content: "\ed1f"; }
+.ri-film-fill:before { content: "\ed20"; }
+.ri-film-line:before { content: "\ed21"; }
+.ri-filter-2-fill:before { content: "\ed22"; }
+.ri-filter-2-line:before { content: "\ed23"; }
+.ri-filter-3-fill:before { content: "\ed24"; }
+.ri-filter-3-line:before { content: "\ed25"; }
+.ri-filter-fill:before { content: "\ed26"; }
+.ri-filter-line:before { content: "\ed27"; }
+.ri-filter-off-fill:before { content: "\ed28"; }
+.ri-filter-off-line:before { content: "\ed29"; }
+.ri-find-replace-fill:before { content: "\ed2a"; }
+.ri-find-replace-line:before { content: "\ed2b"; }
+.ri-finder-fill:before { content: "\ed2c"; }
+.ri-finder-line:before { content: "\ed2d"; }
+.ri-fingerprint-2-fill:before { content: "\ed2e"; }
+.ri-fingerprint-2-line:before { content: "\ed2f"; }
+.ri-fingerprint-fill:before { content: "\ed30"; }
+.ri-fingerprint-line:before { content: "\ed31"; }
+.ri-fire-fill:before { content: "\ed32"; }
+.ri-fire-line:before { content: "\ed33"; }
+.ri-firefox-fill:before { content: "\ed34"; }
+.ri-firefox-line:before { content: "\ed35"; }
+.ri-first-aid-kit-fill:before { content: "\ed36"; }
+.ri-first-aid-kit-line:before { content: "\ed37"; }
+.ri-flag-2-fill:before { content: "\ed38"; }
+.ri-flag-2-line:before { content: "\ed39"; }
+.ri-flag-fill:before { content: "\ed3a"; }
+.ri-flag-line:before { content: "\ed3b"; }
+.ri-flashlight-fill:before { content: "\ed3c"; }
+.ri-flashlight-line:before { content: "\ed3d"; }
+.ri-flask-fill:before { content: "\ed3e"; }
+.ri-flask-line:before { content: "\ed3f"; }
+.ri-flight-land-fill:before { content: "\ed40"; }
+.ri-flight-land-line:before { content: "\ed41"; }
+.ri-flight-takeoff-fill:before { content: "\ed42"; }
+.ri-flight-takeoff-line:before { content: "\ed43"; }
+.ri-flood-fill:before { content: "\ed44"; }
+.ri-flood-line:before { content: "\ed45"; }
+.ri-flow-chart:before { content: "\ed46"; }
+.ri-flutter-fill:before { content: "\ed47"; }
+.ri-flutter-line:before { content: "\ed48"; }
+.ri-focus-2-fill:before { content: "\ed49"; }
+.ri-focus-2-line:before { content: "\ed4a"; }
+.ri-focus-3-fill:before { content: "\ed4b"; }
+.ri-focus-3-line:before { content: "\ed4c"; }
+.ri-focus-fill:before { content: "\ed4d"; }
+.ri-focus-line:before { content: "\ed4e"; }
+.ri-foggy-fill:before { content: "\ed4f"; }
+.ri-foggy-line:before { content: "\ed50"; }
+.ri-folder-2-fill:before { content: "\ed51"; }
+.ri-folder-2-line:before { content: "\ed52"; }
+.ri-folder-3-fill:before { content: "\ed53"; }
+.ri-folder-3-line:before { content: "\ed54"; }
+.ri-folder-4-fill:before { content: "\ed55"; }
+.ri-folder-4-line:before { content: "\ed56"; }
+.ri-folder-5-fill:before { content: "\ed57"; }
+.ri-folder-5-line:before { content: "\ed58"; }
+.ri-folder-add-fill:before { content: "\ed59"; }
+.ri-folder-add-line:before { content: "\ed5a"; }
+.ri-folder-chart-2-fill:before { content: "\ed5b"; }
+.ri-folder-chart-2-line:before { content: "\ed5c"; }
+.ri-folder-chart-fill:before { content: "\ed5d"; }
+.ri-folder-chart-line:before { content: "\ed5e"; }
+.ri-folder-download-fill:before { content: "\ed5f"; }
+.ri-folder-download-line:before { content: "\ed60"; }
+.ri-folder-fill:before { content: "\ed61"; }
+.ri-folder-forbid-fill:before { content: "\ed62"; }
+.ri-folder-forbid-line:before { content: "\ed63"; }
+.ri-folder-history-fill:before { content: "\ed64"; }
+.ri-folder-history-line:before { content: "\ed65"; }
+.ri-folder-info-fill:before { content: "\ed66"; }
+.ri-folder-info-line:before { content: "\ed67"; }
+.ri-folder-keyhole-fill:before { content: "\ed68"; }
+.ri-folder-keyhole-line:before { content: "\ed69"; }
+.ri-folder-line:before { content: "\ed6a"; }
+.ri-folder-lock-fill:before { content: "\ed6b"; }
+.ri-folder-lock-line:before { content: "\ed6c"; }
+.ri-folder-music-fill:before { content: "\ed6d"; }
+.ri-folder-music-line:before { content: "\ed6e"; }
+.ri-folder-open-fill:before { content: "\ed6f"; }
+.ri-folder-open-line:before { content: "\ed70"; }
+.ri-folder-received-fill:before { content: "\ed71"; }
+.ri-folder-received-line:before { content: "\ed72"; }
+.ri-folder-reduce-fill:before { content: "\ed73"; }
+.ri-folder-reduce-line:before { content: "\ed74"; }
+.ri-folder-settings-fill:before { content: "\ed75"; }
+.ri-folder-settings-line:before { content: "\ed76"; }
+.ri-folder-shared-fill:before { content: "\ed77"; }
+.ri-folder-shared-line:before { content: "\ed78"; }
+.ri-folder-shield-2-fill:before { content: "\ed79"; }
+.ri-folder-shield-2-line:before { content: "\ed7a"; }
+.ri-folder-shield-fill:before { content: "\ed7b"; }
+.ri-folder-shield-line:before { content: "\ed7c"; }
+.ri-folder-transfer-fill:before { content: "\ed7d"; }
+.ri-folder-transfer-line:before { content: "\ed7e"; }
+.ri-folder-unknow-fill:before { content: "\ed7f"; }
+.ri-folder-unknow-line:before { content: "\ed80"; }
+.ri-folder-upload-fill:before { content: "\ed81"; }
+.ri-folder-upload-line:before { content: "\ed82"; }
+.ri-folder-user-fill:before { content: "\ed83"; }
+.ri-folder-user-line:before { content: "\ed84"; }
+.ri-folder-warning-fill:before { content: "\ed85"; }
+.ri-folder-warning-line:before { content: "\ed86"; }
+.ri-folder-zip-fill:before { content: "\ed87"; }
+.ri-folder-zip-line:before { content: "\ed88"; }
+.ri-folders-fill:before { content: "\ed89"; }
+.ri-folders-line:before { content: "\ed8a"; }
+.ri-font-color:before { content: "\ed8b"; }
+.ri-font-size-2:before { content: "\ed8c"; }
+.ri-font-size:before { content: "\ed8d"; }
+.ri-football-fill:before { content: "\ed8e"; }
+.ri-football-line:before { content: "\ed8f"; }
+.ri-footprint-fill:before { content: "\ed90"; }
+.ri-footprint-line:before { content: "\ed91"; }
+.ri-forbid-2-fill:before { content: "\ed92"; }
+.ri-forbid-2-line:before { content: "\ed93"; }
+.ri-forbid-fill:before { content: "\ed94"; }
+.ri-forbid-line:before { content: "\ed95"; }
+.ri-format-clear:before { content: "\ed96"; }
+.ri-fridge-fill:before { content: "\ed97"; }
+.ri-fridge-line:before { content: "\ed98"; }
+.ri-fullscreen-exit-fill:before { content: "\ed99"; }
+.ri-fullscreen-exit-line:before { content: "\ed9a"; }
+.ri-fullscreen-fill:before { content: "\ed9b"; }
+.ri-fullscreen-line:before { content: "\ed9c"; }
+.ri-function-fill:before { content: "\ed9d"; }
+.ri-function-line:before { content: "\ed9e"; }
+.ri-functions:before { content: "\ed9f"; }
+.ri-funds-box-fill:before { content: "\eda0"; }
+.ri-funds-box-line:before { content: "\eda1"; }
+.ri-funds-fill:before { content: "\eda2"; }
+.ri-funds-line:before { content: "\eda3"; }
+.ri-gallery-fill:before { content: "\eda4"; }
+.ri-gallery-line:before { content: "\eda5"; }
+.ri-gallery-upload-fill:before { content: "\eda6"; }
+.ri-gallery-upload-line:before { content: "\eda7"; }
+.ri-game-fill:before { content: "\eda8"; }
+.ri-game-line:before { content: "\eda9"; }
+.ri-gamepad-fill:before { content: "\edaa"; }
+.ri-gamepad-line:before { content: "\edab"; }
+.ri-gas-station-fill:before { content: "\edac"; }
+.ri-gas-station-line:before { content: "\edad"; }
+.ri-gatsby-fill:before { content: "\edae"; }
+.ri-gatsby-line:before { content: "\edaf"; }
+.ri-genderless-fill:before { content: "\edb0"; }
+.ri-genderless-line:before { content: "\edb1"; }
+.ri-ghost-2-fill:before { content: "\edb2"; }
+.ri-ghost-2-line:before { content: "\edb3"; }
+.ri-ghost-fill:before { content: "\edb4"; }
+.ri-ghost-line:before { content: "\edb5"; }
+.ri-ghost-smile-fill:before { content: "\edb6"; }
+.ri-ghost-smile-line:before { content: "\edb7"; }
+.ri-gift-2-fill:before { content: "\edb8"; }
+.ri-gift-2-line:before { content: "\edb9"; }
+.ri-gift-fill:before { content: "\edba"; }
+.ri-gift-line:before { content: "\edbb"; }
+.ri-git-branch-fill:before { content: "\edbc"; }
+.ri-git-branch-line:before { content: "\edbd"; }
+.ri-git-commit-fill:before { content: "\edbe"; }
+.ri-git-commit-line:before { content: "\edbf"; }
+.ri-git-merge-fill:before { content: "\edc0"; }
+.ri-git-merge-line:before { content: "\edc1"; }
+.ri-git-pull-request-fill:before { content: "\edc2"; }
+.ri-git-pull-request-line:before { content: "\edc3"; }
+.ri-git-repository-commits-fill:before { content: "\edc4"; }
+.ri-git-repository-commits-line:before { content: "\edc5"; }
+.ri-git-repository-fill:before { content: "\edc6"; }
+.ri-git-repository-line:before { content: "\edc7"; }
+.ri-git-repository-private-fill:before { content: "\edc8"; }
+.ri-git-repository-private-line:before { content: "\edc9"; }
+.ri-github-fill:before { content: "\edca"; }
+.ri-github-line:before { content: "\edcb"; }
+.ri-gitlab-fill:before { content: "\edcc"; }
+.ri-gitlab-line:before { content: "\edcd"; }
+.ri-global-fill:before { content: "\edce"; }
+.ri-global-line:before { content: "\edcf"; }
+.ri-globe-fill:before { content: "\edd0"; }
+.ri-globe-line:before { content: "\edd1"; }
+.ri-goblet-fill:before { content: "\edd2"; }
+.ri-goblet-line:before { content: "\edd3"; }
+.ri-google-fill:before { content: "\edd4"; }
+.ri-google-line:before { content: "\edd5"; }
+.ri-google-play-fill:before { content: "\edd6"; }
+.ri-google-play-line:before { content: "\edd7"; }
+.ri-government-fill:before { content: "\edd8"; }
+.ri-government-line:before { content: "\edd9"; }
+.ri-gps-fill:before { content: "\edda"; }
+.ri-gps-line:before { content: "\eddb"; }
+.ri-gradienter-fill:before { content: "\eddc"; }
+.ri-gradienter-line:before { content: "\eddd"; }
+.ri-grid-fill:before { content: "\edde"; }
+.ri-grid-line:before { content: "\eddf"; }
+.ri-group-2-fill:before { content: "\ede0"; }
+.ri-group-2-line:before { content: "\ede1"; }
+.ri-group-fill:before { content: "\ede2"; }
+.ri-group-line:before { content: "\ede3"; }
+.ri-guide-fill:before { content: "\ede4"; }
+.ri-guide-line:before { content: "\ede5"; }
+.ri-h-1:before { content: "\ede6"; }
+.ri-h-2:before { content: "\ede7"; }
+.ri-h-3:before { content: "\ede8"; }
+.ri-h-4:before { content: "\ede9"; }
+.ri-h-5:before { content: "\edea"; }
+.ri-h-6:before { content: "\edeb"; }
+.ri-hail-fill:before { content: "\edec"; }
+.ri-hail-line:before { content: "\eded"; }
+.ri-hammer-fill:before { content: "\edee"; }
+.ri-hammer-line:before { content: "\edef"; }
+.ri-hand-coin-fill:before { content: "\edf0"; }
+.ri-hand-coin-line:before { content: "\edf1"; }
+.ri-hand-heart-fill:before { content: "\edf2"; }
+.ri-hand-heart-line:before { content: "\edf3"; }
+.ri-hand-sanitizer-fill:before { content: "\edf4"; }
+.ri-hand-sanitizer-line:before { content: "\edf5"; }
+.ri-handbag-fill:before { content: "\edf6"; }
+.ri-handbag-line:before { content: "\edf7"; }
+.ri-hard-drive-2-fill:before { content: "\edf8"; }
+.ri-hard-drive-2-line:before { content: "\edf9"; }
+.ri-hard-drive-fill:before { content: "\edfa"; }
+.ri-hard-drive-line:before { content: "\edfb"; }
+.ri-hashtag:before { content: "\edfc"; }
+.ri-haze-2-fill:before { content: "\edfd"; }
+.ri-haze-2-line:before { content: "\edfe"; }
+.ri-haze-fill:before { content: "\edff"; }
+.ri-haze-line:before { content: "\ee00"; }
+.ri-hd-fill:before { content: "\ee01"; }
+.ri-hd-line:before { content: "\ee02"; }
+.ri-heading:before { content: "\ee03"; }
+.ri-headphone-fill:before { content: "\ee04"; }
+.ri-headphone-line:before { content: "\ee05"; }
+.ri-health-book-fill:before { content: "\ee06"; }
+.ri-health-book-line:before { content: "\ee07"; }
+.ri-heart-2-fill:before { content: "\ee08"; }
+.ri-heart-2-line:before { content: "\ee09"; }
+.ri-heart-3-fill:before { content: "\ee0a"; }
+.ri-heart-3-line:before { content: "\ee0b"; }
+.ri-heart-add-fill:before { content: "\ee0c"; }
+.ri-heart-add-line:before { content: "\ee0d"; }
+.ri-heart-fill:before { content: "\ee0e"; }
+.ri-heart-line:before { content: "\ee0f"; }
+.ri-heart-pulse-fill:before { content: "\ee10"; }
+.ri-heart-pulse-line:before { content: "\ee11"; }
+.ri-hearts-fill:before { content: "\ee12"; }
+.ri-hearts-line:before { content: "\ee13"; }
+.ri-heavy-showers-fill:before { content: "\ee14"; }
+.ri-heavy-showers-line:before { content: "\ee15"; }
+.ri-history-fill:before { content: "\ee16"; }
+.ri-history-line:before { content: "\ee17"; }
+.ri-home-2-fill:before { content: "\ee18"; }
+.ri-home-2-line:before { content: "\ee19"; }
+.ri-home-3-fill:before { content: "\ee1a"; }
+.ri-home-3-line:before { content: "\ee1b"; }
+.ri-home-4-fill:before { content: "\ee1c"; }
+.ri-home-4-line:before { content: "\ee1d"; }
+.ri-home-5-fill:before { content: "\ee1e"; }
+.ri-home-5-line:before { content: "\ee1f"; }
+.ri-home-6-fill:before { content: "\ee20"; }
+.ri-home-6-line:before { content: "\ee21"; }
+.ri-home-7-fill:before { content: "\ee22"; }
+.ri-home-7-line:before { content: "\ee23"; }
+.ri-home-8-fill:before { content: "\ee24"; }
+.ri-home-8-line:before { content: "\ee25"; }
+.ri-home-fill:before { content: "\ee26"; }
+.ri-home-gear-fill:before { content: "\ee27"; }
+.ri-home-gear-line:before { content: "\ee28"; }
+.ri-home-heart-fill:before { content: "\ee29"; }
+.ri-home-heart-line:before { content: "\ee2a"; }
+.ri-home-line:before { content: "\ee2b"; }
+.ri-home-smile-2-fill:before { content: "\ee2c"; }
+.ri-home-smile-2-line:before { content: "\ee2d"; }
+.ri-home-smile-fill:before { content: "\ee2e"; }
+.ri-home-smile-line:before { content: "\ee2f"; }
+.ri-home-wifi-fill:before { content: "\ee30"; }
+.ri-home-wifi-line:before { content: "\ee31"; }
+.ri-honor-of-kings-fill:before { content: "\ee32"; }
+.ri-honor-of-kings-line:before { content: "\ee33"; }
+.ri-honour-fill:before { content: "\ee34"; }
+.ri-honour-line:before { content: "\ee35"; }
+.ri-hospital-fill:before { content: "\ee36"; }
+.ri-hospital-line:before { content: "\ee37"; }
+.ri-hotel-bed-fill:before { content: "\ee38"; }
+.ri-hotel-bed-line:before { content: "\ee39"; }
+.ri-hotel-fill:before { content: "\ee3a"; }
+.ri-hotel-line:before { content: "\ee3b"; }
+.ri-hotspot-fill:before { content: "\ee3c"; }
+.ri-hotspot-line:before { content: "\ee3d"; }
+.ri-hq-fill:before { content: "\ee3e"; }
+.ri-hq-line:before { content: "\ee3f"; }
+.ri-html5-fill:before { content: "\ee40"; }
+.ri-html5-line:before { content: "\ee41"; }
+.ri-ie-fill:before { content: "\ee42"; }
+.ri-ie-line:before { content: "\ee43"; }
+.ri-image-2-fill:before { content: "\ee44"; }
+.ri-image-2-line:before { content: "\ee45"; }
+.ri-image-add-fill:before { content: "\ee46"; }
+.ri-image-add-line:before { content: "\ee47"; }
+.ri-image-edit-fill:before { content: "\ee48"; }
+.ri-image-edit-line:before { content: "\ee49"; }
+.ri-image-fill:before { content: "\ee4a"; }
+.ri-image-line:before { content: "\ee4b"; }
+.ri-inbox-archive-fill:before { content: "\ee4c"; }
+.ri-inbox-archive-line:before { content: "\ee4d"; }
+.ri-inbox-fill:before { content: "\ee4e"; }
+.ri-inbox-line:before { content: "\ee4f"; }
+.ri-inbox-unarchive-fill:before { content: "\ee50"; }
+.ri-inbox-unarchive-line:before { content: "\ee51"; }
+.ri-increase-decrease-fill:before { content: "\ee52"; }
+.ri-increase-decrease-line:before { content: "\ee53"; }
+.ri-indent-decrease:before { content: "\ee54"; }
+.ri-indent-increase:before { content: "\ee55"; }
+.ri-indeterminate-circle-fill:before { content: "\ee56"; }
+.ri-indeterminate-circle-line:before { content: "\ee57"; }
+.ri-information-fill:before { content: "\ee58"; }
+.ri-information-line:before { content: "\ee59"; }
+.ri-infrared-thermometer-fill:before { content: "\ee5a"; }
+.ri-infrared-thermometer-line:before { content: "\ee5b"; }
+.ri-ink-bottle-fill:before { content: "\ee5c"; }
+.ri-ink-bottle-line:before { content: "\ee5d"; }
+.ri-input-cursor-move:before { content: "\ee5e"; }
+.ri-input-method-fill:before { content: "\ee5f"; }
+.ri-input-method-line:before { content: "\ee60"; }
+.ri-insert-column-left:before { content: "\ee61"; }
+.ri-insert-column-right:before { content: "\ee62"; }
+.ri-insert-row-bottom:before { content: "\ee63"; }
+.ri-insert-row-top:before { content: "\ee64"; }
+.ri-instagram-fill:before { content: "\ee65"; }
+.ri-instagram-line:before { content: "\ee66"; }
+.ri-install-fill:before { content: "\ee67"; }
+.ri-install-line:before { content: "\ee68"; }
+.ri-invision-fill:before { content: "\ee69"; }
+.ri-invision-line:before { content: "\ee6a"; }
+.ri-italic:before { content: "\ee6b"; }
+.ri-kakao-talk-fill:before { content: "\ee6c"; }
+.ri-kakao-talk-line:before { content: "\ee6d"; }
+.ri-key-2-fill:before { content: "\ee6e"; }
+.ri-key-2-line:before { content: "\ee6f"; }
+.ri-key-fill:before { content: "\ee70"; }
+.ri-key-line:before { content: "\ee71"; }
+.ri-keyboard-box-fill:before { content: "\ee72"; }
+.ri-keyboard-box-line:before { content: "\ee73"; }
+.ri-keyboard-fill:before { content: "\ee74"; }
+.ri-keyboard-line:before { content: "\ee75"; }
+.ri-keynote-fill:before { content: "\ee76"; }
+.ri-keynote-line:before { content: "\ee77"; }
+.ri-knife-blood-fill:before { content: "\ee78"; }
+.ri-knife-blood-line:before { content: "\ee79"; }
+.ri-knife-fill:before { content: "\ee7a"; }
+.ri-knife-line:before { content: "\ee7b"; }
+.ri-landscape-fill:before { content: "\ee7c"; }
+.ri-landscape-line:before { content: "\ee7d"; }
+.ri-layout-2-fill:before { content: "\ee7e"; }
+.ri-layout-2-line:before { content: "\ee7f"; }
+.ri-layout-3-fill:before { content: "\ee80"; }
+.ri-layout-3-line:before { content: "\ee81"; }
+.ri-layout-4-fill:before { content: "\ee82"; }
+.ri-layout-4-line:before { content: "\ee83"; }
+.ri-layout-5-fill:before { content: "\ee84"; }
+.ri-layout-5-line:before { content: "\ee85"; }
+.ri-layout-6-fill:before { content: "\ee86"; }
+.ri-layout-6-line:before { content: "\ee87"; }
+.ri-layout-bottom-2-fill:before { content: "\ee88"; }
+.ri-layout-bottom-2-line:before { content: "\ee89"; }
+.ri-layout-bottom-fill:before { content: "\ee8a"; }
+.ri-layout-bottom-line:before { content: "\ee8b"; }
+.ri-layout-column-fill:before { content: "\ee8c"; }
+.ri-layout-column-line:before { content: "\ee8d"; }
+.ri-layout-fill:before { content: "\ee8e"; }
+.ri-layout-grid-fill:before { content: "\ee8f"; }
+.ri-layout-grid-line:before { content: "\ee90"; }
+.ri-layout-left-2-fill:before { content: "\ee91"; }
+.ri-layout-left-2-line:before { content: "\ee92"; }
+.ri-layout-left-fill:before { content: "\ee93"; }
+.ri-layout-left-line:before { content: "\ee94"; }
+.ri-layout-line:before { content: "\ee95"; }
+.ri-layout-masonry-fill:before { content: "\ee96"; }
+.ri-layout-masonry-line:before { content: "\ee97"; }
+.ri-layout-right-2-fill:before { content: "\ee98"; }
+.ri-layout-right-2-line:before { content: "\ee99"; }
+.ri-layout-right-fill:before { content: "\ee9a"; }
+.ri-layout-right-line:before { content: "\ee9b"; }
+.ri-layout-row-fill:before { content: "\ee9c"; }
+.ri-layout-row-line:before { content: "\ee9d"; }
+.ri-layout-top-2-fill:before { content: "\ee9e"; }
+.ri-layout-top-2-line:before { content: "\ee9f"; }
+.ri-layout-top-fill:before { content: "\eea0"; }
+.ri-layout-top-line:before { content: "\eea1"; }
+.ri-leaf-fill:before { content: "\eea2"; }
+.ri-leaf-line:before { content: "\eea3"; }
+.ri-lifebuoy-fill:before { content: "\eea4"; }
+.ri-lifebuoy-line:before { content: "\eea5"; }
+.ri-lightbulb-fill:before { content: "\eea6"; }
+.ri-lightbulb-flash-fill:before { content: "\eea7"; }
+.ri-lightbulb-flash-line:before { content: "\eea8"; }
+.ri-lightbulb-line:before { content: "\eea9"; }
+.ri-line-chart-fill:before { content: "\eeaa"; }
+.ri-line-chart-line:before { content: "\eeab"; }
+.ri-line-fill:before { content: "\eeac"; }
+.ri-line-height:before { content: "\eead"; }
+.ri-line-line:before { content: "\eeae"; }
+.ri-link-m:before { content: "\eeaf"; }
+.ri-link-unlink-m:before { content: "\eeb0"; }
+.ri-link-unlink:before { content: "\eeb1"; }
+.ri-link:before { content: "\eeb2"; }
+.ri-linkedin-box-fill:before { content: "\eeb3"; }
+.ri-linkedin-box-line:before { content: "\eeb4"; }
+.ri-linkedin-fill:before { content: "\eeb5"; }
+.ri-linkedin-line:before { content: "\eeb6"; }
+.ri-links-fill:before { content: "\eeb7"; }
+.ri-links-line:before { content: "\eeb8"; }
+.ri-list-check-2:before { content: "\eeb9"; }
+.ri-list-check:before { content: "\eeba"; }
+.ri-list-ordered:before { content: "\eebb"; }
+.ri-list-settings-fill:before { content: "\eebc"; }
+.ri-list-settings-line:before { content: "\eebd"; }
+.ri-list-unordered:before { content: "\eebe"; }
+.ri-live-fill:before { content: "\eebf"; }
+.ri-live-line:before { content: "\eec0"; }
+.ri-loader-2-fill:before { content: "\eec1"; }
+.ri-loader-2-line:before { content: "\eec2"; }
+.ri-loader-3-fill:before { content: "\eec3"; }
+.ri-loader-3-line:before { content: "\eec4"; }
+.ri-loader-4-fill:before { content: "\eec5"; }
+.ri-loader-4-line:before { content: "\eec6"; }
+.ri-loader-5-fill:before { content: "\eec7"; }
+.ri-loader-5-line:before { content: "\eec8"; }
+.ri-loader-fill:before { content: "\eec9"; }
+.ri-loader-line:before { content: "\eeca"; }
+.ri-lock-2-fill:before { content: "\eecb"; }
+.ri-lock-2-line:before { content: "\eecc"; }
+.ri-lock-fill:before { content: "\eecd"; }
+.ri-lock-line:before { content: "\eece"; }
+.ri-lock-password-fill:before { content: "\eecf"; }
+.ri-lock-password-line:before { content: "\eed0"; }
+.ri-lock-unlock-fill:before { content: "\eed1"; }
+.ri-lock-unlock-line:before { content: "\eed2"; }
+.ri-login-box-fill:before { content: "\eed3"; }
+.ri-login-box-line:before { content: "\eed4"; }
+.ri-login-circle-fill:before { content: "\eed5"; }
+.ri-login-circle-line:before { content: "\eed6"; }
+.ri-logout-box-fill:before { content: "\eed7"; }
+.ri-logout-box-line:before { content: "\eed8"; }
+.ri-logout-box-r-fill:before { content: "\eed9"; }
+.ri-logout-box-r-line:before { content: "\eeda"; }
+.ri-logout-circle-fill:before { content: "\eedb"; }
+.ri-logout-circle-line:before { content: "\eedc"; }
+.ri-logout-circle-r-fill:before { content: "\eedd"; }
+.ri-logout-circle-r-line:before { content: "\eede"; }
+.ri-luggage-cart-fill:before { content: "\eedf"; }
+.ri-luggage-cart-line:before { content: "\eee0"; }
+.ri-luggage-deposit-fill:before { content: "\eee1"; }
+.ri-luggage-deposit-line:before { content: "\eee2"; }
+.ri-lungs-fill:before { content: "\eee3"; }
+.ri-lungs-line:before { content: "\eee4"; }
+.ri-mac-fill:before { content: "\eee5"; }
+.ri-mac-line:before { content: "\eee6"; }
+.ri-macbook-fill:before { content: "\eee7"; }
+.ri-macbook-line:before { content: "\eee8"; }
+.ri-magic-fill:before { content: "\eee9"; }
+.ri-magic-line:before { content: "\eeea"; }
+.ri-mail-add-fill:before { content: "\eeeb"; }
+.ri-mail-add-line:before { content: "\eeec"; }
+.ri-mail-check-fill:before { content: "\eeed"; }
+.ri-mail-check-line:before { content: "\eeee"; }
+.ri-mail-close-fill:before { content: "\eeef"; }
+.ri-mail-close-line:before { content: "\eef0"; }
+.ri-mail-download-fill:before { content: "\eef1"; }
+.ri-mail-download-line:before { content: "\eef2"; }
+.ri-mail-fill:before { content: "\eef3"; }
+.ri-mail-forbid-fill:before { content: "\eef4"; }
+.ri-mail-forbid-line:before { content: "\eef5"; }
+.ri-mail-line:before { content: "\eef6"; }
+.ri-mail-lock-fill:before { content: "\eef7"; }
+.ri-mail-lock-line:before { content: "\eef8"; }
+.ri-mail-open-fill:before { content: "\eef9"; }
+.ri-mail-open-line:before { content: "\eefa"; }
+.ri-mail-send-fill:before { content: "\eefb"; }
+.ri-mail-send-line:before { content: "\eefc"; }
+.ri-mail-settings-fill:before { content: "\eefd"; }
+.ri-mail-settings-line:before { content: "\eefe"; }
+.ri-mail-star-fill:before { content: "\eeff"; }
+.ri-mail-star-line:before { content: "\ef00"; }
+.ri-mail-unread-fill:before { content: "\ef01"; }
+.ri-mail-unread-line:before { content: "\ef02"; }
+.ri-mail-volume-fill:before { content: "\ef03"; }
+.ri-mail-volume-line:before { content: "\ef04"; }
+.ri-map-2-fill:before { content: "\ef05"; }
+.ri-map-2-line:before { content: "\ef06"; }
+.ri-map-fill:before { content: "\ef07"; }
+.ri-map-line:before { content: "\ef08"; }
+.ri-map-pin-2-fill:before { content: "\ef09"; }
+.ri-map-pin-2-line:before { content: "\ef0a"; }
+.ri-map-pin-3-fill:before { content: "\ef0b"; }
+.ri-map-pin-3-line:before { content: "\ef0c"; }
+.ri-map-pin-4-fill:before { content: "\ef0d"; }
+.ri-map-pin-4-line:before { content: "\ef0e"; }
+.ri-map-pin-5-fill:before { content: "\ef0f"; }
+.ri-map-pin-5-line:before { content: "\ef10"; }
+.ri-map-pin-add-fill:before { content: "\ef11"; }
+.ri-map-pin-add-line:before { content: "\ef12"; }
+.ri-map-pin-fill:before { content: "\ef13"; }
+.ri-map-pin-line:before { content: "\ef14"; }
+.ri-map-pin-range-fill:before { content: "\ef15"; }
+.ri-map-pin-range-line:before { content: "\ef16"; }
+.ri-map-pin-time-fill:before { content: "\ef17"; }
+.ri-map-pin-time-line:before { content: "\ef18"; }
+.ri-map-pin-user-fill:before { content: "\ef19"; }
+.ri-map-pin-user-line:before { content: "\ef1a"; }
+.ri-mark-pen-fill:before { content: "\ef1b"; }
+.ri-mark-pen-line:before { content: "\ef1c"; }
+.ri-markdown-fill:before { content: "\ef1d"; }
+.ri-markdown-line:before { content: "\ef1e"; }
+.ri-markup-fill:before { content: "\ef1f"; }
+.ri-markup-line:before { content: "\ef20"; }
+.ri-mastercard-fill:before { content: "\ef21"; }
+.ri-mastercard-line:before { content: "\ef22"; }
+.ri-mastodon-fill:before { content: "\ef23"; }
+.ri-mastodon-line:before { content: "\ef24"; }
+.ri-medal-2-fill:before { content: "\ef25"; }
+.ri-medal-2-line:before { content: "\ef26"; }
+.ri-medal-fill:before { content: "\ef27"; }
+.ri-medal-line:before { content: "\ef28"; }
+.ri-medicine-bottle-fill:before { content: "\ef29"; }
+.ri-medicine-bottle-line:before { content: "\ef2a"; }
+.ri-medium-fill:before { content: "\ef2b"; }
+.ri-medium-line:before { content: "\ef2c"; }
+.ri-men-fill:before { content: "\ef2d"; }
+.ri-men-line:before { content: "\ef2e"; }
+.ri-mental-health-fill:before { content: "\ef2f"; }
+.ri-mental-health-line:before { content: "\ef30"; }
+.ri-menu-2-fill:before { content: "\ef31"; }
+.ri-menu-2-line:before { content: "\ef32"; }
+.ri-menu-3-fill:before { content: "\ef33"; }
+.ri-menu-3-line:before { content: "\ef34"; }
+.ri-menu-4-fill:before { content: "\ef35"; }
+.ri-menu-4-line:before { content: "\ef36"; }
+.ri-menu-5-fill:before { content: "\ef37"; }
+.ri-menu-5-line:before { content: "\ef38"; }
+.ri-menu-add-fill:before { content: "\ef39"; }
+.ri-menu-add-line:before { content: "\ef3a"; }
+.ri-menu-fill:before { content: "\ef3b"; }
+.ri-menu-fold-fill:before { content: "\ef3c"; }
+.ri-menu-fold-line:before { content: "\ef3d"; }
+.ri-menu-line:before { content: "\ef3e"; }
+.ri-menu-unfold-fill:before { content: "\ef3f"; }
+.ri-menu-unfold-line:before { content: "\ef40"; }
+.ri-merge-cells-horizontal:before { content: "\ef41"; }
+.ri-merge-cells-vertical:before { content: "\ef42"; }
+.ri-message-2-fill:before { content: "\ef43"; }
+.ri-message-2-line:before { content: "\ef44"; }
+.ri-message-3-fill:before { content: "\ef45"; }
+.ri-message-3-line:before { content: "\ef46"; }
+.ri-message-fill:before { content: "\ef47"; }
+.ri-message-line:before { content: "\ef48"; }
+.ri-messenger-fill:before { content: "\ef49"; }
+.ri-messenger-line:before { content: "\ef4a"; }
+.ri-meteor-fill:before { content: "\ef4b"; }
+.ri-meteor-line:before { content: "\ef4c"; }
+.ri-mic-2-fill:before { content: "\ef4d"; }
+.ri-mic-2-line:before { content: "\ef4e"; }
+.ri-mic-fill:before { content: "\ef4f"; }
+.ri-mic-line:before { content: "\ef50"; }
+.ri-mic-off-fill:before { content: "\ef51"; }
+.ri-mic-off-line:before { content: "\ef52"; }
+.ri-mickey-fill:before { content: "\ef53"; }
+.ri-mickey-line:before { content: "\ef54"; }
+.ri-microscope-fill:before { content: "\ef55"; }
+.ri-microscope-line:before { content: "\ef56"; }
+.ri-microsoft-fill:before { content: "\ef57"; }
+.ri-microsoft-line:before { content: "\ef58"; }
+.ri-mind-map:before { content: "\ef59"; }
+.ri-mini-program-fill:before { content: "\ef5a"; }
+.ri-mini-program-line:before { content: "\ef5b"; }
+.ri-mist-fill:before { content: "\ef5c"; }
+.ri-mist-line:before { content: "\ef5d"; }
+.ri-money-cny-box-fill:before { content: "\ef5e"; }
+.ri-money-cny-box-line:before { content: "\ef5f"; }
+.ri-money-cny-circle-fill:before { content: "\ef60"; }
+.ri-money-cny-circle-line:before { content: "\ef61"; }
+.ri-money-dollar-box-fill:before { content: "\ef62"; }
+.ri-money-dollar-box-line:before { content: "\ef63"; }
+.ri-money-dollar-circle-fill:before { content: "\ef64"; }
+.ri-money-dollar-circle-line:before { content: "\ef65"; }
+.ri-money-euro-box-fill:before { content: "\ef66"; }
+.ri-money-euro-box-line:before { content: "\ef67"; }
+.ri-money-euro-circle-fill:before { content: "\ef68"; }
+.ri-money-euro-circle-line:before { content: "\ef69"; }
+.ri-money-pound-box-fill:before { content: "\ef6a"; }
+.ri-money-pound-box-line:before { content: "\ef6b"; }
+.ri-money-pound-circle-fill:before { content: "\ef6c"; }
+.ri-money-pound-circle-line:before { content: "\ef6d"; }
+.ri-moon-clear-fill:before { content: "\ef6e"; }
+.ri-moon-clear-line:before { content: "\ef6f"; }
+.ri-moon-cloudy-fill:before { content: "\ef70"; }
+.ri-moon-cloudy-line:before { content: "\ef71"; }
+.ri-moon-fill:before { content: "\ef72"; }
+.ri-moon-foggy-fill:before { content: "\ef73"; }
+.ri-moon-foggy-line:before { content: "\ef74"; }
+.ri-moon-line:before { content: "\ef75"; }
+.ri-more-2-fill:before { content: "\ef76"; }
+.ri-more-2-line:before { content: "\ef77"; }
+.ri-more-fill:before { content: "\ef78"; }
+.ri-more-line:before { content: "\ef79"; }
+.ri-motorbike-fill:before { content: "\ef7a"; }
+.ri-motorbike-line:before { content: "\ef7b"; }
+.ri-mouse-fill:before { content: "\ef7c"; }
+.ri-mouse-line:before { content: "\ef7d"; }
+.ri-movie-2-fill:before { content: "\ef7e"; }
+.ri-movie-2-line:before { content: "\ef7f"; }
+.ri-movie-fill:before { content: "\ef80"; }
+.ri-movie-line:before { content: "\ef81"; }
+.ri-music-2-fill:before { content: "\ef82"; }
+.ri-music-2-line:before { content: "\ef83"; }
+.ri-music-fill:before { content: "\ef84"; }
+.ri-music-line:before { content: "\ef85"; }
+.ri-mv-fill:before { content: "\ef86"; }
+.ri-mv-line:before { content: "\ef87"; }
+.ri-navigation-fill:before { content: "\ef88"; }
+.ri-navigation-line:before { content: "\ef89"; }
+.ri-netease-cloud-music-fill:before { content: "\ef8a"; }
+.ri-netease-cloud-music-line:before { content: "\ef8b"; }
+.ri-netflix-fill:before { content: "\ef8c"; }
+.ri-netflix-line:before { content: "\ef8d"; }
+.ri-newspaper-fill:before { content: "\ef8e"; }
+.ri-newspaper-line:before { content: "\ef8f"; }
+.ri-node-tree:before { content: "\ef90"; }
+.ri-notification-2-fill:before { content: "\ef91"; }
+.ri-notification-2-line:before { content: "\ef92"; }
+.ri-notification-3-fill:before { content: "\ef93"; }
+.ri-notification-3-line:before { content: "\ef94"; }
+.ri-notification-4-fill:before { content: "\ef95"; }
+.ri-notification-4-line:before { content: "\ef96"; }
+.ri-notification-badge-fill:before { content: "\ef97"; }
+.ri-notification-badge-line:before { content: "\ef98"; }
+.ri-notification-fill:before { content: "\ef99"; }
+.ri-notification-line:before { content: "\ef9a"; }
+.ri-notification-off-fill:before { content: "\ef9b"; }
+.ri-notification-off-line:before { content: "\ef9c"; }
+.ri-npmjs-fill:before { content: "\ef9d"; }
+.ri-npmjs-line:before { content: "\ef9e"; }
+.ri-number-0:before { content: "\ef9f"; }
+.ri-number-1:before { content: "\efa0"; }
+.ri-number-2:before { content: "\efa1"; }
+.ri-number-3:before { content: "\efa2"; }
+.ri-number-4:before { content: "\efa3"; }
+.ri-number-5:before { content: "\efa4"; }
+.ri-number-6:before { content: "\efa5"; }
+.ri-number-7:before { content: "\efa6"; }
+.ri-number-8:before { content: "\efa7"; }
+.ri-number-9:before { content: "\efa8"; }
+.ri-numbers-fill:before { content: "\efa9"; }
+.ri-numbers-line:before { content: "\efaa"; }
+.ri-nurse-fill:before { content: "\efab"; }
+.ri-nurse-line:before { content: "\efac"; }
+.ri-oil-fill:before { content: "\efad"; }
+.ri-oil-line:before { content: "\efae"; }
+.ri-omega:before { content: "\efaf"; }
+.ri-open-arm-fill:before { content: "\efb0"; }
+.ri-open-arm-line:before { content: "\efb1"; }
+.ri-open-source-fill:before { content: "\efb2"; }
+.ri-open-source-line:before { content: "\efb3"; }
+.ri-opera-fill:before { content: "\efb4"; }
+.ri-opera-line:before { content: "\efb5"; }
+.ri-order-play-fill:before { content: "\efb6"; }
+.ri-order-play-line:before { content: "\efb7"; }
+.ri-organization-chart:before { content: "\efb8"; }
+.ri-outlet-2-fill:before { content: "\efb9"; }
+.ri-outlet-2-line:before { content: "\efba"; }
+.ri-outlet-fill:before { content: "\efbb"; }
+.ri-outlet-line:before { content: "\efbc"; }
+.ri-page-separator:before { content: "\efbd"; }
+.ri-pages-fill:before { content: "\efbe"; }
+.ri-pages-line:before { content: "\efbf"; }
+.ri-paint-brush-fill:before { content: "\efc0"; }
+.ri-paint-brush-line:before { content: "\efc1"; }
+.ri-paint-fill:before { content: "\efc2"; }
+.ri-paint-line:before { content: "\efc3"; }
+.ri-palette-fill:before { content: "\efc4"; }
+.ri-palette-line:before { content: "\efc5"; }
+.ri-pantone-fill:before { content: "\efc6"; }
+.ri-pantone-line:before { content: "\efc7"; }
+.ri-paragraph:before { content: "\efc8"; }
+.ri-parent-fill:before { content: "\efc9"; }
+.ri-parent-line:before { content: "\efca"; }
+.ri-parentheses-fill:before { content: "\efcb"; }
+.ri-parentheses-line:before { content: "\efcc"; }
+.ri-parking-box-fill:before { content: "\efcd"; }
+.ri-parking-box-line:before { content: "\efce"; }
+.ri-parking-fill:before { content: "\efcf"; }
+.ri-parking-line:before { content: "\efd0"; }
+.ri-passport-fill:before { content: "\efd1"; }
+.ri-passport-line:before { content: "\efd2"; }
+.ri-patreon-fill:before { content: "\efd3"; }
+.ri-patreon-line:before { content: "\efd4"; }
+.ri-pause-circle-fill:before { content: "\efd5"; }
+.ri-pause-circle-line:before { content: "\efd6"; }
+.ri-pause-fill:before { content: "\efd7"; }
+.ri-pause-line:before { content: "\efd8"; }
+.ri-pause-mini-fill:before { content: "\efd9"; }
+.ri-pause-mini-line:before { content: "\efda"; }
+.ri-paypal-fill:before { content: "\efdb"; }
+.ri-paypal-line:before { content: "\efdc"; }
+.ri-pen-nib-fill:before { content: "\efdd"; }
+.ri-pen-nib-line:before { content: "\efde"; }
+.ri-pencil-fill:before { content: "\efdf"; }
+.ri-pencil-line:before { content: "\efe0"; }
+.ri-pencil-ruler-2-fill:before { content: "\efe1"; }
+.ri-pencil-ruler-2-line:before { content: "\efe2"; }
+.ri-pencil-ruler-fill:before { content: "\efe3"; }
+.ri-pencil-ruler-line:before { content: "\efe4"; }
+.ri-percent-fill:before { content: "\efe5"; }
+.ri-percent-line:before { content: "\efe6"; }
+.ri-phone-camera-fill:before { content: "\efe7"; }
+.ri-phone-camera-line:before { content: "\efe8"; }
+.ri-phone-fill:before { content: "\efe9"; }
+.ri-phone-find-fill:before { content: "\efea"; }
+.ri-phone-find-line:before { content: "\efeb"; }
+.ri-phone-line:before { content: "\efec"; }
+.ri-phone-lock-fill:before { content: "\efed"; }
+.ri-phone-lock-line:before { content: "\efee"; }
+.ri-picture-in-picture-2-fill:before { content: "\efef"; }
+.ri-picture-in-picture-2-line:before { content: "\eff0"; }
+.ri-picture-in-picture-exit-fill:before { content: "\eff1"; }
+.ri-picture-in-picture-exit-line:before { content: "\eff2"; }
+.ri-picture-in-picture-fill:before { content: "\eff3"; }
+.ri-picture-in-picture-line:before { content: "\eff4"; }
+.ri-pie-chart-2-fill:before { content: "\eff5"; }
+.ri-pie-chart-2-line:before { content: "\eff6"; }
+.ri-pie-chart-box-fill:before { content: "\eff7"; }
+.ri-pie-chart-box-line:before { content: "\eff8"; }
+.ri-pie-chart-fill:before { content: "\eff9"; }
+.ri-pie-chart-line:before { content: "\effa"; }
+.ri-pin-distance-fill:before { content: "\effb"; }
+.ri-pin-distance-line:before { content: "\effc"; }
+.ri-ping-pong-fill:before { content: "\effd"; }
+.ri-ping-pong-line:before { content: "\effe"; }
+.ri-pinterest-fill:before { content: "\efff"; }
+.ri-pinterest-line:before { content: "\f000"; }
+.ri-pinyin-input:before { content: "\f001"; }
+.ri-pixelfed-fill:before { content: "\f002"; }
+.ri-pixelfed-line:before { content: "\f003"; }
+.ri-plane-fill:before { content: "\f004"; }
+.ri-plane-line:before { content: "\f005"; }
+.ri-plant-fill:before { content: "\f006"; }
+.ri-plant-line:before { content: "\f007"; }
+.ri-play-circle-fill:before { content: "\f008"; }
+.ri-play-circle-line:before { content: "\f009"; }
+.ri-play-fill:before { content: "\f00a"; }
+.ri-play-line:before { content: "\f00b"; }
+.ri-play-list-2-fill:before { content: "\f00c"; }
+.ri-play-list-2-line:before { content: "\f00d"; }
+.ri-play-list-add-fill:before { content: "\f00e"; }
+.ri-play-list-add-line:before { content: "\f00f"; }
+.ri-play-list-fill:before { content: "\f010"; }
+.ri-play-list-line:before { content: "\f011"; }
+.ri-play-mini-fill:before { content: "\f012"; }
+.ri-play-mini-line:before { content: "\f013"; }
+.ri-playstation-fill:before { content: "\f014"; }
+.ri-playstation-line:before { content: "\f015"; }
+.ri-plug-2-fill:before { content: "\f016"; }
+.ri-plug-2-line:before { content: "\f017"; }
+.ri-plug-fill:before { content: "\f018"; }
+.ri-plug-line:before { content: "\f019"; }
+.ri-polaroid-2-fill:before { content: "\f01a"; }
+.ri-polaroid-2-line:before { content: "\f01b"; }
+.ri-polaroid-fill:before { content: "\f01c"; }
+.ri-polaroid-line:before { content: "\f01d"; }
+.ri-police-car-fill:before { content: "\f01e"; }
+.ri-police-car-line:before { content: "\f01f"; }
+.ri-price-tag-2-fill:before { content: "\f020"; }
+.ri-price-tag-2-line:before { content: "\f021"; }
+.ri-price-tag-3-fill:before { content: "\f022"; }
+.ri-price-tag-3-line:before { content: "\f023"; }
+.ri-price-tag-fill:before { content: "\f024"; }
+.ri-price-tag-line:before { content: "\f025"; }
+.ri-printer-cloud-fill:before { content: "\f026"; }
+.ri-printer-cloud-line:before { content: "\f027"; }
+.ri-printer-fill:before { content: "\f028"; }
+.ri-printer-line:before { content: "\f029"; }
+.ri-product-hunt-fill:before { content: "\f02a"; }
+.ri-product-hunt-line:before { content: "\f02b"; }
+.ri-profile-fill:before { content: "\f02c"; }
+.ri-profile-line:before { content: "\f02d"; }
+.ri-projector-2-fill:before { content: "\f02e"; }
+.ri-projector-2-line:before { content: "\f02f"; }
+.ri-projector-fill:before { content: "\f030"; }
+.ri-projector-line:before { content: "\f031"; }
+.ri-psychotherapy-fill:before { content: "\f032"; }
+.ri-psychotherapy-line:before { content: "\f033"; }
+.ri-pulse-fill:before { content: "\f034"; }
+.ri-pulse-line:before { content: "\f035"; }
+.ri-pushpin-2-fill:before { content: "\f036"; }
+.ri-pushpin-2-line:before { content: "\f037"; }
+.ri-pushpin-fill:before { content: "\f038"; }
+.ri-pushpin-line:before { content: "\f039"; }
+.ri-qq-fill:before { content: "\f03a"; }
+.ri-qq-line:before { content: "\f03b"; }
+.ri-qr-code-fill:before { content: "\f03c"; }
+.ri-qr-code-line:before { content: "\f03d"; }
+.ri-qr-scan-2-fill:before { content: "\f03e"; }
+.ri-qr-scan-2-line:before { content: "\f03f"; }
+.ri-qr-scan-fill:before { content: "\f040"; }
+.ri-qr-scan-line:before { content: "\f041"; }
+.ri-question-answer-fill:before { content: "\f042"; }
+.ri-question-answer-line:before { content: "\f043"; }
+.ri-question-fill:before { content: "\f044"; }
+.ri-question-line:before { content: "\f045"; }
+.ri-question-mark:before { content: "\f046"; }
+.ri-questionnaire-fill:before { content: "\f047"; }
+.ri-questionnaire-line:before { content: "\f048"; }
+.ri-quill-pen-fill:before { content: "\f049"; }
+.ri-quill-pen-line:before { content: "\f04a"; }
+.ri-radar-fill:before { content: "\f04b"; }
+.ri-radar-line:before { content: "\f04c"; }
+.ri-radio-2-fill:before { content: "\f04d"; }
+.ri-radio-2-line:before { content: "\f04e"; }
+.ri-radio-button-fill:before { content: "\f04f"; }
+.ri-radio-button-line:before { content: "\f050"; }
+.ri-radio-fill:before { content: "\f051"; }
+.ri-radio-line:before { content: "\f052"; }
+.ri-rainbow-fill:before { content: "\f053"; }
+.ri-rainbow-line:before { content: "\f054"; }
+.ri-rainy-fill:before { content: "\f055"; }
+.ri-rainy-line:before { content: "\f056"; }
+.ri-reactjs-fill:before { content: "\f057"; }
+.ri-reactjs-line:before { content: "\f058"; }
+.ri-record-circle-fill:before { content: "\f059"; }
+.ri-record-circle-line:before { content: "\f05a"; }
+.ri-record-mail-fill:before { content: "\f05b"; }
+.ri-record-mail-line:before { content: "\f05c"; }
+.ri-recycle-fill:before { content: "\f05d"; }
+.ri-recycle-line:before { content: "\f05e"; }
+.ri-red-packet-fill:before { content: "\f05f"; }
+.ri-red-packet-line:before { content: "\f060"; }
+.ri-reddit-fill:before { content: "\f061"; }
+.ri-reddit-line:before { content: "\f062"; }
+.ri-refresh-fill:before { content: "\f063"; }
+.ri-refresh-line:before { content: "\f064"; }
+.ri-refund-2-fill:before { content: "\f065"; }
+.ri-refund-2-line:before { content: "\f066"; }
+.ri-refund-fill:before { content: "\f067"; }
+.ri-refund-line:before { content: "\f068"; }
+.ri-registered-fill:before { content: "\f069"; }
+.ri-registered-line:before { content: "\f06a"; }
+.ri-remixicon-fill:before { content: "\f06b"; }
+.ri-remixicon-line:before { content: "\f06c"; }
+.ri-remote-control-2-fill:before { content: "\f06d"; }
+.ri-remote-control-2-line:before { content: "\f06e"; }
+.ri-remote-control-fill:before { content: "\f06f"; }
+.ri-remote-control-line:before { content: "\f070"; }
+.ri-repeat-2-fill:before { content: "\f071"; }
+.ri-repeat-2-line:before { content: "\f072"; }
+.ri-repeat-fill:before { content: "\f073"; }
+.ri-repeat-line:before { content: "\f074"; }
+.ri-repeat-one-fill:before { content: "\f075"; }
+.ri-repeat-one-line:before { content: "\f076"; }
+.ri-reply-all-fill:before { content: "\f077"; }
+.ri-reply-all-line:before { content: "\f078"; }
+.ri-reply-fill:before { content: "\f079"; }
+.ri-reply-line:before { content: "\f07a"; }
+.ri-reserved-fill:before { content: "\f07b"; }
+.ri-reserved-line:before { content: "\f07c"; }
+.ri-rest-time-fill:before { content: "\f07d"; }
+.ri-rest-time-line:before { content: "\f07e"; }
+.ri-restart-fill:before { content: "\f07f"; }
+.ri-restart-line:before { content: "\f080"; }
+.ri-restaurant-2-fill:before { content: "\f081"; }
+.ri-restaurant-2-line:before { content: "\f082"; }
+.ri-restaurant-fill:before { content: "\f083"; }
+.ri-restaurant-line:before { content: "\f084"; }
+.ri-rewind-fill:before { content: "\f085"; }
+.ri-rewind-line:before { content: "\f086"; }
+.ri-rewind-mini-fill:before { content: "\f087"; }
+.ri-rewind-mini-line:before { content: "\f088"; }
+.ri-rhythm-fill:before { content: "\f089"; }
+.ri-rhythm-line:before { content: "\f08a"; }
+.ri-riding-fill:before { content: "\f08b"; }
+.ri-riding-line:before { content: "\f08c"; }
+.ri-road-map-fill:before { content: "\f08d"; }
+.ri-road-map-line:before { content: "\f08e"; }
+.ri-roadster-fill:before { content: "\f08f"; }
+.ri-roadster-line:before { content: "\f090"; }
+.ri-robot-fill:before { content: "\f091"; }
+.ri-robot-line:before { content: "\f092"; }
+.ri-rocket-2-fill:before { content: "\f093"; }
+.ri-rocket-2-line:before { content: "\f094"; }
+.ri-rocket-fill:before { content: "\f095"; }
+.ri-rocket-line:before { content: "\f096"; }
+.ri-rotate-lock-fill:before { content: "\f097"; }
+.ri-rotate-lock-line:before { content: "\f098"; }
+.ri-rounded-corner:before { content: "\f099"; }
+.ri-route-fill:before { content: "\f09a"; }
+.ri-route-line:before { content: "\f09b"; }
+.ri-router-fill:before { content: "\f09c"; }
+.ri-router-line:before { content: "\f09d"; }
+.ri-rss-fill:before { content: "\f09e"; }
+.ri-rss-line:before { content: "\f09f"; }
+.ri-ruler-2-fill:before { content: "\f0a0"; }
+.ri-ruler-2-line:before { content: "\f0a1"; }
+.ri-ruler-fill:before { content: "\f0a2"; }
+.ri-ruler-line:before { content: "\f0a3"; }
+.ri-run-fill:before { content: "\f0a4"; }
+.ri-run-line:before { content: "\f0a5"; }
+.ri-safari-fill:before { content: "\f0a6"; }
+.ri-safari-line:before { content: "\f0a7"; }
+.ri-safe-2-fill:before { content: "\f0a8"; }
+.ri-safe-2-line:before { content: "\f0a9"; }
+.ri-safe-fill:before { content: "\f0aa"; }
+.ri-safe-line:before { content: "\f0ab"; }
+.ri-sailboat-fill:before { content: "\f0ac"; }
+.ri-sailboat-line:before { content: "\f0ad"; }
+.ri-save-2-fill:before { content: "\f0ae"; }
+.ri-save-2-line:before { content: "\f0af"; }
+.ri-save-3-fill:before { content: "\f0b0"; }
+.ri-save-3-line:before { content: "\f0b1"; }
+.ri-save-fill:before { content: "\f0b2"; }
+.ri-save-line:before { content: "\f0b3"; }
+.ri-scales-2-fill:before { content: "\f0b4"; }
+.ri-scales-2-line:before { content: "\f0b5"; }
+.ri-scales-3-fill:before { content: "\f0b6"; }
+.ri-scales-3-line:before { content: "\f0b7"; }
+.ri-scales-fill:before { content: "\f0b8"; }
+.ri-scales-line:before { content: "\f0b9"; }
+.ri-scan-2-fill:before { content: "\f0ba"; }
+.ri-scan-2-line:before { content: "\f0bb"; }
+.ri-scan-fill:before { content: "\f0bc"; }
+.ri-scan-line:before { content: "\f0bd"; }
+.ri-scissors-2-fill:before { content: "\f0be"; }
+.ri-scissors-2-line:before { content: "\f0bf"; }
+.ri-scissors-cut-fill:before { content: "\f0c0"; }
+.ri-scissors-cut-line:before { content: "\f0c1"; }
+.ri-scissors-fill:before { content: "\f0c2"; }
+.ri-scissors-line:before { content: "\f0c3"; }
+.ri-screenshot-2-fill:before { content: "\f0c4"; }
+.ri-screenshot-2-line:before { content: "\f0c5"; }
+.ri-screenshot-fill:before { content: "\f0c6"; }
+.ri-screenshot-line:before { content: "\f0c7"; }
+.ri-sd-card-fill:before { content: "\f0c8"; }
+.ri-sd-card-line:before { content: "\f0c9"; }
+.ri-sd-card-mini-fill:before { content: "\f0ca"; }
+.ri-sd-card-mini-line:before { content: "\f0cb"; }
+.ri-search-2-fill:before { content: "\f0cc"; }
+.ri-search-2-line:before { content: "\f0cd"; }
+.ri-search-eye-fill:before { content: "\f0ce"; }
+.ri-search-eye-line:before { content: "\f0cf"; }
+.ri-search-fill:before { content: "\f0d0"; }
+.ri-search-line:before { content: "\f0d1"; }
+.ri-secure-payment-fill:before { content: "\f0d2"; }
+.ri-secure-payment-line:before { content: "\f0d3"; }
+.ri-seedling-fill:before { content: "\f0d4"; }
+.ri-seedling-line:before { content: "\f0d5"; }
+.ri-send-backward:before { content: "\f0d6"; }
+.ri-send-plane-2-fill:before { content: "\f0d7"; }
+.ri-send-plane-2-line:before { content: "\f0d8"; }
+.ri-send-plane-fill:before { content: "\f0d9"; }
+.ri-send-plane-line:before { content: "\f0da"; }
+.ri-send-to-back:before { content: "\f0db"; }
+.ri-sensor-fill:before { content: "\f0dc"; }
+.ri-sensor-line:before { content: "\f0dd"; }
+.ri-separator:before { content: "\f0de"; }
+.ri-server-fill:before { content: "\f0df"; }
+.ri-server-line:before { content: "\f0e0"; }
+.ri-service-fill:before { content: "\f0e1"; }
+.ri-service-line:before { content: "\f0e2"; }
+.ri-settings-2-fill:before { content: "\f0e3"; }
+.ri-settings-2-line:before { content: "\f0e4"; }
+.ri-settings-3-fill:before { content: "\f0e5"; }
+.ri-settings-3-line:before { content: "\f0e6"; }
+.ri-settings-4-fill:before { content: "\f0e7"; }
+.ri-settings-4-line:before { content: "\f0e8"; }
+.ri-settings-5-fill:before { content: "\f0e9"; }
+.ri-settings-5-line:before { content: "\f0ea"; }
+.ri-settings-6-fill:before { content: "\f0eb"; }
+.ri-settings-6-line:before { content: "\f0ec"; }
+.ri-settings-fill:before { content: "\f0ed"; }
+.ri-settings-line:before { content: "\f0ee"; }
+.ri-shape-2-fill:before { content: "\f0ef"; }
+.ri-shape-2-line:before { content: "\f0f0"; }
+.ri-shape-fill:before { content: "\f0f1"; }
+.ri-shape-line:before { content: "\f0f2"; }
+.ri-share-box-fill:before { content: "\f0f3"; }
+.ri-share-box-line:before { content: "\f0f4"; }
+.ri-share-circle-fill:before { content: "\f0f5"; }
+.ri-share-circle-line:before { content: "\f0f6"; }
+.ri-share-fill:before { content: "\f0f7"; }
+.ri-share-forward-2-fill:before { content: "\f0f8"; }
+.ri-share-forward-2-line:before { content: "\f0f9"; }
+.ri-share-forward-box-fill:before { content: "\f0fa"; }
+.ri-share-forward-box-line:before { content: "\f0fb"; }
+.ri-share-forward-fill:before { content: "\f0fc"; }
+.ri-share-forward-line:before { content: "\f0fd"; }
+.ri-share-line:before { content: "\f0fe"; }
+.ri-shield-check-fill:before { content: "\f0ff"; }
+.ri-shield-check-line:before { content: "\f100"; }
+.ri-shield-cross-fill:before { content: "\f101"; }
+.ri-shield-cross-line:before { content: "\f102"; }
+.ri-shield-fill:before { content: "\f103"; }
+.ri-shield-flash-fill:before { content: "\f104"; }
+.ri-shield-flash-line:before { content: "\f105"; }
+.ri-shield-keyhole-fill:before { content: "\f106"; }
+.ri-shield-keyhole-line:before { content: "\f107"; }
+.ri-shield-line:before { content: "\f108"; }
+.ri-shield-star-fill:before { content: "\f109"; }
+.ri-shield-star-line:before { content: "\f10a"; }
+.ri-shield-user-fill:before { content: "\f10b"; }
+.ri-shield-user-line:before { content: "\f10c"; }
+.ri-ship-2-fill:before { content: "\f10d"; }
+.ri-ship-2-line:before { content: "\f10e"; }
+.ri-ship-fill:before { content: "\f10f"; }
+.ri-ship-line:before { content: "\f110"; }
+.ri-shirt-fill:before { content: "\f111"; }
+.ri-shirt-line:before { content: "\f112"; }
+.ri-shopping-bag-2-fill:before { content: "\f113"; }
+.ri-shopping-bag-2-line:before { content: "\f114"; }
+.ri-shopping-bag-3-fill:before { content: "\f115"; }
+.ri-shopping-bag-3-line:before { content: "\f116"; }
+.ri-shopping-bag-fill:before { content: "\f117"; }
+.ri-shopping-bag-line:before { content: "\f118"; }
+.ri-shopping-basket-2-fill:before { content: "\f119"; }
+.ri-shopping-basket-2-line:before { content: "\f11a"; }
+.ri-shopping-basket-fill:before { content: "\f11b"; }
+.ri-shopping-basket-line:before { content: "\f11c"; }
+.ri-shopping-cart-2-fill:before { content: "\f11d"; }
+.ri-shopping-cart-2-line:before { content: "\f11e"; }
+.ri-shopping-cart-fill:before { content: "\f11f"; }
+.ri-shopping-cart-line:before { content: "\f120"; }
+.ri-showers-fill:before { content: "\f121"; }
+.ri-showers-line:before { content: "\f122"; }
+.ri-shuffle-fill:before { content: "\f123"; }
+.ri-shuffle-line:before { content: "\f124"; }
+.ri-shut-down-fill:before { content: "\f125"; }
+.ri-shut-down-line:before { content: "\f126"; }
+.ri-side-bar-fill:before { content: "\f127"; }
+.ri-side-bar-line:before { content: "\f128"; }
+.ri-signal-tower-fill:before { content: "\f129"; }
+.ri-signal-tower-line:before { content: "\f12a"; }
+.ri-signal-wifi-1-fill:before { content: "\f12b"; }
+.ri-signal-wifi-1-line:before { content: "\f12c"; }
+.ri-signal-wifi-2-fill:before { content: "\f12d"; }
+.ri-signal-wifi-2-line:before { content: "\f12e"; }
+.ri-signal-wifi-3-fill:before { content: "\f12f"; }
+.ri-signal-wifi-3-line:before { content: "\f130"; }
+.ri-signal-wifi-error-fill:before { content: "\f131"; }
+.ri-signal-wifi-error-line:before { content: "\f132"; }
+.ri-signal-wifi-fill:before { content: "\f133"; }
+.ri-signal-wifi-line:before { content: "\f134"; }
+.ri-signal-wifi-off-fill:before { content: "\f135"; }
+.ri-signal-wifi-off-line:before { content: "\f136"; }
+.ri-sim-card-2-fill:before { content: "\f137"; }
+.ri-sim-card-2-line:before { content: "\f138"; }
+.ri-sim-card-fill:before { content: "\f139"; }
+.ri-sim-card-line:before { content: "\f13a"; }
+.ri-single-quotes-l:before { content: "\f13b"; }
+.ri-single-quotes-r:before { content: "\f13c"; }
+.ri-sip-fill:before { content: "\f13d"; }
+.ri-sip-line:before { content: "\f13e"; }
+.ri-skip-back-fill:before { content: "\f13f"; }
+.ri-skip-back-line:before { content: "\f140"; }
+.ri-skip-back-mini-fill:before { content: "\f141"; }
+.ri-skip-back-mini-line:before { content: "\f142"; }
+.ri-skip-forward-fill:before { content: "\f143"; }
+.ri-skip-forward-line:before { content: "\f144"; }
+.ri-skip-forward-mini-fill:before { content: "\f145"; }
+.ri-skip-forward-mini-line:before { content: "\f146"; }
+.ri-skull-2-fill:before { content: "\f147"; }
+.ri-skull-2-line:before { content: "\f148"; }
+.ri-skull-fill:before { content: "\f149"; }
+.ri-skull-line:before { content: "\f14a"; }
+.ri-skype-fill:before { content: "\f14b"; }
+.ri-skype-line:before { content: "\f14c"; }
+.ri-slack-fill:before { content: "\f14d"; }
+.ri-slack-line:before { content: "\f14e"; }
+.ri-slice-fill:before { content: "\f14f"; }
+.ri-slice-line:before { content: "\f150"; }
+.ri-slideshow-2-fill:before { content: "\f151"; }
+.ri-slideshow-2-line:before { content: "\f152"; }
+.ri-slideshow-3-fill:before { content: "\f153"; }
+.ri-slideshow-3-line:before { content: "\f154"; }
+.ri-slideshow-4-fill:before { content: "\f155"; }
+.ri-slideshow-4-line:before { content: "\f156"; }
+.ri-slideshow-fill:before { content: "\f157"; }
+.ri-slideshow-line:before { content: "\f158"; }
+.ri-smartphone-fill:before { content: "\f159"; }
+.ri-smartphone-line:before { content: "\f15a"; }
+.ri-snapchat-fill:before { content: "\f15b"; }
+.ri-snapchat-line:before { content: "\f15c"; }
+.ri-snowy-fill:before { content: "\f15d"; }
+.ri-snowy-line:before { content: "\f15e"; }
+.ri-sort-asc:before { content: "\f15f"; }
+.ri-sort-desc:before { content: "\f160"; }
+.ri-sound-module-fill:before { content: "\f161"; }
+.ri-sound-module-line:before { content: "\f162"; }
+.ri-soundcloud-fill:before { content: "\f163"; }
+.ri-soundcloud-line:before { content: "\f164"; }
+.ri-space-ship-fill:before { content: "\f165"; }
+.ri-space-ship-line:before { content: "\f166"; }
+.ri-space:before { content: "\f167"; }
+.ri-spam-2-fill:before { content: "\f168"; }
+.ri-spam-2-line:before { content: "\f169"; }
+.ri-spam-3-fill:before { content: "\f16a"; }
+.ri-spam-3-line:before { content: "\f16b"; }
+.ri-spam-fill:before { content: "\f16c"; }
+.ri-spam-line:before { content: "\f16d"; }
+.ri-speaker-2-fill:before { content: "\f16e"; }
+.ri-speaker-2-line:before { content: "\f16f"; }
+.ri-speaker-3-fill:before { content: "\f170"; }
+.ri-speaker-3-line:before { content: "\f171"; }
+.ri-speaker-fill:before { content: "\f172"; }
+.ri-speaker-line:before { content: "\f173"; }
+.ri-spectrum-fill:before { content: "\f174"; }
+.ri-spectrum-line:before { content: "\f175"; }
+.ri-speed-fill:before { content: "\f176"; }
+.ri-speed-line:before { content: "\f177"; }
+.ri-speed-mini-fill:before { content: "\f178"; }
+.ri-speed-mini-line:before { content: "\f179"; }
+.ri-split-cells-horizontal:before { content: "\f17a"; }
+.ri-split-cells-vertical:before { content: "\f17b"; }
+.ri-spotify-fill:before { content: "\f17c"; }
+.ri-spotify-line:before { content: "\f17d"; }
+.ri-spy-fill:before { content: "\f17e"; }
+.ri-spy-line:before { content: "\f17f"; }
+.ri-stack-fill:before { content: "\f180"; }
+.ri-stack-line:before { content: "\f181"; }
+.ri-stack-overflow-fill:before { content: "\f182"; }
+.ri-stack-overflow-line:before { content: "\f183"; }
+.ri-stackshare-fill:before { content: "\f184"; }
+.ri-stackshare-line:before { content: "\f185"; }
+.ri-star-fill:before { content: "\f186"; }
+.ri-star-half-fill:before { content: "\f187"; }
+.ri-star-half-line:before { content: "\f188"; }
+.ri-star-half-s-fill:before { content: "\f189"; }
+.ri-star-half-s-line:before { content: "\f18a"; }
+.ri-star-line:before { content: "\f18b"; }
+.ri-star-s-fill:before { content: "\f18c"; }
+.ri-star-s-line:before { content: "\f18d"; }
+.ri-star-smile-fill:before { content: "\f18e"; }
+.ri-star-smile-line:before { content: "\f18f"; }
+.ri-steam-fill:before { content: "\f190"; }
+.ri-steam-line:before { content: "\f191"; }
+.ri-steering-2-fill:before { content: "\f192"; }
+.ri-steering-2-line:before { content: "\f193"; }
+.ri-steering-fill:before { content: "\f194"; }
+.ri-steering-line:before { content: "\f195"; }
+.ri-stethoscope-fill:before { content: "\f196"; }
+.ri-stethoscope-line:before { content: "\f197"; }
+.ri-sticky-note-2-fill:before { content: "\f198"; }
+.ri-sticky-note-2-line:before { content: "\f199"; }
+.ri-sticky-note-fill:before { content: "\f19a"; }
+.ri-sticky-note-line:before { content: "\f19b"; }
+.ri-stock-fill:before { content: "\f19c"; }
+.ri-stock-line:before { content: "\f19d"; }
+.ri-stop-circle-fill:before { content: "\f19e"; }
+.ri-stop-circle-line:before { content: "\f19f"; }
+.ri-stop-fill:before { content: "\f1a0"; }
+.ri-stop-line:before { content: "\f1a1"; }
+.ri-stop-mini-fill:before { content: "\f1a2"; }
+.ri-stop-mini-line:before { content: "\f1a3"; }
+.ri-store-2-fill:before { content: "\f1a4"; }
+.ri-store-2-line:before { content: "\f1a5"; }
+.ri-store-3-fill:before { content: "\f1a6"; }
+.ri-store-3-line:before { content: "\f1a7"; }
+.ri-store-fill:before { content: "\f1a8"; }
+.ri-store-line:before { content: "\f1a9"; }
+.ri-strikethrough-2:before { content: "\f1aa"; }
+.ri-strikethrough:before { content: "\f1ab"; }
+.ri-subscript-2:before { content: "\f1ac"; }
+.ri-subscript:before { content: "\f1ad"; }
+.ri-subtract-fill:before { content: "\f1ae"; }
+.ri-subtract-line:before { content: "\f1af"; }
+.ri-subway-fill:before { content: "\f1b0"; }
+.ri-subway-line:before { content: "\f1b1"; }
+.ri-subway-wifi-fill:before { content: "\f1b2"; }
+.ri-subway-wifi-line:before { content: "\f1b3"; }
+.ri-suitcase-2-fill:before { content: "\f1b4"; }
+.ri-suitcase-2-line:before { content: "\f1b5"; }
+.ri-suitcase-3-fill:before { content: "\f1b6"; }
+.ri-suitcase-3-line:before { content: "\f1b7"; }
+.ri-suitcase-fill:before { content: "\f1b8"; }
+.ri-suitcase-line:before { content: "\f1b9"; }
+.ri-sun-cloudy-fill:before { content: "\f1ba"; }
+.ri-sun-cloudy-line:before { content: "\f1bb"; }
+.ri-sun-fill:before { content: "\f1bc"; }
+.ri-sun-foggy-fill:before { content: "\f1bd"; }
+.ri-sun-foggy-line:before { content: "\f1be"; }
+.ri-sun-line:before { content: "\f1bf"; }
+.ri-superscript-2:before { content: "\f1c0"; }
+.ri-superscript:before { content: "\f1c1"; }
+.ri-surgical-mask-fill:before { content: "\f1c2"; }
+.ri-surgical-mask-line:before { content: "\f1c3"; }
+.ri-surround-sound-fill:before { content: "\f1c4"; }
+.ri-surround-sound-line:before { content: "\f1c5"; }
+.ri-survey-fill:before { content: "\f1c6"; }
+.ri-survey-line:before { content: "\f1c7"; }
+.ri-swap-box-fill:before { content: "\f1c8"; }
+.ri-swap-box-line:before { content: "\f1c9"; }
+.ri-swap-fill:before { content: "\f1ca"; }
+.ri-swap-line:before { content: "\f1cb"; }
+.ri-switch-fill:before { content: "\f1cc"; }
+.ri-switch-line:before { content: "\f1cd"; }
+.ri-sword-fill:before { content: "\f1ce"; }
+.ri-sword-line:before { content: "\f1cf"; }
+.ri-syringe-fill:before { content: "\f1d0"; }
+.ri-syringe-line:before { content: "\f1d1"; }
+.ri-t-box-fill:before { content: "\f1d2"; }
+.ri-t-box-line:before { content: "\f1d3"; }
+.ri-t-shirt-2-fill:before { content: "\f1d4"; }
+.ri-t-shirt-2-line:before { content: "\f1d5"; }
+.ri-t-shirt-air-fill:before { content: "\f1d6"; }
+.ri-t-shirt-air-line:before { content: "\f1d7"; }
+.ri-t-shirt-fill:before { content: "\f1d8"; }
+.ri-t-shirt-line:before { content: "\f1d9"; }
+.ri-table-2:before { content: "\f1da"; }
+.ri-table-alt-fill:before { content: "\f1db"; }
+.ri-table-alt-line:before { content: "\f1dc"; }
+.ri-table-fill:before { content: "\f1dd"; }
+.ri-table-line:before { content: "\f1de"; }
+.ri-tablet-fill:before { content: "\f1df"; }
+.ri-tablet-line:before { content: "\f1e0"; }
+.ri-takeaway-fill:before { content: "\f1e1"; }
+.ri-takeaway-line:before { content: "\f1e2"; }
+.ri-taobao-fill:before { content: "\f1e3"; }
+.ri-taobao-line:before { content: "\f1e4"; }
+.ri-tape-fill:before { content: "\f1e5"; }
+.ri-tape-line:before { content: "\f1e6"; }
+.ri-task-fill:before { content: "\f1e7"; }
+.ri-task-line:before { content: "\f1e8"; }
+.ri-taxi-fill:before { content: "\f1e9"; }
+.ri-taxi-line:before { content: "\f1ea"; }
+.ri-taxi-wifi-fill:before { content: "\f1eb"; }
+.ri-taxi-wifi-line:before { content: "\f1ec"; }
+.ri-team-fill:before { content: "\f1ed"; }
+.ri-team-line:before { content: "\f1ee"; }
+.ri-telegram-fill:before { content: "\f1ef"; }
+.ri-telegram-line:before { content: "\f1f0"; }
+.ri-temp-cold-fill:before { content: "\f1f1"; }
+.ri-temp-cold-line:before { content: "\f1f2"; }
+.ri-temp-hot-fill:before { content: "\f1f3"; }
+.ri-temp-hot-line:before { content: "\f1f4"; }
+.ri-terminal-box-fill:before { content: "\f1f5"; }
+.ri-terminal-box-line:before { content: "\f1f6"; }
+.ri-terminal-fill:before { content: "\f1f7"; }
+.ri-terminal-line:before { content: "\f1f8"; }
+.ri-terminal-window-fill:before { content: "\f1f9"; }
+.ri-terminal-window-line:before { content: "\f1fa"; }
+.ri-test-tube-fill:before { content: "\f1fb"; }
+.ri-test-tube-line:before { content: "\f1fc"; }
+.ri-text-direction-l:before { content: "\f1fd"; }
+.ri-text-direction-r:before { content: "\f1fe"; }
+.ri-text-spacing:before { content: "\f1ff"; }
+.ri-text-wrap:before { content: "\f200"; }
+.ri-text:before { content: "\f201"; }
+.ri-thermometer-fill:before { content: "\f202"; }
+.ri-thermometer-line:before { content: "\f203"; }
+.ri-thumb-down-fill:before { content: "\f204"; }
+.ri-thumb-down-line:before { content: "\f205"; }
+.ri-thumb-up-fill:before { content: "\f206"; }
+.ri-thumb-up-line:before { content: "\f207"; }
+.ri-thunderstorms-fill:before { content: "\f208"; }
+.ri-thunderstorms-line:before { content: "\f209"; }
+.ri-ticket-2-fill:before { content: "\f20a"; }
+.ri-ticket-2-line:before { content: "\f20b"; }
+.ri-ticket-fill:before { content: "\f20c"; }
+.ri-ticket-line:before { content: "\f20d"; }
+.ri-time-fill:before { content: "\f20e"; }
+.ri-time-line:before { content: "\f20f"; }
+.ri-timer-2-fill:before { content: "\f210"; }
+.ri-timer-2-line:before { content: "\f211"; }
+.ri-timer-fill:before { content: "\f212"; }
+.ri-timer-flash-fill:before { content: "\f213"; }
+.ri-timer-flash-line:before { content: "\f214"; }
+.ri-timer-line:before { content: "\f215"; }
+.ri-todo-fill:before { content: "\f216"; }
+.ri-todo-line:before { content: "\f217"; }
+.ri-toggle-fill:before { content: "\f218"; }
+.ri-toggle-line:before { content: "\f219"; }
+.ri-tools-fill:before { content: "\f21a"; }
+.ri-tools-line:before { content: "\f21b"; }
+.ri-tornado-fill:before { content: "\f21c"; }
+.ri-tornado-line:before { content: "\f21d"; }
+.ri-trademark-fill:before { content: "\f21e"; }
+.ri-trademark-line:before { content: "\f21f"; }
+.ri-traffic-light-fill:before { content: "\f220"; }
+.ri-traffic-light-line:before { content: "\f221"; }
+.ri-train-fill:before { content: "\f222"; }
+.ri-train-line:before { content: "\f223"; }
+.ri-train-wifi-fill:before { content: "\f224"; }
+.ri-train-wifi-line:before { content: "\f225"; }
+.ri-translate-2:before { content: "\f226"; }
+.ri-translate:before { content: "\f227"; }
+.ri-travesti-fill:before { content: "\f228"; }
+.ri-travesti-line:before { content: "\f229"; }
+.ri-treasure-map-fill:before { content: "\f22a"; }
+.ri-treasure-map-line:before { content: "\f22b"; }
+.ri-trello-fill:before { content: "\f22c"; }
+.ri-trello-line:before { content: "\f22d"; }
+.ri-trophy-fill:before { content: "\f22e"; }
+.ri-trophy-line:before { content: "\f22f"; }
+.ri-truck-fill:before { content: "\f230"; }
+.ri-truck-line:before { content: "\f231"; }
+.ri-tumblr-fill:before { content: "\f232"; }
+.ri-tumblr-line:before { content: "\f233"; }
+.ri-tv-2-fill:before { content: "\f234"; }
+.ri-tv-2-line:before { content: "\f235"; }
+.ri-tv-fill:before { content: "\f236"; }
+.ri-tv-line:before { content: "\f237"; }
+.ri-twitch-fill:before { content: "\f238"; }
+.ri-twitch-line:before { content: "\f239"; }
+.ri-twitter-fill:before { content: "\f23a"; }
+.ri-twitter-line:before { content: "\f23b"; }
+.ri-typhoon-fill:before { content: "\f23c"; }
+.ri-typhoon-line:before { content: "\f23d"; }
+.ri-u-disk-fill:before { content: "\f23e"; }
+.ri-u-disk-line:before { content: "\f23f"; }
+.ri-ubuntu-fill:before { content: "\f240"; }
+.ri-ubuntu-line:before { content: "\f241"; }
+.ri-umbrella-fill:before { content: "\f242"; }
+.ri-umbrella-line:before { content: "\f243"; }
+.ri-underline:before { content: "\f244"; }
+.ri-uninstall-fill:before { content: "\f245"; }
+.ri-uninstall-line:before { content: "\f246"; }
+.ri-unsplash-fill:before { content: "\f247"; }
+.ri-unsplash-line:before { content: "\f248"; }
+.ri-upload-2-fill:before { content: "\f249"; }
+.ri-upload-2-line:before { content: "\f24a"; }
+.ri-upload-cloud-2-fill:before { content: "\f24b"; }
+.ri-upload-cloud-2-line:before { content: "\f24c"; }
+.ri-upload-cloud-fill:before { content: "\f24d"; }
+.ri-upload-cloud-line:before { content: "\f24e"; }
+.ri-upload-fill:before { content: "\f24f"; }
+.ri-upload-line:before { content: "\f250"; }
+.ri-usb-fill:before { content: "\f251"; }
+.ri-usb-line:before { content: "\f252"; }
+.ri-user-2-fill:before { content: "\f253"; }
+.ri-user-2-line:before { content: "\f254"; }
+.ri-user-3-fill:before { content: "\f255"; }
+.ri-user-3-line:before { content: "\f256"; }
+.ri-user-4-fill:before { content: "\f257"; }
+.ri-user-4-line:before { content: "\f258"; }
+.ri-user-5-fill:before { content: "\f259"; }
+.ri-user-5-line:before { content: "\f25a"; }
+.ri-user-6-fill:before { content: "\f25b"; }
+.ri-user-6-line:before { content: "\f25c"; }
+.ri-user-add-fill:before { content: "\f25d"; }
+.ri-user-add-line:before { content: "\f25e"; }
+.ri-user-fill:before { content: "\f25f"; }
+.ri-user-follow-fill:before { content: "\f260"; }
+.ri-user-follow-line:before { content: "\f261"; }
+.ri-user-heart-fill:before { content: "\f262"; }
+.ri-user-heart-line:before { content: "\f263"; }
+.ri-user-line:before { content: "\f264"; }
+.ri-user-location-fill:before { content: "\f265"; }
+.ri-user-location-line:before { content: "\f266"; }
+.ri-user-received-2-fill:before { content: "\f267"; }
+.ri-user-received-2-line:before { content: "\f268"; }
+.ri-user-received-fill:before { content: "\f269"; }
+.ri-user-received-line:before { content: "\f26a"; }
+.ri-user-search-fill:before { content: "\f26b"; }
+.ri-user-search-line:before { content: "\f26c"; }
+.ri-user-settings-fill:before { content: "\f26d"; }
+.ri-user-settings-line:before { content: "\f26e"; }
+.ri-user-shared-2-fill:before { content: "\f26f"; }
+.ri-user-shared-2-line:before { content: "\f270"; }
+.ri-user-shared-fill:before { content: "\f271"; }
+.ri-user-shared-line:before { content: "\f272"; }
+.ri-user-smile-fill:before { content: "\f273"; }
+.ri-user-smile-line:before { content: "\f274"; }
+.ri-user-star-fill:before { content: "\f275"; }
+.ri-user-star-line:before { content: "\f276"; }
+.ri-user-unfollow-fill:before { content: "\f277"; }
+.ri-user-unfollow-line:before { content: "\f278"; }
+.ri-user-voice-fill:before { content: "\f279"; }
+.ri-user-voice-line:before { content: "\f27a"; }
+.ri-video-add-fill:before { content: "\f27b"; }
+.ri-video-add-line:before { content: "\f27c"; }
+.ri-video-chat-fill:before { content: "\f27d"; }
+.ri-video-chat-line:before { content: "\f27e"; }
+.ri-video-download-fill:before { content: "\f27f"; }
+.ri-video-download-line:before { content: "\f280"; }
+.ri-video-fill:before { content: "\f281"; }
+.ri-video-line:before { content: "\f282"; }
+.ri-video-upload-fill:before { content: "\f283"; }
+.ri-video-upload-line:before { content: "\f284"; }
+.ri-vidicon-2-fill:before { content: "\f285"; }
+.ri-vidicon-2-line:before { content: "\f286"; }
+.ri-vidicon-fill:before { content: "\f287"; }
+.ri-vidicon-line:before { content: "\f288"; }
+.ri-vimeo-fill:before { content: "\f289"; }
+.ri-vimeo-line:before { content: "\f28a"; }
+.ri-vip-crown-2-fill:before { content: "\f28b"; }
+.ri-vip-crown-2-line:before { content: "\f28c"; }
+.ri-vip-crown-fill:before { content: "\f28d"; }
+.ri-vip-crown-line:before { content: "\f28e"; }
+.ri-vip-diamond-fill:before { content: "\f28f"; }
+.ri-vip-diamond-line:before { content: "\f290"; }
+.ri-vip-fill:before { content: "\f291"; }
+.ri-vip-line:before { content: "\f292"; }
+.ri-virus-fill:before { content: "\f293"; }
+.ri-virus-line:before { content: "\f294"; }
+.ri-visa-fill:before { content: "\f295"; }
+.ri-visa-line:before { content: "\f296"; }
+.ri-voice-recognition-fill:before { content: "\f297"; }
+.ri-voice-recognition-line:before { content: "\f298"; }
+.ri-voiceprint-fill:before { content: "\f299"; }
+.ri-voiceprint-line:before { content: "\f29a"; }
+.ri-volume-down-fill:before { content: "\f29b"; }
+.ri-volume-down-line:before { content: "\f29c"; }
+.ri-volume-mute-fill:before { content: "\f29d"; }
+.ri-volume-mute-line:before { content: "\f29e"; }
+.ri-volume-off-vibrate-fill:before { content: "\f29f"; }
+.ri-volume-off-vibrate-line:before { content: "\f2a0"; }
+.ri-volume-up-fill:before { content: "\f2a1"; }
+.ri-volume-up-line:before { content: "\f2a2"; }
+.ri-volume-vibrate-fill:before { content: "\f2a3"; }
+.ri-volume-vibrate-line:before { content: "\f2a4"; }
+.ri-vuejs-fill:before { content: "\f2a5"; }
+.ri-vuejs-line:before { content: "\f2a6"; }
+.ri-walk-fill:before { content: "\f2a7"; }
+.ri-walk-line:before { content: "\f2a8"; }
+.ri-wallet-2-fill:before { content: "\f2a9"; }
+.ri-wallet-2-line:before { content: "\f2aa"; }
+.ri-wallet-3-fill:before { content: "\f2ab"; }
+.ri-wallet-3-line:before { content: "\f2ac"; }
+.ri-wallet-fill:before { content: "\f2ad"; }
+.ri-wallet-line:before { content: "\f2ae"; }
+.ri-water-flash-fill:before { content: "\f2af"; }
+.ri-water-flash-line:before { content: "\f2b0"; }
+.ri-webcam-fill:before { content: "\f2b1"; }
+.ri-webcam-line:before { content: "\f2b2"; }
+.ri-wechat-2-fill:before { content: "\f2b3"; }
+.ri-wechat-2-line:before { content: "\f2b4"; }
+.ri-wechat-fill:before { content: "\f2b5"; }
+.ri-wechat-line:before { content: "\f2b6"; }
+.ri-wechat-pay-fill:before { content: "\f2b7"; }
+.ri-wechat-pay-line:before { content: "\f2b8"; }
+.ri-weibo-fill:before { content: "\f2b9"; }
+.ri-weibo-line:before { content: "\f2ba"; }
+.ri-whatsapp-fill:before { content: "\f2bb"; }
+.ri-whatsapp-line:before { content: "\f2bc"; }
+.ri-wheelchair-fill:before { content: "\f2bd"; }
+.ri-wheelchair-line:before { content: "\f2be"; }
+.ri-wifi-fill:before { content: "\f2bf"; }
+.ri-wifi-line:before { content: "\f2c0"; }
+.ri-wifi-off-fill:before { content: "\f2c1"; }
+.ri-wifi-off-line:before { content: "\f2c2"; }
+.ri-window-2-fill:before { content: "\f2c3"; }
+.ri-window-2-line:before { content: "\f2c4"; }
+.ri-window-fill:before { content: "\f2c5"; }
+.ri-window-line:before { content: "\f2c6"; }
+.ri-windows-fill:before { content: "\f2c7"; }
+.ri-windows-line:before { content: "\f2c8"; }
+.ri-windy-fill:before { content: "\f2c9"; }
+.ri-windy-line:before { content: "\f2ca"; }
+.ri-wireless-charging-fill:before { content: "\f2cb"; }
+.ri-wireless-charging-line:before { content: "\f2cc"; }
+.ri-women-fill:before { content: "\f2cd"; }
+.ri-women-line:before { content: "\f2ce"; }
+.ri-wubi-input:before { content: "\f2cf"; }
+.ri-xbox-fill:before { content: "\f2d0"; }
+.ri-xbox-line:before { content: "\f2d1"; }
+.ri-xing-fill:before { content: "\f2d2"; }
+.ri-xing-line:before { content: "\f2d3"; }
+.ri-youtube-fill:before { content: "\f2d4"; }
+.ri-youtube-line:before { content: "\f2d5"; }
+.ri-zcool-fill:before { content: "\f2d6"; }
+.ri-zcool-line:before { content: "\f2d7"; }
+.ri-zhihu-fill:before { content: "\f2d8"; }
+.ri-zhihu-line:before { content: "\f2d9"; }
+.ri-zoom-in-fill:before { content: "\f2da"; }
+.ri-zoom-in-line:before { content: "\f2db"; }
+.ri-zoom-out-fill:before { content: "\f2dc"; }
+.ri-zoom-out-line:before { content: "\f2dd"; }
+.ri-zzz-fill:before { content: "\f2de"; }
+.ri-zzz-line:before { content: "\f2df"; }
+.ri-arrow-down-double-fill:before { content: "\f2e0"; }
+.ri-arrow-down-double-line:before { content: "\f2e1"; }
+.ri-arrow-left-double-fill:before { content: "\f2e2"; }
+.ri-arrow-left-double-line:before { content: "\f2e3"; }
+.ri-arrow-right-double-fill:before { content: "\f2e4"; }
+.ri-arrow-right-double-line:before { content: "\f2e5"; }
+.ri-arrow-turn-back-fill:before { content: "\f2e6"; }
+.ri-arrow-turn-back-line:before { content: "\f2e7"; }
+.ri-arrow-turn-forward-fill:before { content: "\f2e8"; }
+.ri-arrow-turn-forward-line:before { content: "\f2e9"; }
+.ri-arrow-up-double-fill:before { content: "\f2ea"; }
+.ri-arrow-up-double-line:before { content: "\f2eb"; }
+.ri-bard-fill:before { content: "\f2ec"; }
+.ri-bard-line:before { content: "\f2ed"; }
+.ri-bootstrap-fill:before { content: "\f2ee"; }
+.ri-bootstrap-line:before { content: "\f2ef"; }
+.ri-box-1-fill:before { content: "\f2f0"; }
+.ri-box-1-line:before { content: "\f2f1"; }
+.ri-box-2-fill:before { content: "\f2f2"; }
+.ri-box-2-line:before { content: "\f2f3"; }
+.ri-box-3-fill:before { content: "\f2f4"; }
+.ri-box-3-line:before { content: "\f2f5"; }
+.ri-brain-fill:before { content: "\f2f6"; }
+.ri-brain-line:before { content: "\f2f7"; }
+.ri-candle-fill:before { content: "\f2f8"; }
+.ri-candle-line:before { content: "\f2f9"; }
+.ri-cash-fill:before { content: "\f2fa"; }
+.ri-cash-line:before { content: "\f2fb"; }
+.ri-contract-left-fill:before { content: "\f2fc"; }
+.ri-contract-left-line:before { content: "\f2fd"; }
+.ri-contract-left-right-fill:before { content: "\f2fe"; }
+.ri-contract-left-right-line:before { content: "\f2ff"; }
+.ri-contract-right-fill:before { content: "\f300"; }
+.ri-contract-right-line:before { content: "\f301"; }
+.ri-contract-up-down-fill:before { content: "\f302"; }
+.ri-contract-up-down-line:before { content: "\f303"; }
+.ri-copilot-fill:before { content: "\f304"; }
+.ri-copilot-line:before { content: "\f305"; }
+.ri-corner-down-left-fill:before { content: "\f306"; }
+.ri-corner-down-left-line:before { content: "\f307"; }
+.ri-corner-down-right-fill:before { content: "\f308"; }
+.ri-corner-down-right-line:before { content: "\f309"; }
+.ri-corner-left-down-fill:before { content: "\f30a"; }
+.ri-corner-left-down-line:before { content: "\f30b"; }
+.ri-corner-left-up-fill:before { content: "\f30c"; }
+.ri-corner-left-up-line:before { content: "\f30d"; }
+.ri-corner-right-down-fill:before { content: "\f30e"; }
+.ri-corner-right-down-line:before { content: "\f30f"; }
+.ri-corner-right-up-fill:before { content: "\f310"; }
+.ri-corner-right-up-line:before { content: "\f311"; }
+.ri-corner-up-left-double-fill:before { content: "\f312"; }
+.ri-corner-up-left-double-line:before { content: "\f313"; }
+.ri-corner-up-left-fill:before { content: "\f314"; }
+.ri-corner-up-left-line:before { content: "\f315"; }
+.ri-corner-up-right-double-fill:before { content: "\f316"; }
+.ri-corner-up-right-double-line:before { content: "\f317"; }
+.ri-corner-up-right-fill:before { content: "\f318"; }
+.ri-corner-up-right-line:before { content: "\f319"; }
+.ri-cross-fill:before { content: "\f31a"; }
+.ri-cross-line:before { content: "\f31b"; }
+.ri-edge-new-fill:before { content: "\f31c"; }
+.ri-edge-new-line:before { content: "\f31d"; }
+.ri-equal-fill:before { content: "\f31e"; }
+.ri-equal-line:before { content: "\f31f"; }
+.ri-expand-left-fill:before { content: "\f320"; }
+.ri-expand-left-line:before { content: "\f321"; }
+.ri-expand-left-right-fill:before { content: "\f322"; }
+.ri-expand-left-right-line:before { content: "\f323"; }
+.ri-expand-right-fill:before { content: "\f324"; }
+.ri-expand-right-line:before { content: "\f325"; }
+.ri-expand-up-down-fill:before { content: "\f326"; }
+.ri-expand-up-down-line:before { content: "\f327"; }
+.ri-flickr-fill:before { content: "\f328"; }
+.ri-flickr-line:before { content: "\f329"; }
+.ri-forward-10-fill:before { content: "\f32a"; }
+.ri-forward-10-line:before { content: "\f32b"; }
+.ri-forward-15-fill:before { content: "\f32c"; }
+.ri-forward-15-line:before { content: "\f32d"; }
+.ri-forward-30-fill:before { content: "\f32e"; }
+.ri-forward-30-line:before { content: "\f32f"; }
+.ri-forward-5-fill:before { content: "\f330"; }
+.ri-forward-5-line:before { content: "\f331"; }
+.ri-graduation-cap-fill:before { content: "\f332"; }
+.ri-graduation-cap-line:before { content: "\f333"; }
+.ri-home-office-fill:before { content: "\f334"; }
+.ri-home-office-line:before { content: "\f335"; }
+.ri-hourglass-2-fill:before { content: "\f336"; }
+.ri-hourglass-2-line:before { content: "\f337"; }
+.ri-hourglass-fill:before { content: "\f338"; }
+.ri-hourglass-line:before { content: "\f339"; }
+.ri-javascript-fill:before { content: "\f33a"; }
+.ri-javascript-line:before { content: "\f33b"; }
+.ri-loop-left-fill:before { content: "\f33c"; }
+.ri-loop-left-line:before { content: "\f33d"; }
+.ri-loop-right-fill:before { content: "\f33e"; }
+.ri-loop-right-line:before { content: "\f33f"; }
+.ri-memories-fill:before { content: "\f340"; }
+.ri-memories-line:before { content: "\f341"; }
+.ri-meta-fill:before { content: "\f342"; }
+.ri-meta-line:before { content: "\f343"; }
+.ri-microsoft-loop-fill:before { content: "\f344"; }
+.ri-microsoft-loop-line:before { content: "\f345"; }
+.ri-nft-fill:before { content: "\f346"; }
+.ri-nft-line:before { content: "\f347"; }
+.ri-notion-fill:before { content: "\f348"; }
+.ri-notion-line:before { content: "\f349"; }
+.ri-openai-fill:before { content: "\f34a"; }
+.ri-openai-line:before { content: "\f34b"; }
+.ri-overline:before { content: "\f34c"; }
+.ri-p2p-fill:before { content: "\f34d"; }
+.ri-p2p-line:before { content: "\f34e"; }
+.ri-presentation-fill:before { content: "\f34f"; }
+.ri-presentation-line:before { content: "\f350"; }
+.ri-replay-10-fill:before { content: "\f351"; }
+.ri-replay-10-line:before { content: "\f352"; }
+.ri-replay-15-fill:before { content: "\f353"; }
+.ri-replay-15-line:before { content: "\f354"; }
+.ri-replay-30-fill:before { content: "\f355"; }
+.ri-replay-30-line:before { content: "\f356"; }
+.ri-replay-5-fill:before { content: "\f357"; }
+.ri-replay-5-line:before { content: "\f358"; }
+.ri-school-fill:before { content: "\f359"; }
+.ri-school-line:before { content: "\f35a"; }
+.ri-shining-2-fill:before { content: "\f35b"; }
+.ri-shining-2-line:before { content: "\f35c"; }
+.ri-shining-fill:before { content: "\f35d"; }
+.ri-shining-line:before { content: "\f35e"; }
+.ri-sketching:before { content: "\f35f"; }
+.ri-skip-down-fill:before { content: "\f360"; }
+.ri-skip-down-line:before { content: "\f361"; }
+.ri-skip-left-fill:before { content: "\f362"; }
+.ri-skip-left-line:before { content: "\f363"; }
+.ri-skip-right-fill:before { content: "\f364"; }
+.ri-skip-right-line:before { content: "\f365"; }
+.ri-skip-up-fill:before { content: "\f366"; }
+.ri-skip-up-line:before { content: "\f367"; }
+.ri-slow-down-fill:before { content: "\f368"; }
+.ri-slow-down-line:before { content: "\f369"; }
+.ri-sparkling-2-fill:before { content: "\f36a"; }
+.ri-sparkling-2-line:before { content: "\f36b"; }
+.ri-sparkling-fill:before { content: "\f36c"; }
+.ri-sparkling-line:before { content: "\f36d"; }
+.ri-speak-fill:before { content: "\f36e"; }
+.ri-speak-line:before { content: "\f36f"; }
+.ri-speed-up-fill:before { content: "\f370"; }
+.ri-speed-up-line:before { content: "\f371"; }
+.ri-tiktok-fill:before { content: "\f372"; }
+.ri-tiktok-line:before { content: "\f373"; }
+.ri-token-swap-fill:before { content: "\f374"; }
+.ri-token-swap-line:before { content: "\f375"; }
+.ri-unpin-fill:before { content: "\f376"; }
+.ri-unpin-line:before { content: "\f377"; }
+.ri-wechat-channels-fill:before { content: "\f378"; }
+.ri-wechat-channels-line:before { content: "\f379"; }
+.ri-wordpress-fill:before { content: "\f37a"; }
+.ri-wordpress-line:before { content: "\f37b"; }
+.ri-blender-fill:before { content: "\f37c"; }
+.ri-blender-line:before { content: "\f37d"; }
+.ri-emoji-sticker-fill:before { content: "\f37e"; }
+.ri-emoji-sticker-line:before { content: "\f37f"; }
+.ri-git-close-pull-request-fill:before { content: "\f380"; }
+.ri-git-close-pull-request-line:before { content: "\f381"; }
+.ri-instance-fill:before { content: "\f382"; }
+.ri-instance-line:before { content: "\f383"; }
+.ri-megaphone-fill:before { content: "\f384"; }
+.ri-megaphone-line:before { content: "\f385"; }
+.ri-pass-expired-fill:before { content: "\f386"; }
+.ri-pass-expired-line:before { content: "\f387"; }
+.ri-pass-pending-fill:before { content: "\f388"; }
+.ri-pass-pending-line:before { content: "\f389"; }
+.ri-pass-valid-fill:before { content: "\f38a"; }
+.ri-pass-valid-line:before { content: "\f38b"; }
+.ri-ai-generate:before { content: "\f38c"; }
+.ri-calendar-close-fill:before { content: "\f38d"; }
+.ri-calendar-close-line:before { content: "\f38e"; }
+.ri-draggable:before { content: "\f38f"; }
+.ri-font-family:before { content: "\f390"; }
+.ri-font-mono:before { content: "\f391"; }
+.ri-font-sans-serif:before { content: "\f392"; }
+.ri-hard-drive-3-fill:before { content: "\f393"; }
+.ri-hard-drive-3-line:before { content: "\f394"; }
+.ri-kick-fill:before { content: "\f395"; }
+.ri-kick-line:before { content: "\f396"; }
+.ri-list-check-3:before { content: "\f397"; }
+.ri-list-indefinite:before { content: "\f398"; }
+.ri-list-ordered-2:before { content: "\f399"; }
+.ri-list-radio:before { content: "\f39a"; }
+.ri-openbase-fill:before { content: "\f39b"; }
+.ri-openbase-line:before { content: "\f39c"; }
+.ri-planet-fill:before { content: "\f39d"; }
+.ri-planet-line:before { content: "\f39e"; }
+.ri-prohibited-fill:before { content: "\f39f"; }
+.ri-prohibited-line:before { content: "\f3a0"; }
+.ri-quote-text:before { content: "\f3a1"; }
+.ri-seo-fill:before { content: "\f3a2"; }
+.ri-seo-line:before { content: "\f3a3"; }
+.ri-slash-commands:before { content: "\f3a4"; }
+.ri-archive-2-fill:before { content: "\f3a5"; }
+.ri-archive-2-line:before { content: "\f3a6"; }
+.ri-inbox-2-fill:before { content: "\f3a7"; }
+.ri-inbox-2-line:before { content: "\f3a8"; }
+.ri-shake-hands-fill:before { content: "\f3a9"; }
+.ri-shake-hands-line:before { content: "\f3aa"; }
+.ri-supabase-fill:before { content: "\f3ab"; }
+.ri-supabase-line:before { content: "\f3ac"; }
+.ri-water-percent-fill:before { content: "\f3ad"; }
+.ri-water-percent-line:before { content: "\f3ae"; }
+.ri-yuque-fill:before { content: "\f3af"; }
+.ri-yuque-line:before { content: "\f3b0"; }
+.ri-crosshair-2-fill:before { content: "\f3b1"; }
+.ri-crosshair-2-line:before { content: "\f3b2"; }
+.ri-crosshair-fill:before { content: "\f3b3"; }
+.ri-crosshair-line:before { content: "\f3b4"; }
+.ri-file-close-fill:before { content: "\f3b5"; }
+.ri-file-close-line:before { content: "\f3b6"; }
+.ri-infinity-fill:before { content: "\f3b7"; }
+.ri-infinity-line:before { content: "\f3b8"; }
+.ri-rfid-fill:before { content: "\f3b9"; }
+.ri-rfid-line:before { content: "\f3ba"; }
+.ri-slash-commands-2:before { content: "\f3bb"; }
+.ri-user-forbid-fill:before { content: "\f3bc"; }
+.ri-user-forbid-line:before { content: "\f3bd"; }
+.ri-beer-fill:before { content: "\f3be"; }
+.ri-beer-line:before { content: "\f3bf"; }
+.ri-circle-fill:before { content: "\f3c0"; }
+.ri-circle-line:before { content: "\f3c1"; }
+.ri-dropdown-list:before { content: "\f3c2"; }
+.ri-file-image-fill:before { content: "\f3c3"; }
+.ri-file-image-line:before { content: "\f3c4"; }
+.ri-file-pdf-2-fill:before { content: "\f3c5"; }
+.ri-file-pdf-2-line:before { content: "\f3c6"; }
+.ri-file-video-fill:before { content: "\f3c7"; }
+.ri-file-video-line:before { content: "\f3c8"; }
+.ri-folder-image-fill:before { content: "\f3c9"; }
+.ri-folder-image-line:before { content: "\f3ca"; }
+.ri-folder-video-fill:before { content: "\f3cb"; }
+.ri-folder-video-line:before { content: "\f3cc"; }
+.ri-hexagon-fill:before { content: "\f3cd"; }
+.ri-hexagon-line:before { content: "\f3ce"; }
+.ri-menu-search-fill:before { content: "\f3cf"; }
+.ri-menu-search-line:before { content: "\f3d0"; }
+.ri-octagon-fill:before { content: "\f3d1"; }
+.ri-octagon-line:before { content: "\f3d2"; }
+.ri-pentagon-fill:before { content: "\f3d3"; }
+.ri-pentagon-line:before { content: "\f3d4"; }
+.ri-rectangle-fill:before { content: "\f3d5"; }
+.ri-rectangle-line:before { content: "\f3d6"; }
+.ri-robot-2-fill:before { content: "\f3d7"; }
+.ri-robot-2-line:before { content: "\f3d8"; }
+.ri-shapes-fill:before { content: "\f3d9"; }
+.ri-shapes-line:before { content: "\f3da"; }
+.ri-square-fill:before { content: "\f3db"; }
+.ri-square-line:before { content: "\f3dc"; }
+.ri-tent-fill:before { content: "\f3dd"; }
+.ri-tent-line:before { content: "\f3de"; }
+.ri-threads-fill:before { content: "\f3df"; }
+.ri-threads-line:before { content: "\f3e0"; }
+.ri-tree-fill:before { content: "\f3e1"; }
+.ri-tree-line:before { content: "\f3e2"; }
+.ri-triangle-fill:before { content: "\f3e3"; }
+.ri-triangle-line:before { content: "\f3e4"; }
+.ri-twitter-x-fill:before { content: "\f3e5"; }
+.ri-twitter-x-line:before { content: "\f3e6"; }
+.ri-verified-badge-fill:before { content: "\f3e7"; }
+.ri-verified-badge-line:before { content: "\f3e8"; }
+.ri-armchair-fill:before { content: "\f3e9"; }
+.ri-armchair-line:before { content: "\f3ea"; }
+.ri-bnb-fill:before { content: "\f3eb"; }
+.ri-bnb-line:before { content: "\f3ec"; }
+.ri-bread-fill:before { content: "\f3ed"; }
+.ri-bread-line:before { content: "\f3ee"; }
+.ri-btc-fill:before { content: "\f3ef"; }
+.ri-btc-line:before { content: "\f3f0"; }
+.ri-calendar-schedule-fill:before { content: "\f3f1"; }
+.ri-calendar-schedule-line:before { content: "\f3f2"; }
+.ri-dice-1-fill:before { content: "\f3f3"; }
+.ri-dice-1-line:before { content: "\f3f4"; }
+.ri-dice-2-fill:before { content: "\f3f5"; }
+.ri-dice-2-line:before { content: "\f3f6"; }
+.ri-dice-3-fill:before { content: "\f3f7"; }
+.ri-dice-3-line:before { content: "\f3f8"; }
+.ri-dice-4-fill:before { content: "\f3f9"; }
+.ri-dice-4-line:before { content: "\f3fa"; }
+.ri-dice-5-fill:before { content: "\f3fb"; }
+.ri-dice-5-line:before { content: "\f3fc"; }
+.ri-dice-6-fill:before { content: "\f3fd"; }
+.ri-dice-6-line:before { content: "\f3fe"; }
+.ri-dice-fill:before { content: "\f3ff"; }
+.ri-dice-line:before { content: "\f400"; }
+.ri-drinks-fill:before { content: "\f401"; }
+.ri-drinks-line:before { content: "\f402"; }
+.ri-equalizer-2-fill:before { content: "\f403"; }
+.ri-equalizer-2-line:before { content: "\f404"; }
+.ri-equalizer-3-fill:before { content: "\f405"; }
+.ri-equalizer-3-line:before { content: "\f406"; }
+.ri-eth-fill:before { content: "\f407"; }
+.ri-eth-line:before { content: "\f408"; }
+.ri-flower-fill:before { content: "\f409"; }
+.ri-flower-line:before { content: "\f40a"; }
+.ri-glasses-2-fill:before { content: "\f40b"; }
+.ri-glasses-2-line:before { content: "\f40c"; }
+.ri-glasses-fill:before { content: "\f40d"; }
+.ri-glasses-line:before { content: "\f40e"; }
+.ri-goggles-fill:before { content: "\f40f"; }
+.ri-goggles-line:before { content: "\f410"; }
+.ri-image-circle-fill:before { content: "\f411"; }
+.ri-image-circle-line:before { content: "\f412"; }
+.ri-info-i:before { content: "\f413"; }
+.ri-money-rupee-circle-fill:before { content: "\f414"; }
+.ri-money-rupee-circle-line:before { content: "\f415"; }
+.ri-news-fill:before { content: "\f416"; }
+.ri-news-line:before { content: "\f417"; }
+.ri-robot-3-fill:before { content: "\f418"; }
+.ri-robot-3-line:before { content: "\f419"; }
+.ri-share-2-fill:before { content: "\f41a"; }
+.ri-share-2-line:before { content: "\f41b"; }
+.ri-sofa-fill:before { content: "\f41c"; }
+.ri-sofa-line:before { content: "\f41d"; }
+.ri-svelte-fill:before { content: "\f41e"; }
+.ri-svelte-line:before { content: "\f41f"; }
+.ri-vk-fill:before { content: "\f420"; }
+.ri-vk-line:before { content: "\f421"; }
+.ri-xrp-fill:before { content: "\f422"; }
+.ri-xrp-line:before { content: "\f423"; }
+.ri-xtz-fill:before { content: "\f424"; }
+.ri-xtz-line:before { content: "\f425"; }
+.ri-archive-stack-fill:before { content: "\f426"; }
+.ri-archive-stack-line:before { content: "\f427"; }
+.ri-bowl-fill:before { content: "\f428"; }
+.ri-bowl-line:before { content: "\f429"; }
+.ri-calendar-view:before { content: "\f42a"; }
+.ri-carousel-view:before { content: "\f42b"; }
+.ri-code-block:before { content: "\f42c"; }
+.ri-color-filter-fill:before { content: "\f42d"; }
+.ri-color-filter-line:before { content: "\f42e"; }
+.ri-contacts-book-3-fill:before { content: "\f42f"; }
+.ri-contacts-book-3-line:before { content: "\f430"; }
+.ri-contract-fill:before { content: "\f431"; }
+.ri-contract-line:before { content: "\f432"; }
+.ri-drinks-2-fill:before { content: "\f433"; }
+.ri-drinks-2-line:before { content: "\f434"; }
+.ri-export-fill:before { content: "\f435"; }
+.ri-export-line:before { content: "\f436"; }
+.ri-file-check-fill:before { content: "\f437"; }
+.ri-file-check-line:before { content: "\f438"; }
+.ri-focus-mode:before { content: "\f439"; }
+.ri-folder-6-fill:before { content: "\f43a"; }
+.ri-folder-6-line:before { content: "\f43b"; }
+.ri-folder-check-fill:before { content: "\f43c"; }
+.ri-folder-check-line:before { content: "\f43d"; }
+.ri-folder-close-fill:before { content: "\f43e"; }
+.ri-folder-close-line:before { content: "\f43f"; }
+.ri-folder-cloud-fill:before { content: "\f440"; }
+.ri-folder-cloud-line:before { content: "\f441"; }
+.ri-gallery-view-2:before { content: "\f442"; }
+.ri-gallery-view:before { content: "\f443"; }
+.ri-hand:before { content: "\f444"; }
+.ri-import-fill:before { content: "\f445"; }
+.ri-import-line:before { content: "\f446"; }
+.ri-information-2-fill:before { content: "\f447"; }
+.ri-information-2-line:before { content: "\f448"; }
+.ri-kanban-view-2:before { content: "\f449"; }
+.ri-kanban-view:before { content: "\f44a"; }
+.ri-list-view:before { content: "\f44b"; }
+.ri-lock-star-fill:before { content: "\f44c"; }
+.ri-lock-star-line:before { content: "\f44d"; }
+.ri-puzzle-2-fill:before { content: "\f44e"; }
+.ri-puzzle-2-line:before { content: "\f44f"; }
+.ri-puzzle-fill:before { content: "\f450"; }
+.ri-puzzle-line:before { content: "\f451"; }
+.ri-ram-2-fill:before { content: "\f452"; }
+.ri-ram-2-line:before { content: "\f453"; }
+.ri-ram-fill:before { content: "\f454"; }
+.ri-ram-line:before { content: "\f455"; }
+.ri-receipt-fill:before { content: "\f456"; }
+.ri-receipt-line:before { content: "\f457"; }
+.ri-shadow-fill:before { content: "\f458"; }
+.ri-shadow-line:before { content: "\f459"; }
+.ri-sidebar-fold-fill:before { content: "\f45a"; }
+.ri-sidebar-fold-line:before { content: "\f45b"; }
+.ri-sidebar-unfold-fill:before { content: "\f45c"; }
+.ri-sidebar-unfold-line:before { content: "\f45d"; }
+.ri-slideshow-view:before { content: "\f45e"; }
+.ri-sort-alphabet-asc:before { content: "\f45f"; }
+.ri-sort-alphabet-desc:before { content: "\f460"; }
+.ri-sort-number-asc:before { content: "\f461"; }
+.ri-sort-number-desc:before { content: "\f462"; }
+.ri-stacked-view:before { content: "\f463"; }
+.ri-sticky-note-add-fill:before { content: "\f464"; }
+.ri-sticky-note-add-line:before { content: "\f465"; }
+.ri-swap-2-fill:before { content: "\f466"; }
+.ri-swap-2-line:before { content: "\f467"; }
+.ri-swap-3-fill:before { content: "\f468"; }
+.ri-swap-3-line:before { content: "\f469"; }
+.ri-table-3:before { content: "\f46a"; }
+.ri-table-view:before { content: "\f46b"; }
+.ri-text-block:before { content: "\f46c"; }
+.ri-text-snippet:before { content: "\f46d"; }
+.ri-timeline-view:before { content: "\f46e"; }
+.ri-blogger-fill:before { content: "\f46f"; }
+.ri-blogger-line:before { content: "\f470"; }
+.ri-chat-thread-fill:before { content: "\f471"; }
+.ri-chat-thread-line:before { content: "\f472"; }
+.ri-discount-percent-fill:before { content: "\f473"; }
+.ri-discount-percent-line:before { content: "\f474"; }
+.ri-exchange-2-fill:before { content: "\f475"; }
+.ri-exchange-2-line:before { content: "\f476"; }
+.ri-git-fork-fill:before { content: "\f477"; }
+.ri-git-fork-line:before { content: "\f478"; }
+.ri-input-field:before { content: "\f479"; }
+.ri-progress-1-fill:before { content: "\f47a"; }
+.ri-progress-1-line:before { content: "\f47b"; }
+.ri-progress-2-fill:before { content: "\f47c"; }
+.ri-progress-2-line:before { content: "\f47d"; }
+.ri-progress-3-fill:before { content: "\f47e"; }
+.ri-progress-3-line:before { content: "\f47f"; }
+.ri-progress-4-fill:before { content: "\f480"; }
+.ri-progress-4-line:before { content: "\f481"; }
+.ri-progress-5-fill:before { content: "\f482"; }
+.ri-progress-5-line:before { content: "\f483"; }
+.ri-progress-6-fill:before { content: "\f484"; }
+.ri-progress-6-line:before { content: "\f485"; }
+.ri-progress-7-fill:before { content: "\f486"; }
+.ri-progress-7-line:before { content: "\f487"; }
+.ri-progress-8-fill:before { content: "\f488"; }
+.ri-progress-8-line:before { content: "\f489"; }
+.ri-remix-run-fill:before { content: "\f48a"; }
+.ri-remix-run-line:before { content: "\f48b"; }
+.ri-signpost-fill:before { content: "\f48c"; }
+.ri-signpost-line:before { content: "\f48d"; }
+.ri-time-zone-fill:before { content: "\f48e"; }
+.ri-time-zone-line:before { content: "\f48f"; }
+.ri-arrow-down-wide-fill:before { content: "\f490"; }
+.ri-arrow-down-wide-line:before { content: "\f491"; }
+.ri-arrow-left-wide-fill:before { content: "\f492"; }
+.ri-arrow-left-wide-line:before { content: "\f493"; }
+.ri-arrow-right-wide-fill:before { content: "\f494"; }
+.ri-arrow-right-wide-line:before { content: "\f495"; }
+.ri-arrow-up-wide-fill:before { content: "\f496"; }
+.ri-arrow-up-wide-line:before { content: "\f497"; }
+.ri-bluesky-fill:before { content: "\f498"; }
+.ri-bluesky-line:before { content: "\f499"; }
+.ri-expand-height-fill:before { content: "\f49a"; }
+.ri-expand-height-line:before { content: "\f49b"; }
+.ri-expand-width-fill:before { content: "\f49c"; }
+.ri-expand-width-line:before { content: "\f49d"; }
+.ri-forward-end-fill:before { content: "\f49e"; }
+.ri-forward-end-line:before { content: "\f49f"; }
+.ri-forward-end-mini-fill:before { content: "\f4a0"; }
+.ri-forward-end-mini-line:before { content: "\f4a1"; }
+.ri-friendica-fill:before { content: "\f4a2"; }
+.ri-friendica-line:before { content: "\f4a3"; }
+.ri-git-pr-draft-fill:before { content: "\f4a4"; }
+.ri-git-pr-draft-line:before { content: "\f4a5"; }
+.ri-play-reverse-fill:before { content: "\f4a6"; }
+.ri-play-reverse-line:before { content: "\f4a7"; }
+.ri-play-reverse-mini-fill:before { content: "\f4a8"; }
+.ri-play-reverse-mini-line:before { content: "\f4a9"; }
+.ri-rewind-start-fill:before { content: "\f4aa"; }
+.ri-rewind-start-line:before { content: "\f4ab"; }
+.ri-rewind-start-mini-fill:before { content: "\f4ac"; }
+.ri-rewind-start-mini-line:before { content: "\f4ad"; }
+.ri-scroll-to-bottom-fill:before { content: "\f4ae"; }
+.ri-scroll-to-bottom-line:before { content: "\f4af"; }
+.ri-add-large-fill:before { content: "\f4b0"; }
+.ri-add-large-line:before { content: "\f4b1"; }
+.ri-aed-electrodes-fill:before { content: "\f4b2"; }
+.ri-aed-electrodes-line:before { content: "\f4b3"; }
+.ri-aed-fill:before { content: "\f4b4"; }
+.ri-aed-line:before { content: "\f4b5"; }
+.ri-alibaba-cloud-fill:before { content: "\f4b6"; }
+.ri-alibaba-cloud-line:before { content: "\f4b7"; }
+.ri-align-item-bottom-fill:before { content: "\f4b8"; }
+.ri-align-item-bottom-line:before { content: "\f4b9"; }
+.ri-align-item-horizontal-center-fill:before { content: "\f4ba"; }
+.ri-align-item-horizontal-center-line:before { content: "\f4bb"; }
+.ri-align-item-left-fill:before { content: "\f4bc"; }
+.ri-align-item-left-line:before { content: "\f4bd"; }
+.ri-align-item-right-fill:before { content: "\f4be"; }
+.ri-align-item-right-line:before { content: "\f4bf"; }
+.ri-align-item-top-fill:before { content: "\f4c0"; }
+.ri-align-item-top-line:before { content: "\f4c1"; }
+.ri-align-item-vertical-center-fill:before { content: "\f4c2"; }
+.ri-align-item-vertical-center-line:before { content: "\f4c3"; }
+.ri-apps-2-add-fill:before { content: "\f4c4"; }
+.ri-apps-2-add-line:before { content: "\f4c5"; }
+.ri-close-large-fill:before { content: "\f4c6"; }
+.ri-close-large-line:before { content: "\f4c7"; }
+.ri-collapse-diagonal-2-fill:before { content: "\f4c8"; }
+.ri-collapse-diagonal-2-line:before { content: "\f4c9"; }
+.ri-collapse-diagonal-fill:before { content: "\f4ca"; }
+.ri-collapse-diagonal-line:before { content: "\f4cb"; }
+.ri-dashboard-horizontal-fill:before { content: "\f4cc"; }
+.ri-dashboard-horizontal-line:before { content: "\f4cd"; }
+.ri-expand-diagonal-2-fill:before { content: "\f4ce"; }
+.ri-expand-diagonal-2-line:before { content: "\f4cf"; }
+.ri-expand-diagonal-fill:before { content: "\f4d0"; }
+.ri-expand-diagonal-line:before { content: "\f4d1"; }
+.ri-firebase-fill:before { content: "\f4d2"; }
+.ri-firebase-line:before { content: "\f4d3"; }
+.ri-flip-horizontal-2-fill:before { content: "\f4d4"; }
+.ri-flip-horizontal-2-line:before { content: "\f4d5"; }
+.ri-flip-horizontal-fill:before { content: "\f4d6"; }
+.ri-flip-horizontal-line:before { content: "\f4d7"; }
+.ri-flip-vertical-2-fill:before { content: "\f4d8"; }
+.ri-flip-vertical-2-line:before { content: "\f4d9"; }
+.ri-flip-vertical-fill:before { content: "\f4da"; }
+.ri-flip-vertical-line:before { content: "\f4db"; }
+.ri-formula:before { content: "\f4dc"; }
+.ri-function-add-fill:before { content: "\f4dd"; }
+.ri-function-add-line:before { content: "\f4de"; }
+.ri-goblet-2-fill:before { content: "\f4df"; }
+.ri-goblet-2-line:before { content: "\f4e0"; }
+.ri-golf-ball-fill:before { content: "\f4e1"; }
+.ri-golf-ball-line:before { content: "\f4e2"; }
+.ri-group-3-fill:before { content: "\f4e3"; }
+.ri-group-3-line:before { content: "\f4e4"; }
+.ri-heart-add-2-fill:before { content: "\f4e5"; }
+.ri-heart-add-2-line:before { content: "\f4e6"; }
+.ri-id-card-fill:before { content: "\f4e7"; }
+.ri-id-card-line:before { content: "\f4e8"; }
+.ri-information-off-fill:before { content: "\f4e9"; }
+.ri-information-off-line:before { content: "\f4ea"; }
+.ri-java-fill:before { content: "\f4eb"; }
+.ri-java-line:before { content: "\f4ec"; }
+.ri-layout-grid-2-fill:before { content: "\f4ed"; }
+.ri-layout-grid-2-line:before { content: "\f4ee"; }
+.ri-layout-horizontal-fill:before { content: "\f4ef"; }
+.ri-layout-horizontal-line:before { content: "\f4f0"; }
+.ri-layout-vertical-fill:before { content: "\f4f1"; }
+.ri-layout-vertical-line:before { content: "\f4f2"; }
+.ri-menu-fold-2-fill:before { content: "\f4f3"; }
+.ri-menu-fold-2-line:before { content: "\f4f4"; }
+.ri-menu-fold-3-fill:before { content: "\f4f5"; }
+.ri-menu-fold-3-line:before { content: "\f4f6"; }
+.ri-menu-fold-4-fill:before { content: "\f4f7"; }
+.ri-menu-fold-4-line:before { content: "\f4f8"; }
+.ri-menu-unfold-2-fill:before { content: "\f4f9"; }
+.ri-menu-unfold-2-line:before { content: "\f4fa"; }
+.ri-menu-unfold-3-fill:before { content: "\f4fb"; }
+.ri-menu-unfold-3-line:before { content: "\f4fc"; }
+.ri-menu-unfold-4-fill:before { content: "\f4fd"; }
+.ri-menu-unfold-4-line:before { content: "\f4fe"; }
+.ri-mobile-download-fill:before { content: "\f4ff"; }
+.ri-mobile-download-line:before { content: "\f500"; }
+.ri-nextjs-fill:before { content: "\f501"; }
+.ri-nextjs-line:before { content: "\f502"; }
+.ri-nodejs-fill:before { content: "\f503"; }
+.ri-nodejs-line:before { content: "\f504"; }
+.ri-pause-large-fill:before { content: "\f505"; }
+.ri-pause-large-line:before { content: "\f506"; }
+.ri-play-large-fill:before { content: "\f507"; }
+.ri-play-large-line:before { content: "\f508"; }
+.ri-play-reverse-large-fill:before { content: "\f509"; }
+.ri-play-reverse-large-line:before { content: "\f50a"; }
+.ri-police-badge-fill:before { content: "\f50b"; }
+.ri-police-badge-line:before { content: "\f50c"; }
+.ri-prohibited-2-fill:before { content: "\f50d"; }
+.ri-prohibited-2-line:before { content: "\f50e"; }
+.ri-shopping-bag-4-fill:before { content: "\f50f"; }
+.ri-shopping-bag-4-line:before { content: "\f510"; }
+.ri-snowflake-fill:before { content: "\f511"; }
+.ri-snowflake-line:before { content: "\f512"; }
+.ri-square-root:before { content: "\f513"; }
+.ri-stop-large-fill:before { content: "\f514"; }
+.ri-stop-large-line:before { content: "\f515"; }
+.ri-tailwind-css-fill:before { content: "\f516"; }
+.ri-tailwind-css-line:before { content: "\f517"; }
+.ri-tooth-fill:before { content: "\f518"; }
+.ri-tooth-line:before { content: "\f519"; }
+.ri-video-off-fill:before { content: "\f51a"; }
+.ri-video-off-line:before { content: "\f51b"; }
+.ri-video-on-fill:before { content: "\f51c"; }
+.ri-video-on-line:before { content: "\f51d"; }
+.ri-webhook-fill:before { content: "\f51e"; }
+.ri-webhook-line:before { content: "\f51f"; }
+.ri-weight-fill:before { content: "\f520"; }
+.ri-weight-line:before { content: "\f521"; }
+.ri-book-shelf-fill:before { content: "\f522"; }
+.ri-book-shelf-line:before { content: "\f523"; }
+.ri-brain-2-fill:before { content: "\f524"; }
+.ri-brain-2-line:before { content: "\f525"; }
+.ri-chat-search-fill:before { content: "\f526"; }
+.ri-chat-search-line:before { content: "\f527"; }
+.ri-chat-unread-fill:before { content: "\f528"; }
+.ri-chat-unread-line:before { content: "\f529"; }
+.ri-collapse-horizontal-fill:before { content: "\f52a"; }
+.ri-collapse-horizontal-line:before { content: "\f52b"; }
+.ri-collapse-vertical-fill:before { content: "\f52c"; }
+.ri-collapse-vertical-line:before { content: "\f52d"; }
+.ri-dna-fill:before { content: "\f52e"; }
+.ri-dna-line:before { content: "\f52f"; }
+.ri-dropper-fill:before { content: "\f530"; }
+.ri-dropper-line:before { content: "\f531"; }
+.ri-expand-diagonal-s-2-fill:before { content: "\f532"; }
+.ri-expand-diagonal-s-2-line:before { content: "\f533"; }
+.ri-expand-diagonal-s-fill:before { content: "\f534"; }
+.ri-expand-diagonal-s-line:before { content: "\f535"; }
+.ri-expand-horizontal-fill:before { content: "\f536"; }
+.ri-expand-horizontal-line:before { content: "\f537"; }
+.ri-expand-horizontal-s-fill:before { content: "\f538"; }
+.ri-expand-horizontal-s-line:before { content: "\f539"; }
+.ri-expand-vertical-fill:before { content: "\f53a"; }
+.ri-expand-vertical-line:before { content: "\f53b"; }
+.ri-expand-vertical-s-fill:before { content: "\f53c"; }
+.ri-expand-vertical-s-line:before { content: "\f53d"; }
+.ri-gemini-fill:before { content: "\f53e"; }
+.ri-gemini-line:before { content: "\f53f"; }
+.ri-reset-left-fill:before { content: "\f540"; }
+.ri-reset-left-line:before { content: "\f541"; }
+.ri-reset-right-fill:before { content: "\f542"; }
+.ri-reset-right-line:before { content: "\f543"; }
+.ri-stairs-fill:before { content: "\f544"; }
+.ri-stairs-line:before { content: "\f545"; }
+.ri-telegram-2-fill:before { content: "\f546"; }
+.ri-telegram-2-line:before { content: "\f547"; }
+.ri-triangular-flag-fill:before { content: "\f548"; }
+.ri-triangular-flag-line:before { content: "\f549"; }
+.ri-user-minus-fill:before { content: "\f54a"; }
+.ri-user-minus-line:before { content: "\f54b"; }
+.ri-account-box-2-fill:before { content: "\f54c"; }
+.ri-account-box-2-line:before { content: "\f54d"; }
+.ri-account-circle-2-fill:before { content: "\f54e"; }
+.ri-account-circle-2-line:before { content: "\f54f"; }
+.ri-alarm-snooze-fill:before { content: "\f550"; }
+.ri-alarm-snooze-line:before { content: "\f551"; }
+.ri-arrow-down-box-fill:before { content: "\f552"; }
+.ri-arrow-down-box-line:before { content: "\f553"; }
+.ri-arrow-left-box-fill:before { content: "\f554"; }
+.ri-arrow-left-box-line:before { content: "\f555"; }
+.ri-arrow-left-down-box-fill:before { content: "\f556"; }
+.ri-arrow-left-down-box-line:before { content: "\f557"; }
+.ri-arrow-left-up-box-fill:before { content: "\f558"; }
+.ri-arrow-left-up-box-line:before { content: "\f559"; }
+.ri-arrow-right-box-fill:before { content: "\f55a"; }
+.ri-arrow-right-box-line:before { content: "\f55b"; }
+.ri-arrow-right-down-box-fill:before { content: "\f55c"; }
+.ri-arrow-right-down-box-line:before { content: "\f55d"; }
+.ri-arrow-right-up-box-fill:before { content: "\f55e"; }
+.ri-arrow-right-up-box-line:before { content: "\f55f"; }
+.ri-arrow-up-box-fill:before { content: "\f560"; }
+.ri-arrow-up-box-line:before { content: "\f561"; }
+.ri-bar-chart-box-ai-fill:before { content: "\f562"; }
+.ri-bar-chart-box-ai-line:before { content: "\f563"; }
+.ri-brush-ai-fill:before { content: "\f564"; }
+.ri-brush-ai-line:before { content: "\f565"; }
+.ri-camera-ai-fill:before { content: "\f566"; }
+.ri-camera-ai-line:before { content: "\f567"; }
+.ri-chat-ai-fill:before { content: "\f568"; }
+.ri-chat-ai-line:before { content: "\f569"; }
+.ri-chat-smile-ai-fill:before { content: "\f56a"; }
+.ri-chat-smile-ai-line:before { content: "\f56b"; }
+.ri-chat-voice-ai-fill:before { content: "\f56c"; }
+.ri-chat-voice-ai-line:before { content: "\f56d"; }
+.ri-code-ai-fill:before { content: "\f56e"; }
+.ri-code-ai-line:before { content: "\f56f"; }
+.ri-color-filter-ai-fill:before { content: "\f570"; }
+.ri-color-filter-ai-line:before { content: "\f571"; }
+.ri-custom-size:before { content: "\f572"; }
+.ri-fediverse-fill:before { content: "\f573"; }
+.ri-fediverse-line:before { content: "\f574"; }
+.ri-flag-off-fill:before { content: "\f575"; }
+.ri-flag-off-line:before { content: "\f576"; }
+.ri-home-9-fill:before { content: "\f577"; }
+.ri-home-9-line:before { content: "\f578"; }
+.ri-image-ai-fill:before { content: "\f579"; }
+.ri-image-ai-line:before { content: "\f57a"; }
+.ri-image-circle-ai-fill:before { content: "\f57b"; }
+.ri-image-circle-ai-line:before { content: "\f57c"; }
+.ri-info-card-fill:before { content: "\f57d"; }
+.ri-info-card-line:before { content: "\f57e"; }
+.ri-landscape-ai-fill:before { content: "\f57f"; }
+.ri-landscape-ai-line:before { content: "\f580"; }
+.ri-letter-spacing-2:before { content: "\f581"; }
+.ri-line-height-2:before { content: "\f582"; }
+.ri-mail-ai-fill:before { content: "\f583"; }
+.ri-mail-ai-line:before { content: "\f584"; }
+.ri-mic-2-ai-fill:before { content: "\f585"; }
+.ri-mic-2-ai-line:before { content: "\f586"; }
+.ri-mic-ai-fill:before { content: "\f587"; }
+.ri-mic-ai-line:before { content: "\f588"; }
+.ri-movie-ai-fill:before { content: "\f589"; }
+.ri-movie-ai-line:before { content: "\f58a"; }
+.ri-music-ai-fill:before { content: "\f58b"; }
+.ri-music-ai-line:before { content: "\f58c"; }
+.ri-notification-snooze-fill:before { content: "\f58d"; }
+.ri-notification-snooze-line:before { content: "\f58e"; }
+.ri-php-fill:before { content: "\f58f"; }
+.ri-php-line:before { content: "\f590"; }
+.ri-pix-fill:before { content: "\f591"; }
+.ri-pix-line:before { content: "\f592"; }
+.ri-pulse-ai-fill:before { content: "\f593"; }
+.ri-pulse-ai-line:before { content: "\f594"; }
+.ri-quill-pen-ai-fill:before { content: "\f595"; }
+.ri-quill-pen-ai-line:before { content: "\f596"; }
+.ri-speak-ai-fill:before { content: "\f597"; }
+.ri-speak-ai-line:before { content: "\f598"; }
+.ri-star-off-fill:before { content: "\f599"; }
+.ri-star-off-line:before { content: "\f59a"; }
+.ri-translate-ai-2:before { content: "\f59b"; }
+.ri-translate-ai:before { content: "\f59c"; }
+.ri-user-community-fill:before { content: "\f59d"; }
+.ri-user-community-line:before { content: "\f59e"; }
+.ri-vercel-fill:before { content: "\f59f"; }
+.ri-vercel-line:before { content: "\f5a0"; }
+.ri-video-ai-fill:before { content: "\f5a1"; }
+.ri-video-ai-line:before { content: "\f5a2"; }
+.ri-video-on-ai-fill:before { content: "\f5a3"; }
+.ri-video-on-ai-line:before { content: "\f5a4"; }
+.ri-voice-ai-fill:before { content: "\f5a5"; }
+.ri-voice-ai-line:before { content: "\f5a6"; }
+.ri-ai-generate-2:before { content: "\f5a7"; }
+.ri-ai-generate-text:before { content: "\f5a8"; }
+.ri-anthropic-fill:before { content: "\f5a9"; }
+.ri-anthropic-line:before { content: "\f5aa"; }
+.ri-apps-2-ai-fill:before { content: "\f5ab"; }
+.ri-apps-2-ai-line:before { content: "\f5ac"; }
+.ri-camera-lens-ai-fill:before { content: "\f5ad"; }
+.ri-camera-lens-ai-line:before { content: "\f5ae"; }
+.ri-clapperboard-ai-fill:before { content: "\f5af"; }
+.ri-clapperboard-ai-line:before { content: "\f5b0"; }
+.ri-claude-fill:before { content: "\f5b1"; }
+.ri-claude-line:before { content: "\f5b2"; }
+.ri-closed-captioning-ai-fill:before { content: "\f5b3"; }
+.ri-closed-captioning-ai-line:before { content: "\f5b4"; }
+.ri-dvd-ai-fill:before { content: "\f5b5"; }
+.ri-dvd-ai-line:before { content: "\f5b6"; }
+.ri-film-ai-fill:before { content: "\f5b7"; }
+.ri-film-ai-line:before { content: "\f5b8"; }
+.ri-font-size-ai:before { content: "\f5b9"; }
+.ri-mixtral-fill:before { content: "\f5ba"; }
+.ri-mixtral-line:before { content: "\f5bb"; }
+.ri-movie-2-ai-fill:before { content: "\f5bc"; }
+.ri-movie-2-ai-line:before { content: "\f5bd"; }
+.ri-mv-ai-fill:before { content: "\f5be"; }
+.ri-mv-ai-line:before { content: "\f5bf"; }
+.ri-perplexity-fill:before { content: "\f5c0"; }
+.ri-perplexity-line:before { content: "\f5c1"; }
+.ri-poker-clubs-fill:before { content: "\f5c2"; }
+.ri-poker-clubs-line:before { content: "\f5c3"; }
+.ri-poker-diamonds-fill:before { content: "\f5c4"; }
+.ri-poker-diamonds-line:before { content: "\f5c5"; }
+.ri-poker-hearts-fill:before { content: "\f5c6"; }
+.ri-poker-hearts-line:before { content: "\f5c7"; }
+.ri-poker-spades-fill:before { content: "\f5c8"; }
+.ri-poker-spades-line:before { content: "\f5c9"; }
+.ri-safe-3-fill:before { content: "\f5ca"; }
+.ri-safe-3-line:before { content: "\f5cb"; }
+.ri-accessibility-fill:before { content: "\f5cc"; }
+.ri-accessibility-line:before { content: "\f5cd"; }
+.ri-alarm-add-fill:before { content: "\f5ce"; }
+.ri-alarm-add-line:before { content: "\f5cf"; }
+.ri-arrow-down-long-fill:before { content: "\f5d0"; }
+.ri-arrow-down-long-line:before { content: "\f5d1"; }
+.ri-arrow-left-down-long-fill:before { content: "\f5d2"; }
+.ri-arrow-left-down-long-line:before { content: "\f5d3"; }
+.ri-arrow-left-long-fill:before { content: "\f5d4"; }
+.ri-arrow-left-long-line:before { content: "\f5d5"; }
+.ri-arrow-left-up-long-fill:before { content: "\f5d6"; }
+.ri-arrow-left-up-long-line:before { content: "\f5d7"; }
+.ri-arrow-right-down-long-fill:before { content: "\f5d8"; }
+.ri-arrow-right-down-long-line:before { content: "\f5d9"; }
+.ri-arrow-right-long-fill:before { content: "\f5da"; }
+.ri-arrow-right-long-line:before { content: "\f5db"; }
+.ri-arrow-right-up-long-fill:before { content: "\f5dc"; }
+.ri-arrow-right-up-long-line:before { content: "\f5dd"; }
+.ri-arrow-up-long-fill:before { content: "\f5de"; }
+.ri-arrow-up-long-line:before { content: "\f5df"; }
+.ri-chess-fill:before { content: "\f5e0"; }
+.ri-chess-line:before { content: "\f5e1"; }
+.ri-diamond-fill:before { content: "\f5e2"; }
+.ri-diamond-line:before { content: "\f5e3"; }
+.ri-diamond-ring-fill:before { content: "\f5e4"; }
+.ri-diamond-ring-line:before { content: "\f5e5"; }
+.ri-figma-fill:before { content: "\f5e6"; }
+.ri-figma-line:before { content: "\f5e7"; }
+.ri-firefox-browser-fill:before { content: "\f5e8"; }
+.ri-firefox-browser-line:before { content: "\f5e9"; }
+.ri-jewelry-fill:before { content: "\f5ea"; }
+.ri-jewelry-line:before { content: "\f5eb"; }
+.ri-multi-image-fill:before { content: "\f5ec"; }
+.ri-multi-image-line:before { content: "\f5ed"; }
+.ri-no-credit-card-fill:before { content: "\f5ee"; }
+.ri-no-credit-card-line:before { content: "\f5ef"; }
+.ri-service-bell-fill:before { content: "\f5f0"; }
+.ri-service-bell-line:before { content: "\f5f1"; }
+.ri-ai-agent-fill:before { content: "\f5f2"; }
+.ri-ai-agent-line:before { content: "\f5f3"; }
+.ri-ai-generate-2-fill:before { content: "\f5f4"; }
+.ri-ai-generate-2-line:before { content: "\f5f5"; }
+.ri-ai-generate-3d-fill:before { content: "\f5f6"; }
+.ri-ai-generate-3d-line:before { content: "\f5f7"; }
+.ri-ai:before { content: "\f5f8"; }
+.ri-apps-ai-fill:before { content: "\f5f9"; }
+.ri-apps-ai-line:before { content: "\f5fa"; }
+.ri-atom-fill:before { content: "\f5fb"; }
+.ri-atom-line:before { content: "\f5fc"; }
+.ri-book-ai-fill:before { content: "\f5fd"; }
+.ri-book-ai-line:before { content: "\f5fe"; }
+.ri-brain-3-fill:before { content: "\f5ff"; }
+.ri-brain-3-line:before { content: "\f600"; }
+.ri-brain-ai-3-fill:before { content: "\f601"; }
+.ri-brain-ai-3-line:before { content: "\f602"; }
+.ri-brush-ai-3-fill:before { content: "\f603"; }
+.ri-brush-ai-3-line:before { content: "\f604"; }
+.ri-camera-4-fill:before { content: "\f605"; }
+.ri-camera-4-line:before { content: "\f606"; }
+.ri-camera-ai-2-fill:before { content: "\f607"; }
+.ri-camera-ai-2-line:before { content: "\f608"; }
+.ri-chat-ai-2-fill:before { content: "\f609"; }
+.ri-chat-ai-2-line:before { content: "\f60a"; }
+.ri-chat-ai-3-fill:before { content: "\f60b"; }
+.ri-chat-ai-3-line:before { content: "\f60c"; }
+.ri-chat-ai-4-fill:before { content: "\f60d"; }
+.ri-chat-ai-4-line:before { content: "\f60e"; }
+.ri-chat-smile-ai-3-fill:before { content: "\f60f"; }
+.ri-chat-smile-ai-3-line:before { content: "\f610"; }
+.ri-deepseek-fill:before { content: "\f611"; }
+.ri-deepseek-line:before { content: "\f612"; }
+.ri-file-ai-2-fill:before { content: "\f613"; }
+.ri-file-ai-2-line:before { content: "\f614"; }
+.ri-file-ai-fill:before { content: "\f615"; }
+.ri-file-ai-line:before { content: "\f616"; }
+.ri-function-ai-fill:before { content: "\f617"; }
+.ri-function-ai-line:before { content: "\f618"; }
+.ri-game-2-fill:before { content: "\f619"; }
+.ri-game-2-line:before { content: "\f61a"; }
+.ri-goblet-broken-fill:before { content: "\f61b"; }
+.ri-goblet-broken-line:before { content: "\f61c"; }
+.ri-lightbulb-ai-fill:before { content: "\f61d"; }
+.ri-lightbulb-ai-line:before { content: "\f61e"; }
+.ri-loop-left-ai-fill:before { content: "\f61f"; }
+.ri-loop-left-ai-line:before { content: "\f620"; }
+.ri-loop-right-ai-fill:before { content: "\f621"; }
+.ri-loop-right-ai-line:before { content: "\f622"; }
+.ri-message-ai-3-fill:before { content: "\f623"; }
+.ri-message-ai-3-line:before { content: "\f624"; }
+.ri-painting-ai-fill:before { content: "\f625"; }
+.ri-painting-ai-line:before { content: "\f626"; }
+.ri-painting-fill:before { content: "\f627"; }
+.ri-painting-line:before { content: "\f628"; }
+.ri-pencil-ai-2-fill:before { content: "\f629"; }
+.ri-pencil-ai-2-line:before { content: "\f62a"; }
+.ri-pencil-ai-fill:before { content: "\f62b"; }
+.ri-pencil-ai-line:before { content: "\f62c"; }
+.ri-remix-fill:before { content: "\f62d"; }
+.ri-remix-line:before { content: "\f62e"; }
+.ri-search-ai-2-fill:before { content: "\f62f"; }
+.ri-search-ai-2-line:before { content: "\f630"; }
+.ri-search-ai-3-fill:before { content: "\f631"; }
+.ri-search-ai-3-line:before { content: "\f632"; }
+.ri-search-ai-4-fill:before { content: "\f633"; }
+.ri-search-ai-4-line:before { content: "\f634"; }
+.ri-search-ai-fill:before { content: "\f635"; }
+.ri-search-ai-line:before { content: "\f636"; }
+.ri-speech-to-text-fill:before { content: "\f637"; }
+.ri-speech-to-text-line:before { content: "\f638"; }
+.ri-target-fill:before { content: "\f639"; }
+.ri-target-line:before { content: "\f63a"; }
+.ri-text-to-speech-fill:before { content: "\f63b"; }
+.ri-text-to-speech-line:before { content: "\f63c"; }
+.ri-wrench-fill:before { content: "\f63d"; }
+.ri-wrench-line:before { content: "\f63e"; }
+.ri-area-chart-fill:before { content: "\f63f"; }
+.ri-area-chart-line:before { content: "\f640"; }
+.ri-baseball-fill:before { content: "\f641"; }
+.ri-baseball-line:before { content: "\f642"; }
+.ri-binoculars-fill:before { content: "\f643"; }
+.ri-binoculars-line:before { content: "\f644"; }
+.ri-cursor-hand:before { content: "\f645"; }
+.ri-emotion-add-fill:before { content: "\f646"; }
+.ri-emotion-add-line:before { content: "\f647"; }
+.ri-file-scan-fill:before { content: "\f648"; }
+.ri-file-scan-line:before { content: "\f649"; }
+.ri-fiverr-fill:before { content: "\f64a"; }
+.ri-fiverr-line:before { content: "\f64b"; }
+.ri-font-serif:before { content: "\f64c"; }
+.ri-ghost-3-fill:before { content: "\f64d"; }
+.ri-ghost-3-line:before { content: "\f64e"; }
+.ri-gitee-fill:before { content: "\f64f"; }
+.ri-gitee-line:before { content: "\f650"; }
+.ri-global-off-fill:before { content: "\f651"; }
+.ri-global-off-line:before { content: "\f652"; }
+.ri-image-download-fill:before { content: "\f653"; }
+.ri-image-download-line:before { content: "\f654"; }
+.ri-image-upload-fill:before { content: "\f655"; }
+.ri-image-upload-line:before { content: "\f656"; }
+.ri-issues-fill:before { content: "\f657"; }
+.ri-issues-line:before { content: "\f658"; }
+.ri-issues-reopen-fill:before { content: "\f659"; }
+.ri-issues-reopen-line:before { content: "\f65a"; }
+.ri-network-error-fill:before { content: "\f65b"; }
+.ri-network-error-line:before { content: "\f65c"; }
+.ri-network-fill:before { content: "\f65d"; }
+.ri-network-line:before { content: "\f65e"; }
+.ri-network-off-fill:before { content: "\f65f"; }
+.ri-network-off-line:before { content: "\f660"; }
+.ri-piano-fill:before { content: "\f661"; }
+.ri-piano-grand-fill:before { content: "\f662"; }
+.ri-piano-grand-line:before { content: "\f663"; }
+.ri-piano-line:before { content: "\f664"; }
+.ri-plug-3-fill:before { content: "\f665"; }
+.ri-plug-3-line:before { content: "\f666"; }
+.ri-send-ins-fill:before { content: "\f667"; }
+.ri-send-ins-line:before { content: "\f668"; }
+.ri-signal-cellular-1-fill:before { content: "\f669"; }
+.ri-signal-cellular-1-line:before { content: "\f66a"; }
+.ri-signal-cellular-2-fill:before { content: "\f66b"; }
+.ri-signal-cellular-2-line:before { content: "\f66c"; }
+.ri-signal-cellular-3-fill:before { content: "\f66d"; }
+.ri-signal-cellular-3-line:before { content: "\f66e"; }
+.ri-signal-cellular-off-fill:before { content: "\f66f"; }
+.ri-signal-cellular-off-line:before { content: "\f670"; }
+.ri-stacked-chart-fill:before { content: "\f671"; }
+.ri-stacked-chart-line:before { content: "\f672"; }
+.ri-upwork-fill:before { content: "\f673"; }
+.ri-upwork-line:before { content: "\f674"; }
+.ri-brain-4-fill:before { content: "\f675"; }
+.ri-brain-4-line:before { content: "\f676"; }
+.ri-certificate-2-fill:before { content: "\f677"; }
+.ri-certificate-2-line:before { content: "\f678"; }
+.ri-certificate-fill:before { content: "\f679"; }
+.ri-certificate-line:before { content: "\f67a"; }
+.ri-cookie-fill:before { content: "\f67b"; }
+.ri-cookie-line:before { content: "\f67c"; }
+.ri-cursor-ai-fill:before { content: "\f67d"; }
+.ri-cursor-ai-line:before { content: "\f67e"; }
+.ri-draw-fill:before { content: "\f67f"; }
+.ri-draw-line:before { content: "\f680"; }
+.ri-ghost-4-fill:before { content: "\f681"; }
+.ri-ghost-4-line:before { content: "\f682"; }
+.ri-gitbook-fill:before { content: "\f683"; }
+.ri-gitbook-line:before { content: "\f684"; }
+.ri-grok-ai-fill:before { content: "\f685"; }
+.ri-grok-ai-line:before { content: "\f686"; }
+.ri-hand-2:before { content: "\f687"; }
+.ri-megaphone-2-fill:before { content: "\f688"; }
+.ri-megaphone-2-line:before { content: "\f689"; }
+.ri-microsoft-copilot-fill:before { content: "\f68a"; }
+.ri-microsoft-copilot-line:before { content: "\f68b"; }
+.ri-mosaic-fill:before { content: "\f68c"; }
+.ri-mosaic-line:before { content: "\f68d"; }
+.ri-qr-scan-ai-fill:before { content: "\f68e"; }
+.ri-qr-scan-ai-line:before { content: "\f68f"; }
+.ri-qwen-ai-fill:before { content: "\f690"; }
+.ri-qwen-ai-line:before { content: "\f691"; }
+.ri-reddit-2-fill:before { content: "\f692"; }
+.ri-reddit-2-line:before { content: "\f693"; }
+.ri-sim-card-warning-fill:before { content: "\f694"; }
+.ri-sim-card-warning-line:before { content: "\f695"; }
+.ri-space-ship-2-fill:before { content: "\f696"; }
+.ri-space-ship-2-line:before { content: "\f697"; }
+.ri-subreddit-fill:before { content: "\f698"; }
+.ri-subreddit-line:before { content: "\f699"; }
+.ri-zhipu-ai-fill:before { content: "\f69a"; }
+.ri-zhipu-ai-line:before { content: "\f69b"; }
+.ri-connector-fill:before { content: "\f69c"; }
+.ri-connector-line:before { content: "\f69d"; }
+
diff --git a/apps/web/src/styles/remixicon/remixicon.woff2 b/apps/web/src/styles/remixicon/remixicon.woff2
new file mode 100644
index 000000000..5e86a2f86
Binary files /dev/null and b/apps/web/src/styles/remixicon/remixicon.woff2 differ
diff --git a/apps/web/src/styles/shell.css b/apps/web/src/styles/shell.css
index f5544a54b..6384b2f6f 100644
--- a/apps/web/src/styles/shell.css
+++ b/apps/web/src/styles/shell.css
@@ -552,13 +552,23 @@
gap: 6px;
flex-shrink: 0;
}
+.app-chrome-file-actions-before {
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+ flex-shrink: 0;
+}
.app-chrome-file-actions {
display: inline-flex;
align-items: center;
gap: 6px;
flex-shrink: 0;
}
-.app-chrome-file-actions:not(:empty) + .app-chrome-actions {
+.app-chrome-file-actions-before:not(:empty) + .app-chrome-file-actions:not(:empty) {
+ margin-left: 4px;
+}
+.app-chrome-file-actions:not(:empty) + .app-chrome-actions,
+.app-chrome-file-actions-before:not(:empty) + .app-chrome-file-actions:empty + .app-chrome-actions {
margin-left: 4px;
padding-left: 8px;
border-left: 1px solid var(--border);
@@ -1005,6 +1015,29 @@
/* -------- Avatar menu (replaces in-topbar agent picker) ------------- */
.avatar-menu { position: relative; }
+.avatar-agent-trigger {
+ width: 58px;
+ height: 32px;
+ padding: 0;
+ display: inline-grid;
+ grid-template-columns: 32px 24px;
+ align-items: center;
+ justify-items: center;
+ border: 1px solid var(--border);
+ border-radius: 7px;
+ background: var(--bg-panel);
+ color: var(--text);
+ cursor: pointer;
+ overflow: hidden;
+ transition: border-color 200ms cubic-bezier(0.23, 1, 0.32, 1),
+ background 200ms cubic-bezier(0.23, 1, 0.32, 1);
+}
+.avatar-agent-trigger:hover:not(:disabled) {
+ border-color: var(--border-strong, var(--border));
+}
+.avatar-agent-trigger > svg:last-child {
+ color: var(--text-muted);
+}
.avatar-btn {
width: 32px;
height: 32px;
@@ -1210,6 +1243,48 @@ a.avatar-item:visited {
flex: 1 1 auto;
min-width: 0;
}
+.split-edit-divider {
+ width: 8px;
+ min-width: 8px;
+ height: 100%;
+ border-right: 1px solid var(--border);
+ background: var(--bg-panel);
+}
+.comment-left-host {
+ display: flex;
+ flex: 1 1 auto;
+ min-width: 0;
+ min-height: 0;
+ overflow: hidden;
+ background: var(--bg-panel);
+}
+.comment-left-host > .comment-side-panel {
+ position: relative;
+ top: auto;
+ right: auto;
+ bottom: auto;
+ flex: 1 1 auto;
+ width: 100%;
+ max-width: none;
+ min-width: 0;
+ min-height: 0;
+ border: 0;
+ border-radius: 0;
+ box-shadow: none;
+ z-index: 20;
+}
+.comment-left-host .comment-side-header {
+ min-height: 40px;
+}
+.comment-left-host .comment-side-list {
+ padding: 16px 12px;
+}
+.comment-side-composer {
+ flex: 0 0 auto;
+ padding: 12px;
+ border-top: 1px solid var(--border);
+ background: var(--bg-panel);
+}
.pane {
display: flex;
flex-direction: column;
diff --git a/apps/web/src/styles/viewer/core.css b/apps/web/src/styles/viewer/core.css
index b7869a1a7..fc6f9555e 100644
--- a/apps/web/src/styles/viewer/core.css
+++ b/apps/web/src/styles/viewer/core.css
@@ -19,7 +19,7 @@
flex-shrink: 0;
}
.viewer-toolbar-left { display: inline-flex; align-items: center; gap: 8px; }
-.viewer-toolbar-actions { display: inline-flex; gap: 2px; align-items: center; flex-wrap: wrap; }
+.viewer-toolbar-actions { display: inline-flex; gap: 2px; align-items: center; }
.viewer-toolbar .icon-only,
.viewer-toolbar-actions .icon-only {
width: 28px;
@@ -134,6 +134,99 @@
opacity: 0.75;
cursor: progress;
}
+.viewer-action-icon {
+ position: relative;
+ justify-content: center;
+ width: 30px;
+ height: 30px;
+ padding: 0;
+}
+.viewer-action-icon[data-tooltip]::after {
+ content: attr(data-tooltip);
+ position: absolute;
+ z-index: 80;
+ top: calc(100% + 7px);
+ left: 50%;
+ transform: translateX(-50%) translateY(-2px);
+ padding: 4px 7px;
+ border-radius: 6px;
+ background: var(--text);
+ color: var(--bg-panel);
+ font-size: 11px;
+ line-height: 1.2;
+ opacity: 0;
+ pointer-events: none;
+ white-space: nowrap;
+ transition: opacity 140ms cubic-bezier(0.23, 1, 0.32, 1), transform 140ms cubic-bezier(0.23, 1, 0.32, 1);
+}
+.viewer-action-icon[data-tooltip]:hover::after,
+.viewer-action-icon[data-tooltip]:focus-visible::after {
+ opacity: 1;
+ transform: translateX(-50%) translateY(0);
+}
+.viewer-comment-toggle.active {
+ border: 1px solid color-mix(in srgb, var(--accent) 26%, transparent);
+ box-shadow: 0 0 0 1px color-mix(in srgb, var(--accent) 8%, transparent);
+}
+.viewer-action-active-dot {
+ position: absolute;
+ right: 5px;
+ top: 5px;
+ width: 6px;
+ height: 6px;
+ border-radius: 50%;
+ background: var(--accent);
+ box-shadow: 0 0 0 2px var(--bg-panel);
+}
+.artifact-tool-menu-anchor {
+ position: relative;
+ display: inline-flex;
+}
+.artifact-tool-menu-trigger[aria-expanded='true'] {
+ background: var(--bg-subtle);
+ color: var(--text);
+}
+.artifact-tool-menu {
+ position: absolute;
+ top: calc(100% + 6px);
+ right: 0;
+ z-index: 59;
+ min-width: 216px;
+ padding: 6px;
+ display: flex;
+ flex-direction: column;
+ gap: 2px;
+ background: var(--bg-panel);
+ border: 1px solid var(--border);
+ border-radius: var(--radius-md, 10px);
+ box-shadow: var(--shadow-md, 0 8px 24px rgba(0, 0, 0, 0.12));
+}
+.artifact-tool-menu-item {
+ width: 100%;
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ padding: 7px 8px;
+ border: 0;
+ border-radius: var(--radius-sm);
+ background: transparent;
+ color: var(--text-muted);
+ font-size: 12.5px;
+ line-height: 1.2;
+ white-space: nowrap;
+ text-align: left;
+ cursor: pointer;
+}
+.artifact-tool-menu-item:hover {
+ background: var(--bg-subtle);
+}
+.artifact-tool-menu-item.active {
+ background: var(--bg-muted);
+ color: var(--text);
+}
+.artifact-tool-menu-item .palette-tweaks-badge {
+ margin-left: auto;
+}
/* Preview-only controls: keep layout stable across modes.
When inactive, reserve the same horizontal slot but fully disable interaction. */
.viewer-preview-controls {
@@ -1015,6 +1108,9 @@
background: var(--bg-panel);
box-shadow: var(--shadow-lg);
}
+.annotation-hover-popover {
+ pointer-events: none;
+}
.comment-popover-head {
display: flex;
align-items: flex-start;
@@ -1154,16 +1250,6 @@
gap: 10px;
min-width: 0;
}
-.comment-popover-remove {
- color: var(--red);
- background: transparent;
- border-color: transparent;
-}
-.comment-popover-remove:hover:not(:disabled) {
- background: var(--red-bg);
- border-color: var(--red-border);
-}
-
/* Right-side comment thread panel. Shown while board (comment) mode
is on; takes the place of the chat sidebar's removed Comments tab.
Floats over the artifact preview at the right edge. */
@@ -1297,6 +1383,11 @@
background: #fff1ec;
border-color: #ff8c75;
}
+.comment-side-item.active {
+ background: color-mix(in srgb, var(--accent) 10%, var(--bg-panel));
+ border-color: color-mix(in srgb, var(--accent) 46%, var(--border));
+ box-shadow: inset 3px 0 0 var(--accent);
+}
.comment-side-item-head {
display: flex;
align-items: center;
@@ -1431,6 +1522,50 @@
pointer-events: auto;
}
+.screenshot-toast-anchor {
+ position: fixed;
+ top: 64px;
+ left: 50%;
+ transform: translateX(-50%);
+ z-index: 1200;
+ pointer-events: auto;
+}
+.screenshot-toast {
+ display: inline-flex;
+ align-items: center;
+ gap: 10px;
+ min-height: 48px;
+ padding: 0 12px 0 16px;
+ border: 1px solid rgba(87, 149, 206, 0.5);
+ border-radius: 16px;
+ background: #0d3858;
+ color: #fff;
+ box-shadow: 0 12px 32px rgba(6, 22, 36, 0.28);
+ font-size: 15px;
+ font-weight: 650;
+ white-space: nowrap;
+}
+.screenshot-toast > i {
+ color: #fff;
+ flex: 0 0 auto;
+}
+.screenshot-toast button {
+ width: 28px;
+ height: 28px;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ border: 0;
+ border-radius: 50%;
+ background: transparent;
+ color: rgba(255, 255, 255, 0.72);
+ cursor: pointer;
+}
+.screenshot-toast button:hover {
+ background: rgba(255, 255, 255, 0.1);
+ color: #fff;
+}
+
/* Inspect panel — sibling of the comment popover. Anchored to the
right side of the preview surface. Width is fixed so layout doesn't
reflow as the user scrubs slider values; controls reserve space for
diff --git a/apps/web/src/styles/viewer/memory.css b/apps/web/src/styles/viewer/memory.css
index bf5b1a0b1..e63d5b082 100644
--- a/apps/web/src/styles/viewer/memory.css
+++ b/apps/web/src/styles/viewer/memory.css
@@ -640,22 +640,21 @@
}
/* Manual edit mode */
.manual-edit-workspace {
- display: grid;
- grid-template-columns: 280px minmax(420px, 1fr) 280px;
- gap: 10px;
+ position: relative;
+ width: 100%;
height: 100%;
min-height: 0;
- padding: 10px;
background: var(--bg);
}
-.manual-edit-workspace > .manual-edit-canvas { grid-column: 2; grid-row: 1; }
-.manual-edit-workspace > .manual-edit-layers { grid-column: 1; grid-row: 1; }
.manual-edit-workspace > .manual-edit-right {
- grid-column: 3;
- grid-row: 1;
- height: 100%;
- min-height: 0;
+ position: absolute;
+ top: 8px;
+ right: 8px;
+ bottom: 8px;
+ width: 320px;
+ max-width: calc(100% - 16px);
overflow: hidden;
+ z-index: 30;
}
/* Claude Code-style edit inspector panel. */
@@ -810,17 +809,15 @@
.cc-disclosure > summary { cursor: pointer; padding: 4px 0; }
.manual-edit-workspace.preview-viewport:not(.preview-viewport-desktop) {
- grid-template-columns: 240px calc(var(--preview-viewport-width) * var(--preview-scale, 1)) 344px;
- justify-content: start;
+ justify-content: center;
}
.manual-edit-canvas {
- position: relative;
+ position: absolute;
+ inset: 0;
min-width: 0;
min-height: 0;
- overflow: auto;
- border: 1px solid var(--border);
- border-radius: 8px;
+ overflow: hidden;
background: var(--bg-panel);
}
@@ -929,6 +926,46 @@
scrollbar-gutter: stable;
}
+.manual-edit-titlebar {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 12px;
+ min-height: 52px;
+ padding: 14px 18px 10px;
+}
+
+.manual-edit-titlebar > span {
+ min-width: 0;
+ overflow: hidden;
+ color: var(--text);
+ font-size: 16px;
+ font-weight: 600;
+ line-height: 1.2;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.manual-edit-titlebar-close {
+ flex: 0 0 auto;
+ width: 38px;
+ height: 38px;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ padding: 0;
+ border: 1px solid var(--border);
+ border-radius: 10px;
+ background: var(--bg-panel);
+ color: var(--text);
+ box-shadow: var(--shadow-xs);
+}
+
+.manual-edit-titlebar-close:hover {
+ background: var(--bg-subtle);
+ border-color: var(--border-strong);
+}
+
.manual-edit-modal-head {
display: flex;
align-items: flex-start;
diff --git a/apps/web/src/styles/viewer/routines.css b/apps/web/src/styles/viewer/routines.css
index 6c6e2c92a..955655761 100644
--- a/apps/web/src/styles/viewer/routines.css
+++ b/apps/web/src/styles/viewer/routines.css
@@ -1507,19 +1507,23 @@
display: inline-flex;
align-items: stretch;
border-radius: 7px;
- border: 1px solid var(--border);
- background: var(--bg-panel);
+ border: 1px solid transparent;
+ background: transparent;
overflow: hidden;
- transition: border-color 200ms cubic-bezier(0.23, 1, 0.32, 1);
+ transition: background 200ms cubic-bezier(0.23, 1, 0.32, 1);
}
.app .handoff-split:hover {
- border-color: var(--border-strong, var(--border));
+ background: color-mix(in srgb, var(--text-muted) 6%, transparent);
}
.app .handoff-trigger {
display: inline-flex;
align-items: center;
- gap: 8px;
- padding: 3px 6px 3px 4px;
+ justify-content: center;
+ width: 32px;
+ min-width: 32px;
+ height: 30px;
+ gap: 0;
+ padding: 0;
border: 0;
background: transparent;
color: var(--text);
@@ -1541,16 +1545,15 @@
gap: 8px;
padding: 3px 12px 3px 4px;
border-radius: 7px;
- border: 1px solid var(--border);
- background: var(--bg-panel);
+ border: 1px solid transparent;
+ background: transparent;
color: var(--text);
font: inherit;
font-size: 12px;
cursor: pointer;
}
.app .handoff-trigger--solo:hover {
- border-color: var(--border-strong, var(--border));
- background: color-mix(in srgb, var(--text-muted) 6%, var(--bg-panel));
+ background: color-mix(in srgb, var(--text-muted) 6%, transparent);
}
.app .handoff-trigger-label {
white-space: nowrap;
@@ -1562,11 +1565,9 @@
display: inline-flex;
align-items: center;
justify-content: center;
- /* Real tap target — at least 28px on the short axis. The previous
- caret was a 16-18px nested span which the user flagged as too
- small to click reliably. */
- min-width: 28px;
- padding: 0 6px;
+ min-width: 24px;
+ width: 24px;
+ padding: 0;
border: 0;
background: transparent;
cursor: pointer;
@@ -1607,6 +1608,14 @@
display: flex;
flex-direction: column;
}
+.app .handoff-menu-title {
+ padding: 6px 10px 7px;
+ border-bottom: 1px solid var(--border);
+ margin: 0 0 4px;
+ color: var(--text-muted);
+ font-size: 11.5px;
+ line-height: 16px;
+}
.app .handoff-menu-item {
display: inline-flex;
align-items: center;
diff --git a/apps/web/src/types.ts b/apps/web/src/types.ts
index b7e119818..6041907d8 100644
--- a/apps/web/src/types.ts
+++ b/apps/web/src/types.ts
@@ -522,4 +522,5 @@ export type {
export interface OpenTabsState {
tabs: ProjectWorkspaceTabId[];
active: ProjectWorkspaceTabId | null;
+ hasSavedState?: boolean;
}
diff --git a/apps/web/tests/artifacts/manifest.test.ts b/apps/web/tests/artifacts/manifest.test.ts
index 4aab5312d..968acaad6 100644
--- a/apps/web/tests/artifacts/manifest.test.ts
+++ b/apps/web/tests/artifacts/manifest.test.ts
@@ -54,6 +54,20 @@ describe('parseArtifactManifest', () => {
const out = parseArtifactManifest(raw);
expect(out?.status).toBe('streaming');
});
+
+ it('preserves primary file hints', () => {
+ const raw = JSON.stringify({
+ version: 1,
+ kind: 'html',
+ title: 'x',
+ entry: 'index.html',
+ renderer: 'html',
+ exports: ['html'],
+ primary: 'index.html',
+ });
+ const out = parseArtifactManifest(raw);
+ expect(out?.primary).toBe('index.html');
+ });
});
describe('inferLegacyManifest', () => {
@@ -112,6 +126,7 @@ describe('createHtmlArtifactManifest', () => {
expect(out.renderer).toBe('html');
expect(out.status).toBe('complete');
expect(out.exports).toEqual(['html', 'pdf', 'zip']);
+ expect(out.primary).toBe(true);
expect(out.entry).toBe('index.html');
expect(out.title).toBe('Landing');
expect(typeof out.createdAt).toBe('string');
diff --git a/apps/web/tests/components/BoardComposerPopover.pod-chip-hover.test.tsx b/apps/web/tests/components/BoardComposerPopover.pod-chip-hover.test.tsx
index 05ce4a463..bf09646c5 100644
--- a/apps/web/tests/components/BoardComposerPopover.pod-chip-hover.test.tsx
+++ b/apps/web/tests/components/BoardComposerPopover.pod-chip-hover.test.tsx
@@ -53,7 +53,6 @@ function renderPopover(overrides: {
onClose={() => {}}
onSaveComment={() => {}}
onSendBatch={() => {}}
- onRemove={() => {}}
onRemoveMember={() => {}}
onHoverMember={overrides.onHoverMember}
sending={false}
diff --git a/apps/web/tests/components/BoardComposerPopover.pod-remove.test.tsx b/apps/web/tests/components/BoardComposerPopover.pod-remove.test.tsx
index 4118491fd..e230b8f75 100644
--- a/apps/web/tests/components/BoardComposerPopover.pod-remove.test.tsx
+++ b/apps/web/tests/components/BoardComposerPopover.pod-remove.test.tsx
@@ -53,7 +53,6 @@ function renderPopover(overrides: {
onClose={() => {}}
onSaveComment={() => {}}
onSendBatch={() => {}}
- onRemove={() => {}}
onRemoveMember={overrides.onRemoveMember}
sending={false}
t={((key: string) => String(key)) as never}
diff --git a/apps/web/tests/components/ChatComposer.infinite-render.test.tsx b/apps/web/tests/components/ChatComposer.infinite-render.test.tsx
index c8c014d1c..dd7adb526 100644
--- a/apps/web/tests/components/ChatComposer.infinite-render.test.tsx
+++ b/apps/web/tests/components/ChatComposer.infinite-render.test.tsx
@@ -109,7 +109,6 @@ describe('ChatComposer infinite re-render regression (#2097)', () => {
await waitFor(() => expect(onSend).toHaveBeenCalledTimes(1));
await waitFor(() => expect(window.localStorage.getItem(key)).toBeNull());
});
-
it('does not re-sync the composer scroll offset on every plain-text keystroke', () => {
const scrollTopGetter = vi.fn(() => 0);
const original = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, 'scrollTop');
diff --git a/apps/web/tests/components/ChatPane.connect-repo.test.tsx b/apps/web/tests/components/ChatPane.connect-repo.test.tsx
index 1439ddeea..b6d5cdc27 100644
--- a/apps/web/tests/components/ChatPane.connect-repo.test.tsx
+++ b/apps/web/tests/components/ChatPane.connect-repo.test.tsx
@@ -7,7 +7,11 @@ import { afterEach, describe, expect, it, vi } from 'vitest';
import { ChatPane } from '../../src/components/ChatPane';
import type { Conversation, ProjectMetadata } from '../../src/types';
-const composerMocks = vi.hoisted(() => ({ setDraft: vi.fn() }));
+const composerMocks = vi.hoisted(() => ({
+ focus: vi.fn(),
+ restoreDraft: vi.fn(),
+ setDraft: vi.fn(),
+}));
vi.mock('../../src/i18n', () => ({
useI18n: () => ({ locale: 'en', setLocale: () => undefined, t: (key: string) => key }),
@@ -16,7 +20,11 @@ vi.mock('../../src/i18n', () => ({
vi.mock('../../src/components/ChatComposer', () => ({
ChatComposer: forwardRef((_props, ref) => {
- useImperativeHandle(ref, () => ({ setDraft: composerMocks.setDraft }));
+ useImperativeHandle(ref, () => ({
+ focus: composerMocks.focus,
+ restoreDraft: composerMocks.restoreDraft,
+ setDraft: composerMocks.setDraft,
+ }));
return
;
}),
}));
diff --git a/apps/web/tests/components/ChatPane.streaming.test.tsx b/apps/web/tests/components/ChatPane.streaming.test.tsx
index bb785fb2d..72040734b 100644
--- a/apps/web/tests/components/ChatPane.streaming.test.tsx
+++ b/apps/web/tests/components/ChatPane.streaming.test.tsx
@@ -1,13 +1,20 @@
// @vitest-environment jsdom
import { cleanup, fireEvent, render, screen } from '@testing-library/react';
-import { forwardRef } from 'react';
+import { forwardRef, useImperativeHandle } from 'react';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { ChatPane, retryableAssistantMessage } from '../../src/components/ChatPane';
import { DESIGN_SYSTEM_WORKSPACE_PROMPT_PREFIX } from '../../src/design-system-auto-prompt';
+import { readExpandedIndexCss } from '../helpers/read-expanded-css';
import type { ChatMessage, Conversation, ProjectMetadata } from '../../src/types';
+const composerMocks = vi.hoisted(() => ({
+ focus: vi.fn(),
+ restoreDraft: vi.fn(),
+ setDraft: vi.fn(),
+}));
+
const translations: Record
= {
'chat.queuedHeader': 'Queued',
'chat.queuedToSend': 'to Send',
@@ -35,9 +42,14 @@ vi.mock('../../src/components/AssistantMessage', () => ({
}));
vi.mock('../../src/components/ChatComposer', () => ({
- ChatComposer: forwardRef(({ streaming }: { streaming: boolean }, _ref) => (
-
- )),
+ ChatComposer: forwardRef(({ streaming }: { streaming: boolean }, ref) => {
+ useImperativeHandle(ref, () => ({
+ focus: composerMocks.focus,
+ restoreDraft: composerMocks.restoreDraft,
+ setDraft: composerMocks.setDraft,
+ }));
+ return ;
+ }),
}));
class MockResizeObserver {
@@ -80,10 +92,25 @@ beforeEach(() => {
afterEach(() => {
cleanup();
+ vi.clearAllMocks();
vi.unstubAllGlobals();
});
describe('ChatPane streaming state', () => {
+ it('keeps queued-send strip styles compact above the composer', () => {
+ const css = readExpandedIndexCss();
+
+ expect(css).toContain('.chat-queued-send-strip');
+ expect(css).toContain('display: flex;');
+ expect(css).toContain('.chat-queued-send-row');
+ expect(css).toContain('align-items: center;');
+ expect(css).toContain('.chat-queued-send-title');
+ expect(css).toContain('text-overflow: ellipsis;');
+ expect(css).toContain('.chat-queued-send-action');
+ expect(css).toContain('width: 26px;');
+ expect(css).toContain('height: 26px;');
+ });
+
it('exposes retry only for the last failed assistant when the pane is idle', () => {
const failed: ChatMessage = {
id: 'assistant-1',
@@ -137,6 +164,54 @@ describe('ChatPane streaming state', () => {
expect(bubble.closest('.msg.user')).not.toBeNull();
});
+ it('hides internal path ids from comment attachment chips', () => {
+ const messages: ChatMessage[] = [
+ {
+ id: 'user-1',
+ role: 'user',
+ content: '',
+ createdAt: 1,
+ commentAttachments: [
+ {
+ id: 'comment-1',
+ order: 1,
+ filePath: 'preview.html',
+ elementId: 'path-0-0-0-0-1',
+ selector: '[data-od-id="path-0-0-0-0-1"]',
+ label: '',
+ comment: '222',
+ currentText: '',
+ pagePosition: { x: 10, y: 20, width: 30, height: 40 },
+ htmlHint: '',
+ },
+ ],
+ },
+ ];
+
+ render(
+
'project-1'}
+ onSend={vi.fn()}
+ onStop={vi.fn()}
+ conversations={conversations}
+ activeConversationId="conv-1"
+ onSelectConversation={vi.fn()}
+ onDeleteConversation={vi.fn()}
+ projectMetadata={projectMetadata}
+ />,
+ );
+
+ expect(screen.getByText('Annotation')).toBeTruthy();
+ expect(screen.getByText('222')).toBeTruthy();
+ expect(screen.queryByText('path-0-0-0-0-1')).toBeNull();
+ });
+
it('summarizes auto-sent design-system workspace prompts', () => {
const messages: ChatMessage[] = [
{
@@ -273,7 +348,25 @@ Expected output:
projectId="project-1"
projectFiles={[]}
queuedItems={[
- { id: 'queued-1', prompt: 'Make the export button larger and use a warmer accent' },
+ {
+ id: 'queued-1',
+ prompt: 'Make the export button larger and use a warmer accent',
+ attachments: [{ path: 'brief.md', name: 'brief.md', kind: 'file' }],
+ commentAttachments: [
+ {
+ id: 'comment-1',
+ order: 1,
+ filePath: 'preview.html',
+ elementId: 'hero',
+ selector: '#hero',
+ label: 'Hero',
+ comment: 'Use a warmer accent',
+ currentText: 'Export',
+ pagePosition: { x: 10, y: 20, width: 30, height: 40 },
+ htmlHint: '',
+ },
+ ],
+ },
{ id: 'queued-2', prompt: 'Then adjust the title spacing' },
{ id: 'queued-3', prompt: 'Reduce the subtitle size' },
{ id: 'queued-4', prompt: 'Switch to a lighter font weight' },
@@ -392,7 +485,6 @@ Expected output:
expect(log!.scrollTop).toBe(600);
});
-
});
const conversations: Conversation[] = [
diff --git a/apps/web/tests/components/FileViewer.manual-edit-history.test.tsx b/apps/web/tests/components/FileViewer.manual-edit-history.test.tsx
index e0f3a405d..85acd75d0 100644
--- a/apps/web/tests/components/FileViewer.manual-edit-history.test.tsx
+++ b/apps/web/tests/components/FileViewer.manual-edit-history.test.tsx
@@ -23,6 +23,19 @@ vi.mock('../../src/components/ManualEditPanel', async (importOriginal) => {
import { FileViewer } from '../../src/components/FileViewer';
+function openManualTools() {
+ // Manual tools now live directly in the primary toolbar.
+}
+
+function clickManualTool(testId: string) {
+ openManualTools();
+ fireEvent.click(screen.getByTestId(testId));
+}
+
+function clickAgentTool(testId: string) {
+ fireEvent.click(screen.getByTestId(testId));
+}
+
afterEach(() => {
cleanup();
panelState.props = null;
@@ -64,16 +77,17 @@ describe('FileViewer manual edit history regressions', () => {
/>,
);
- fireEvent.click(screen.getByTestId('manual-edit-mode-toggle'));
+ clickManualTool('manual-edit-mode-toggle');
await waitFor(() => expect(panelState.props).not.toBeNull());
act(() => {
panelState.props?.onStyleChange?.('hero', { color: '#ef4444' }, 'Style: Hero');
});
- fireEvent.click(screen.getByTestId('draw-overlay-toggle'));
+ clickAgentTool('draw-overlay-toggle');
await waitFor(() => expect(savedSources).toHaveLength(1));
expect(savedSources[0]).toContain('rgb(239, 68, 68)');
+ openManualTools();
expect(screen.getByTestId('manual-edit-mode-toggle').getAttribute('aria-pressed')).toBe('true');
expect(screen.getByTestId('draw-overlay-toggle').getAttribute('aria-pressed')).toBe('false');
@@ -85,7 +99,10 @@ describe('FileViewer manual edit history regressions', () => {
await saveResponse;
});
- await waitFor(() => expect(screen.getByTestId('manual-edit-mode-toggle').getAttribute('aria-pressed')).toBe('false'));
+ await waitFor(() => {
+ openManualTools();
+ expect(screen.getByTestId('manual-edit-mode-toggle').getAttribute('aria-pressed')).toBe('false');
+ });
expect(screen.getByTestId('draw-overlay-toggle').getAttribute('aria-pressed')).toBe('true');
});
@@ -123,7 +140,7 @@ describe('FileViewer manual edit history regressions', () => {
/>,
);
- fireEvent.click(screen.getByTestId('manual-edit-mode-toggle'));
+ clickManualTool('manual-edit-mode-toggle');
await waitFor(() => expect(panelState.props).not.toBeNull());
act(() => {
@@ -195,8 +212,6 @@ describe('FileViewer manual edit history regressions', () => {
expect(frame.getAttribute('data-od-render-mode')).toBe('srcdoc');
expect(panelState.props?.draft.fullSource).toContain('Hero');
});
- const postMessageSpy = vi.spyOn(getActivePreviewFrame().contentWindow!, 'postMessage');
-
act(() => {
panelState.props?.onApplyPatch(
{ id: 'hero', kind: 'set-text', value: 'Updated hero' },
@@ -207,13 +222,7 @@ describe('FileViewer manual edit history regressions', () => {
await waitFor(() => expect(savedSources).toHaveLength(1));
await waitFor(() => expect(panelState.props?.draft.fullSource).toContain('Updated hero'));
await waitFor(() => {
- expect(postMessageSpy).toHaveBeenCalledWith(
- expect.objectContaining({
- type: 'od:srcdoc-transport-activate',
- html: expect.stringContaining('Updated hero'),
- }),
- '*',
- );
+ expect(getActivePreviewFrame().srcdoc).toContain('Updated hero');
});
});
@@ -280,13 +289,8 @@ describe('FileViewer manual edit history regressions', () => {
'*',
);
await waitFor(() => {
- expect(postMessageSpy).toHaveBeenCalledWith(
- expect.objectContaining({
- type: 'od:srcdoc-transport-activate',
- html: expect.not.stringContaining('data-od-id="hero"'),
- }),
- '*',
- );
+ expect((screen.getByTestId('artifact-preview-frame') as HTMLIFrameElement).srcdoc)
+ .not.toContain('data-od-id="hero"');
});
});
});
diff --git a/apps/web/tests/components/FileViewer.manual-edit.test.tsx b/apps/web/tests/components/FileViewer.manual-edit.test.tsx
index 9a5936608..6d15aff0a 100644
--- a/apps/web/tests/components/FileViewer.manual-edit.test.tsx
+++ b/apps/web/tests/components/FileViewer.manual-edit.test.tsx
@@ -15,6 +15,10 @@ afterEach(() => {
});
describe('FileViewer manual edit regressions', () => {
+ function clickManualTool(testId: string) {
+ fireEvent.click(screen.getByTestId(testId));
+ }
+
it('removes invalid fields from pending manual edit style saves without dropping unrelated fields', () => {
expect(cancelManualEditPendingStyleSnapshot({
id: 'hero',
@@ -145,6 +149,56 @@ describe('FileViewer manual edit regressions', () => {
vi.useRealTimers();
}
});
+
+ it('clears a prior manual edit save error after a later successful save', async () => {
+ const source = 'Hero';
+ let saveAttempts = 0;
+ const fetchMock = vi.fn(async (input: string | URL | Request, init?: RequestInit) => {
+ const url = typeof input === 'string' ? input : input instanceof Request ? input.url : String(input);
+ if (url.includes('/api/projects/project-1/files') && init?.method === 'POST') {
+ saveAttempts += 1;
+ if (saveAttempts === 1) {
+ return new Response(JSON.stringify({
+ error: { code: 'FORBIDDEN', message: 'Request failed (403).' },
+ }), { status: 403, headers: { 'Content-Type': 'application/json' } });
+ }
+ return new Response(JSON.stringify({ file: htmlPreviewFile() }), {
+ status: 200,
+ headers: { 'Content-Type': 'application/json' },
+ });
+ }
+ if (url.includes('/api/projects/project-1/raw/preview.html')) {
+ return new Response(source, { status: 200 });
+ }
+ return new Response('{}', { status: 200, headers: { 'Content-Type': 'application/json' } });
+ });
+ vi.stubGlobal('fetch', fetchMock);
+
+ render(
+ ,
+ );
+
+ clickManualTool('manual-edit-mode-toggle');
+ const baseSizeInput = await waitFor(() => {
+ const input = Array.from(document.querySelectorAll('.cc-row'))
+ .find((row) => row.textContent?.includes('Base size'))
+ ?.querySelector('input') as HTMLInputElement | null;
+ if (!input) throw new Error('Base size input not found');
+ return input;
+ });
+
+ fireEvent.change(baseSizeInput, { target: { value: '18' } });
+ await waitFor(() => {
+ expect(screen.getByText(/Could not save the edited file/)).toBeTruthy();
+ });
+
+ fireEvent.change(baseSizeInput, { target: { value: '19' } });
+ await waitFor(() => {
+ expect(screen.queryByText(/Could not save the edited file/)).toBeNull();
+ });
+ });
});
function htmlPreviewFile(): ProjectFile {
diff --git a/apps/web/tests/components/FileViewer.test.tsx b/apps/web/tests/components/FileViewer.test.tsx
index 59b8bf500..eb681e9ae 100644
--- a/apps/web/tests/components/FileViewer.test.tsx
+++ b/apps/web/tests/components/FileViewer.test.tsx
@@ -78,6 +78,10 @@ function srcDocActivationMessages(calls: readonly (readonly unknown[])[]) {
});
}
+function clickAgentTool(testId: string) {
+ fireEvent.click(screen.getByTestId(testId));
+}
+
describe('FileViewer preview scale', () => {
it('keeps file viewer selectors in the effective global stylesheet', () => {
const css = readExpandedIndexCss();
@@ -87,6 +91,19 @@ describe('FileViewer preview scale', () => {
expect(css).toContain('.viewer-action');
});
+ it('keeps the manual edit titlebar from overlapping the close button', () => {
+ const css = readExpandedIndexCss();
+
+ expect(css).toContain('.manual-edit-titlebar');
+ expect(css).toContain('justify-content: space-between;');
+ expect(css).toContain('.manual-edit-titlebar > span');
+ expect(css).toContain('text-overflow: ellipsis;');
+ expect(css).toContain('.manual-edit-titlebar-close');
+ expect(css).toContain('flex: 0 0 auto;');
+ expect(css).toContain('width: 38px;');
+ expect(css).toContain('height: 38px;');
+ });
+
it('uses the requested zoom for desktop preview overlays', () => {
expect(effectivePreviewScale('desktop', 1.5, { width: 320, height: 480 })).toBe(1.5);
});
@@ -377,10 +394,6 @@ describe('FileViewer SVG artifacts', () => {
,
);
- // Both iframes are always mounted (the lazy srcDoc transport avoids
- // booting the artifact in the inactive frame). `data-od-active` and
- // the testid pair identify which iframe is currently the user-facing
- // one without unmounting either side.
expect(markup).toContain('data-testid="artifact-preview-frame"');
expect(markup).toContain('data-od-render-mode="url-load"');
expect(markup).toContain('data-od-render-mode="url-load" data-od-active="true"');
@@ -424,8 +437,7 @@ describe('FileViewer SVG artifacts', () => {
expect(srcDocFrame?.srcdoc).toContain('data-od-lazy-srcdoc-transport');
expect(srcDocFrame?.srcdoc).not.toContain('__odArtifactBootCount');
- const postMessageSpy = vi.spyOn(srcDocFrame!.contentWindow!, 'postMessage');
- fireEvent.click(screen.getByTestId('inspect-mode-toggle'));
+ fireEvent.click(screen.getByTestId('manual-edit-mode-toggle'));
const urlFrameAfter = container.querySelector('iframe[data-od-render-mode="url-load"]') as HTMLIFrameElement | null;
const srcDocFrameAfter = container.querySelector('iframe[data-od-render-mode="srcdoc"]') as HTMLIFrameElement | null;
@@ -435,15 +447,8 @@ describe('FileViewer SVG artifacts', () => {
expect(urlFrameAfter?.getAttribute('data-od-active')).toBe('false');
expect(urlFrameAfter?.getAttribute('src')).toBe('about:blank');
expect(srcDocFrameAfter?.getAttribute('data-od-active')).toBe('true');
- expect(srcDocFrameAfter?.srcdoc).toContain('data-od-lazy-srcdoc-transport');
- expect(srcDocFrameAfter?.srcdoc).not.toContain('__odArtifactBootCount');
-
- await waitFor(() => {
- const activations = srcDocActivationMessages(postMessageSpy.mock.calls);
- expect(activations.at(-1)?.html).toContain('__odArtifactBootCount');
- expect(activations.at(-1)?.html).toContain('data-od-selection-bridge');
- expect(activations.at(-1)?.html).toContain('data-od-preview-focus-guard');
- });
+ expect(srcDocFrameAfter?.srcdoc).toContain('__odArtifactBootCount');
+ expect(srcDocFrameAfter?.srcdoc).toContain('data-od-edit-bridge');
});
it('reactivates the srcDoc transport after switching source back to preview', async () => {
@@ -471,31 +476,23 @@ describe('FileViewer SVG artifacts', () => {
/>,
);
- fireEvent.click(screen.getByTestId('inspect-mode-toggle'));
+ fireEvent.click(screen.getByTestId('manual-edit-mode-toggle'));
await waitFor(() => {
const activeFrame = screen.getByTestId('artifact-preview-frame') as HTMLIFrameElement;
expect(activeFrame.getAttribute('data-od-render-mode')).toBe('srcdoc');
});
- fireEvent.click(screen.getByRole('button', { name: 'Preview' }));
- fireEvent.click(screen.getByRole('menuitem', { name: 'Code' }));
+ fireEvent.click(screen.getByRole('tab', { name: 'Code' }));
expect(screen.queryByTestId('artifact-preview-frame')).toBeNull();
- fireEvent.click(screen.getByRole('button', { name: 'Code' }));
- fireEvent.click(screen.getByRole('menuitem', { name: 'Preview' }));
-
- const remountedFrame = screen.getByTestId('artifact-preview-frame') as HTMLIFrameElement;
- const postMessageSpy = vi.spyOn(remountedFrame.contentWindow!, 'postMessage');
+ fireEvent.click(screen.getByRole('tab', { name: 'Preview' }));
await waitFor(() => {
const activeFrame = screen.getByTestId('artifact-preview-frame') as HTMLIFrameElement;
expect(activeFrame.getAttribute('data-od-render-mode')).toBe('srcdoc');
- });
- await waitFor(() => {
- const activations = srcDocActivationMessages(postMessageSpy.mock.calls);
- expect(activations.at(-1)?.html).toContain('data-od-selection-bridge');
- expect(activations.at(-1)?.html).toContain('Hero');
+ expect(activeFrame.srcdoc).toContain('data-od-edit-bridge');
+ expect(activeFrame.srcdoc).toContain('Hero');
});
});
@@ -683,7 +680,7 @@ describe('FileViewer SVG artifacts', () => {
// Back on Preview, clicking the entry opens the HTML page and closes the
// dead-end module tab (icons.jsx) in one move.
- fireEvent.click(screen.getByRole('button', { name: /preview/i }));
+ fireEvent.click(screen.getByRole('button', { name: /^preview$/i }));
fireEvent.click(await screen.findByRole('button', { name: /backups\.html/ }));
expect(onOpenFileReplacing).toHaveBeenCalledWith('backups.html', 'icons.jsx');
});
@@ -772,17 +769,16 @@ describe('FileViewer SVG artifacts', () => {
);
expect(container.querySelector('.deck-nav')).toBeTruthy();
- expect(container.querySelector('.palette-tweaks-anchor')).toBeTruthy();
+ expect(screen.queryByRole('button', { name: 'Manual' })).toBeNull();
expect(container.querySelector('.viewer-viewport-switcher')).toBeTruthy();
+ expect(screen.queryByTestId('palette-tweaks-toggle')).toBeNull();
- fireEvent.click(container.querySelector('.viewer-mode-trigger')!);
- fireEvent.click(screen.getByRole('menuitem', { name: /code/i }));
+ fireEvent.click(screen.getByRole('tab', { name: 'Code' }));
await waitFor(() => {
expect(container.querySelector('.deck-nav')).toBeNull();
- expect(container.querySelector('.palette-tweaks-anchor')).toBeNull();
expect(container.querySelector('.viewer-viewport-switcher')).toBeNull();
- expect(screen.getByTestId('manual-edit-mode-toggle')).toBeTruthy();
+ expect(screen.queryByTestId('manual-edit-mode-toggle')).toBeNull();
expect(screen.queryByTestId('draw-overlay-toggle')).toBeNull();
expect(screen.queryByTestId('palette-tweaks-toggle')).toBeNull();
expect(screen.queryByRole('button', { name: /100%/ })).toBeNull();
@@ -833,7 +829,7 @@ describe('FileViewer SVG artifacts', () => {
expect(screen.queryByLabelText('Pages project name')).toBeNull();
});
- it('nudges the share button once when an artifact becomes exportable', async () => {
+ it('nudges the export button once when an artifact becomes exportable', async () => {
const file = baseFile({
name: 'nudge.html',
path: 'nudge.html',
@@ -1427,58 +1423,41 @@ describe('FileViewer tweaks toolbar', () => {
});
}
- it('renders the toolbar Draw entry alongside restored Comment and Inspect entries', () => {
+ it('renders Annotation, Edit, and Draw as the primary preview tools', async () => {
render(
,
);
- expect(screen.getByTestId('palette-tweaks-toggle')).toBeTruthy();
+ expect(screen.queryByTestId('palette-tweaks-toggle')).toBeNull();
+ expect(screen.queryByTestId('inspect-mode-toggle')).toBeNull();
expect(screen.getByTestId('board-mode-toggle')).toBeTruthy();
- expect(screen.getByTestId('inspect-mode-toggle')).toBeTruthy();
+ expect(screen.queryByRole('button', { name: 'More annotation tools' })).toBeNull();
+ expect(screen.queryByRole('menuitem', { name: 'Pick element' })).toBeNull();
+ expect(screen.queryByRole('menuitem', { name: 'Region' })).toBeNull();
expect(screen.getByTestId('draw-overlay-toggle')).toBeTruthy();
- expect(screen.queryByPlaceholderText('Type anywhere to add a note')).toBeNull();
- expect(screen.queryByTestId('comment-mode-toggle')).toBeNull();
+ expect(screen.getByRole('button', { name: 'Draw' })).toBeTruthy();
+ expect(screen.getByTestId('screenshot-capture-toggle')).toBeTruthy();
+ expect(screen.getByRole('button', { name: 'Screenshot' })).toBeTruthy();
+ expect(screen.queryByPlaceholderText('Add a note for this annotation')).toBeNull();
expect(screen.queryByRole('button', { name: 'Pods' })).toBeNull();
fireEvent.click(screen.getByTestId('draw-overlay-toggle'));
- expect(screen.getByPlaceholderText('Type anywhere to add a note')).toBeTruthy();
- expect(screen.getByRole('button', { name: 'Click' })).toBeTruthy();
+ expect(screen.getByPlaceholderText('Add a note for this annotation')).toBeTruthy();
+ expect(screen.queryByRole('button', { name: 'Click' })).toBeNull();
+ expect(screen.getByRole('button', { name: 'Undo' })).toBeTruthy();
+ expect(screen.getByRole('button', { name: 'Redo' })).toBeTruthy();
- fireEvent.click(screen.getByTestId('draw-overlay-toggle'));
- expect(screen.queryByPlaceholderText('Type anywhere to add a note')).toBeNull();
- });
+ clickAgentTool('draw-overlay-toggle');
+ expect(screen.queryByPlaceholderText('Add a note for this annotation')).toBeNull();
- it('shows an inspect notice when a clicked child resolves to an annotated ancestor', async () => {
- render(
- ,
- );
-
- const frame = screen.getByTestId('artifact-preview-frame') as HTMLIFrameElement;
- fireEvent.click(screen.getByTestId('inspect-mode-toggle'));
-
- window.dispatchEvent(new MessageEvent('message', {
- source: frame.contentWindow,
- data: {
- type: 'od:comment-target',
- elementId: 'hero',
- selector: '[data-od-id="hero"]',
- label: 'main',
- text: 'Hero',
- style: {},
- clickedDescendant: {
- label: 'h1',
- text: 'Hero',
- },
- },
- }));
-
- const notice = await screen.findByTestId('inspect-ancestor-notice');
- expect(notice.textContent).toContain('You clicked h1');
- expect(notice.textContent).toContain('Editing main instead');
+ fireEvent.click(screen.getByTestId('screenshot-capture-toggle'));
+ expect(screen.getByPlaceholderText('Add a note for this annotation')).toBeTruthy();
+ expect(screen.queryByRole('status')).toBeNull();
+ expect(screen.getByTestId('screenshot-capture-toggle').getAttribute('aria-pressed')).toBe('true');
+ expect(screen.getByTestId('draw-overlay-toggle').getAttribute('aria-pressed')).toBe('false');
+ expect(screen.getByRole('button', { name: 'Send' })).toHaveProperty('disabled', false);
});
it('keeps the Draw bar open after queueing an annotation', () => {
@@ -1488,20 +1467,19 @@ describe('FileViewer tweaks toolbar', () => {
/>,
);
- fireEvent.click(screen.getByTestId('draw-overlay-toggle'));
- const note = screen.getByPlaceholderText('Type anywhere to add a note');
+ clickAgentTool('draw-overlay-toggle');
+ const note = screen.getByPlaceholderText('Add a note for this annotation');
fireEvent.change(note, { target: { value: 'mark this' } });
fireEvent.click(screen.getByRole('button', { name: 'Queue' }));
- expect(screen.getByPlaceholderText('Type anywhere to add a note')).toBeTruthy();
- expect(screen.getAllByRole('button', { name: 'Draw' })[1]?.getAttribute('aria-pressed')).toBe('true');
- expect(screen.getByRole('button', { name: 'Click' }).getAttribute('aria-pressed')).toBe('false');
+ expect(screen.getByPlaceholderText('Add a note for this annotation')).toBeTruthy();
+ expect(screen.queryByRole('button', { name: 'Click' })).toBeNull();
- fireEvent.click(screen.getByTestId('draw-overlay-toggle'));
- expect(screen.queryByPlaceholderText('Type anywhere to add a note')).toBeNull();
+ clickAgentTool('draw-overlay-toggle');
+ expect(screen.queryByPlaceholderText('Add a note for this annotation')).toBeNull();
});
- it('keeps the preloaded selection bridge mounted while the Draw bar switches to click mode', async () => {
+ it('keeps the preloaded selection bridge mounted while the Draw bar is open', async () => {
render(
{
expect((screen.getByTestId('artifact-preview-frame') as HTMLIFrameElement).getAttribute('data-od-render-mode')).toBe('url-load');
const inactiveSrcDocFrame = screen.getByTestId('artifact-preview-frame-srcdoc') as HTMLIFrameElement;
const postMessageSpy = vi.spyOn(inactiveSrcDocFrame.contentWindow!, 'postMessage');
- fireEvent.click(screen.getByTestId('draw-overlay-toggle'));
+ clickAgentTool('draw-overlay-toggle');
const frame = await waitFor(() => {
const activeFrame = screen.getByTestId('artifact-preview-frame') as HTMLIFrameElement;
@@ -1522,12 +1500,10 @@ describe('FileViewer tweaks toolbar', () => {
await waitFor(() => {
expect(srcDocActivationMessages(postMessageSpy.mock.calls).at(-1)?.html).toContain('data-od-selection-bridge');
});
- const initialSrcDoc = frame.srcdoc;
-
- fireEvent.click(screen.getByRole('button', { name: 'Click' }));
-
- await waitFor(() => expect(screen.getByRole('button', { name: 'Click' }).getAttribute('aria-pressed')).toBe('true'));
- expect((screen.getByTestId('artifact-preview-frame') as HTMLIFrameElement).srcdoc).toBe(initialSrcDoc);
+ expect(screen.queryByRole('button', { name: 'Click' })).toBeNull();
+ expect(screen.getByRole('button', { name: 'Undo' })).toBeTruthy();
+ expect(screen.getByRole('button', { name: 'Redo' })).toBeTruthy();
+ expect((screen.getByTestId('artifact-preview-frame') as HTMLIFrameElement).srcdoc).toBe(frame.srcdoc);
});
it('lets Draw direct send emit a queued annotation while a task is running', async () => {
@@ -1541,8 +1517,8 @@ describe('FileViewer tweaks toolbar', () => {
/>,
);
- fireEvent.click(screen.getByTestId('draw-overlay-toggle'));
- fireEvent.change(screen.getByPlaceholderText('Type anywhere to add a note'), {
+ clickAgentTool('draw-overlay-toggle');
+ fireEvent.change(screen.getByPlaceholderText('Add a note for this annotation'), {
target: { value: 'mark this' },
});
@@ -1592,15 +1568,15 @@ describe('FileViewer tweaks toolbar', () => {
/>,
);
- fireEvent.click(screen.getByTestId('board-mode-toggle'));
+ fireEvent.click(screen.getByTestId('comment-panel-toggle'));
expect(screen.getByTestId('comment-side-panel')).toBeTruthy();
expect(screen.queryByTestId('comment-saved-marker-pin-applying')).toBeNull();
expect(screen.queryByText('Already sent to Claude')).toBeNull();
});
- it('keeps the picker hint clear of the open comment side panel', () => {
- render(
+ it('keeps comments and annotation picker mutually exclusive', () => {
+ const { container } = render(
{
/>,
);
- fireEvent.click(screen.getByTestId('board-mode-toggle'));
-
+ fireEvent.click(screen.getByTestId('comment-panel-toggle'));
+ expect(container.querySelector('.comment-preview-layer')?.className).not.toContain('comment-preview-layer-comments-open');
expect(screen.getByTestId('comment-side-panel')).toBeTruthy();
- expect(screen.getByTestId('inspect-empty-hint-container').className).toContain(
- 'comment-side-panel-open',
- );
+ expect(screen.getByTestId('comment-panel-toggle').getAttribute('aria-pressed')).toBe('true');
+ expect(screen.getByTestId('board-mode-toggle').getAttribute('aria-pressed')).toBe('false');
- const closeButton = screen
- .getByTestId('comment-side-panel')
- .querySelector('.comment-side-close');
- expect(closeButton).toBeTruthy();
- fireEvent.click(closeButton!);
+ clickAgentTool('board-mode-toggle');
expect(screen.queryByTestId('comment-side-panel')).toBeNull();
- expect(screen.queryByTestId('comment-side-collapsed-rail')).toBeNull();
+ expect(container.querySelector('.comment-preview-layer')?.className).not.toContain('comment-preview-layer-comments-open');
+ expect(screen.getByTestId('comment-panel-toggle').getAttribute('aria-pressed')).toBe('false');
+ expect(screen.getByTestId('board-mode-toggle').getAttribute('aria-pressed')).toBe('true');
+ expect(screen.queryByTestId('inspect-empty-hint-container')).toBeNull();
+
+ fireEvent.click(screen.getByTestId('comment-panel-toggle'));
+
+ expect(screen.getByTestId('comment-side-panel')).toBeTruthy();
+ expect(screen.getByTestId('comment-panel-toggle').getAttribute('aria-pressed')).toBe('true');
+ expect(screen.getByTestId('board-mode-toggle').getAttribute('aria-pressed')).toBe('false');
expect(screen.queryByTestId('inspect-empty-hint-container')).toBeNull();
});
- it('keeps saved comment marker numbers aligned with the side panel order', () => {
+ it('keeps saved comment pins visible while adding another comment', async () => {
const olderComment: PreviewComment = {
id: 'comment-older',
projectId: 'project-1',
@@ -1666,11 +1646,46 @@ describe('FileViewer tweaks toolbar', () => {
/>,
);
- fireEvent.click(screen.getByTestId('board-mode-toggle'));
+ fireEvent.click(screen.getByTestId('comment-panel-toggle'));
- expect(screen.getAllByTestId('comment-side-item')[0]?.textContent).toContain('Newer comment');
- expect(screen.getByTestId('comment-saved-marker-pin-newer').textContent).toContain('1');
- expect(screen.getByTestId('comment-saved-marker-pin-older').textContent).toContain('2');
+ expect(screen.getByTestId('comment-side-panel')).toBeTruthy();
+ expect(screen.getByTestId('comment-saved-marker-pin-newer').textContent).toBe('C');
+ expect(screen.getByTestId('comment-saved-marker-pin-older').textContent).toBe('C');
+
+ clickAgentTool('board-mode-toggle');
+
+ expect(screen.queryByTestId('comment-side-panel')).toBeNull();
+ expect(screen.queryByTestId('comment-saved-marker-pin-newer')).toBeNull();
+ expect(screen.queryByTestId('comment-saved-marker-pin-older')).toBeNull();
+
+ fireEvent.click(screen.getByTestId('comment-panel-toggle'));
+
+ const frame = screen.getByTestId('artifact-preview-frame') as HTMLIFrameElement;
+ window.dispatchEvent(new MessageEvent('message', {
+ source: frame.contentWindow,
+ data: {
+ type: 'od:comment-target',
+ elementId: 'hero',
+ selector: '[data-od-id="hero"]',
+ label: 'Hero',
+ text: 'Hero',
+ position: { x: 8, y: 12, width: 120, height: 48 },
+ hoverPoint: { x: 12, y: 16 },
+ htmlHint: 'Hero',
+ },
+ }));
+
+ expect((await screen.findByTestId('comment-active-pin')).textContent).toBe('C');
+ expect(screen.getByTestId('comment-saved-marker-pin-newer')).toBeTruthy();
+ expect(screen.getByTestId('comment-saved-marker-pin-older')).toBeTruthy();
+
+ fireEvent.click(screen.getByTestId('comment-saved-marker-pin-newer'));
+ await waitFor(() => {
+ const activeItem = document.querySelector('[data-comment-id="comment-newer"]');
+ expect(activeItem?.className).toContain('active');
+ expect(activeItem?.getAttribute('aria-current')).toBe('true');
+ });
+ expect(document.querySelector('[data-comment-id="comment-older"]')?.className).not.toContain('active');
});
it('does not preload non-open element comments into the picker composer', async () => {
@@ -1702,7 +1717,7 @@ describe('FileViewer tweaks toolbar', () => {
);
const frame = screen.getByTestId('artifact-preview-frame') as HTMLIFrameElement;
- fireEvent.click(screen.getByTestId('board-mode-toggle'));
+ fireEvent.click(screen.getByTestId('comment-panel-toggle'));
window.dispatchEvent(new MessageEvent('message', {
source: frame.contentWindow,
@@ -1723,6 +1738,185 @@ describe('FileViewer tweaks toolbar', () => {
expect(screen.queryByText('Do not resurrect this note')).toBeNull();
});
+ it('keeps the comment composer focused on the note after picking an element', async () => {
+ render(
+ ,
+ );
+
+ const frame = screen.getByTestId('artifact-preview-frame') as HTMLIFrameElement;
+ fireEvent.click(screen.getByTestId('comment-panel-toggle'));
+
+ window.dispatchEvent(new MessageEvent('message', {
+ source: frame.contentWindow,
+ data: {
+ type: 'od:comment-target',
+ elementId: 'hero',
+ selector: '[data-od-id="hero"]',
+ label: 'p',
+ text: 'Hero',
+ position: { x: 8, y: 12, width: 312, height: 63 },
+ htmlHint: 'Hero
',
+ style: {
+ color: 'rgb(26, 25, 22)',
+ fontSize: '13.5px',
+ fontFamily: 'Inter, "PingFang SC", sans-serif',
+ lineHeight: '20px',
+ },
+ },
+ }));
+
+ expect(await screen.findByTestId('comment-popover-input')).toBeTruthy();
+ expect(screen.queryByTestId('annotation-style-summary')).toBeNull();
+ });
+
+ it('switches to the comment panel after saving an annotation comment', async () => {
+ function Harness() {
+ const [comments, setComments] = useState([]);
+ return (
+ {
+ const saved: PreviewComment = {
+ id: 'comment-saved',
+ projectId: 'project-1',
+ conversationId: 'conversation-1',
+ filePath: target.filePath,
+ elementId: target.elementId,
+ selector: target.selector,
+ label: target.label,
+ text: target.text,
+ htmlHint: target.htmlHint,
+ position: target.position,
+ style: target.style,
+ selectionKind: target.selectionKind,
+ memberCount: target.memberCount,
+ podMembers: target.podMembers,
+ note,
+ status: 'open',
+ createdAt: 20,
+ updatedAt: 20,
+ };
+ setComments([saved]);
+ return saved;
+ }}
+ />
+ );
+ }
+
+ render();
+
+ const frame = screen.getByTestId('artifact-preview-frame') as HTMLIFrameElement;
+ fireEvent.click(screen.getByTestId('comment-panel-toggle'));
+
+ window.dispatchEvent(new MessageEvent('message', {
+ source: frame.contentWindow,
+ data: {
+ type: 'od:comment-target',
+ elementId: 'hero',
+ selector: '[data-od-id="hero"]',
+ label: 'Hero',
+ text: 'Hero',
+ position: { x: 8, y: 12, width: 120, height: 48 },
+ htmlHint: 'Hero',
+ },
+ }));
+
+ const input = await screen.findByTestId('comment-popover-input');
+ fireEvent.change(input, { target: { value: '加大字号' } });
+ fireEvent.click(screen.getByTestId('comment-popover-save'));
+
+ await waitFor(() => expect(screen.queryByTestId('comment-popover')).toBeNull());
+ expect(screen.getByTestId('comment-side-panel')).toBeTruthy();
+ expect(screen.getByTestId('comment-panel-toggle').getAttribute('aria-pressed')).toBe('true');
+ expect(screen.getByText('加大字号')).toBeTruthy();
+ const activeItem = document.querySelector('[data-comment-id="comment-saved"]');
+ expect(activeItem?.className).toContain('active');
+ expect(activeItem?.getAttribute('aria-current')).toBe('true');
+ });
+
+ it('returns to element picking from the Comment button while another annotation tool is active', async () => {
+ render(
+ ,
+ );
+
+ clickAgentTool('draw-overlay-toggle');
+ expect(screen.getByTestId('draw-overlay-toggle').getAttribute('aria-pressed')).toBe('true');
+
+ fireEvent.click(screen.getByTestId('comment-panel-toggle'));
+
+ expect(screen.queryByRole('menuitem', { name: 'Pick element' })).toBeNull();
+ expect(screen.getByTestId('board-mode-toggle').getAttribute('aria-pressed')).toBe('false');
+ expect(screen.getByTestId('comment-panel-toggle').getAttribute('aria-pressed')).toBe('true');
+ });
+
+ it('shows element parameters on annotation hover and opens comments on click', async () => {
+ render(
+ ,
+ );
+
+ const frame = screen.getByTestId('artifact-preview-frame') as HTMLIFrameElement;
+ clickAgentTool('board-mode-toggle');
+
+ const target = {
+ elementId: 'hero',
+ selector: '[data-od-id="hero"]',
+ label: 'p',
+ text: 'Hero',
+ position: { x: 8, y: 12, width: 312, height: 63 },
+ hoverPoint: { x: 200, y: 100 },
+ htmlHint: 'Hero
',
+ style: {
+ color: 'rgb(26, 25, 22)',
+ fontSize: '13.5px',
+ fontFamily: 'Inter, "PingFang SC", sans-serif',
+ },
+ };
+
+ window.dispatchEvent(new MessageEvent('message', {
+ source: frame.contentWindow,
+ data: { ...target, type: 'od:comment-hover' },
+ }));
+
+ const summary = await screen.findByTestId('annotation-hover-style-summary');
+ expect(summary.textContent).toContain('Color');
+ expect(summary.textContent).toContain('#1A1916');
+ expect(summary.textContent).toContain('13.5px');
+ expect(screen.queryByTestId('inspect-panel')).toBeNull();
+ expect(screen.queryByTestId('comment-popover-input')).toBeNull();
+
+ window.dispatchEvent(new MessageEvent('message', {
+ source: frame.contentWindow,
+ data: { ...target, type: 'od:comment-target' },
+ }));
+
+ expect(await screen.findByTestId('comment-popover-input')).toBeTruthy();
+ expect(screen.getByTestId('comment-panel-toggle').getAttribute('aria-pressed')).toBe('true');
+ expect(screen.getByTestId('board-mode-toggle').getAttribute('aria-pressed')).toBe('false');
+ expect(screen.queryByTestId('inspect-panel')).toBeNull();
+ await waitFor(() => {
+ expect(screen.queryByTestId('annotation-hover-popover')).toBeNull();
+ });
+ });
+
it('closes an open saved-comment composer when that comment leaves the open state', async () => {
const openComment: PreviewComment = {
id: 'comment-status-transition',
@@ -1751,7 +1945,7 @@ describe('FileViewer tweaks toolbar', () => {
/>,
);
- fireEvent.click(screen.getByTestId('board-mode-toggle'));
+ fireEvent.click(screen.getByTestId('comment-panel-toggle'));
fireEvent.click(screen.getByRole('button', { name: 'Open comment for pin-transition' }));
expect((await screen.findByTestId('comment-popover-input') as HTMLTextAreaElement).value)
@@ -1802,6 +1996,7 @@ describe('FileViewer tweaks toolbar', () => {
},
]}
selectedIds={new Set(['comment-1'])}
+ activeCommentId={null}
collapsed={collapsed}
onCollapsedChange={(next) => {
onCollapseChange(next);
@@ -1834,141 +2029,6 @@ describe('FileViewer tweaks toolbar', () => {
expect(screen.queryByTestId('comment-side-selectbar')).toBeNull();
expect(screen.queryByTestId('comment-side-collapsed-rail')).toBeNull();
});
-
- // PR #1643 regression: the once-per-file guard that mirrors a `.twk-panel`
- // artifact's default-open state into the toolbar `tweaksMode` lives in a
- // message-event listener that previously had an empty deps array. The
- // handler therefore closed over the first-render `file.name`, so switching
- // to a second `.twk-panel` file left the guard comparing against the
- // stale captured name and never re-mirrored the new artifact's open state
- // back to ON. Surfaced by Siri-Ray in
- // https://github.com/nexu-io/open-design/pull/1643#discussion_r3266838151.
- it('mirrors __edit_mode_available default-open state for each switched-to .twk-panel file', async () => {
- function twkFile(name: string): ProjectFile {
- return baseFile({
- name,
- path: name,
- mime: 'text/html',
- kind: 'html',
- artifactManifest: {
- version: 1,
- kind: 'html',
- title: name,
- entry: name,
- renderer: 'html',
- exports: ['html'],
- },
- });
- }
-
- function Switcher() {
- const [file, setFile] = useState(twkFile('first.html'));
- return (
-
-
-
-
- );
- }
-
- render();
-
- const firstFrame = screen.getByTestId('artifact-preview-frame') as HTMLIFrameElement;
- const tweaksButton = () =>
- Array.from(document.querySelectorAll('button')).find(
- (b) => b.getAttribute('title') === 'Tweaks' || b.getAttribute('aria-label') === 'Tweaks',
- ) as HTMLButtonElement | undefined;
-
- // First file: artifact posts __edit_mode_available → toolbar starts ON.
- window.dispatchEvent(
- new MessageEvent('message', {
- source: firstFrame.contentWindow,
- data: { type: '__edit_mode_available' },
- }),
- );
- await waitFor(() => expect(tweaksButton()?.getAttribute('aria-pressed')).toBe('true'));
-
- // User toggles OFF on first file.
- fireEvent.click(tweaksButton()!);
- await waitFor(() => expect(tweaksButton()?.getAttribute('aria-pressed')).toBe('false'));
-
- // Switch to second file. The second artifact also mounts panel-visible
- // and emits __edit_mode_available. The toolbar must mirror that into ON
- // again — the bug was that the handler kept comparing against the first
- // file's name in a stale closure, so the second emission was treated as
- // a "second emission for the same file" and the OFF state stuck.
- fireEvent.click(screen.getByRole('button', { name: 'Switch file' }));
- const secondFrame = screen.getByTestId('artifact-preview-frame') as HTMLIFrameElement;
- window.dispatchEvent(
- new MessageEvent('message', {
- source: secondFrame.contentWindow,
- data: { type: '__edit_mode_available' },
- }),
- );
- await waitFor(() => expect(tweaksButton()?.getAttribute('aria-pressed')).toBe('true'));
- });
-
- // PR #1643 regression: Protocol A in `design-templates/tweaks/SKILL.md`
- // says the artifact MAY declare a default-closed panel via
- // `{ type: '__edit_mode_available', visible: false }`. The handler used
- // to unconditionally mirror availability into `tweaksMode = true`, so a
- // default-closed dynamic artifact would be force-opened by the next
- // `syncBridgeModes` posting `__activate_edit_mode`. The host must now
- // read `visible` and only flip to ON when the panel reports itself open
- // (or omits `visible` — back-compat shim for the common open-by-default
- // case). Surfaced by Siri-Ray in
- // https://github.com/nexu-io/open-design/pull/1643#discussion_r3269955351.
- it('respects __edit_mode_available { visible: false } for default-closed dynamic artifacts', async () => {
- const file = baseFile({
- name: 'closed.html',
- path: 'closed.html',
- mime: 'text/html',
- kind: 'html',
- artifactManifest: {
- version: 1,
- kind: 'html',
- title: 'closed',
- entry: 'closed.html',
- renderer: 'html',
- exports: ['html'],
- },
- });
-
- render(
- ,
- );
-
- const frame = screen.getByTestId('artifact-preview-frame') as HTMLIFrameElement;
- const tweaksButton = () =>
- Array.from(document.querySelectorAll('button')).find(
- (b) => b.getAttribute('title') === 'Tweaks' || b.getAttribute('aria-label') === 'Tweaks',
- ) as HTMLButtonElement | undefined;
-
- // Artifact announces availability AND declares the panel is currently
- // closed. The toolbar must enable (panel exists) but stay OFF — opening
- // it without intent would override the artifact-declared default.
- window.dispatchEvent(
- new MessageEvent('message', {
- source: frame.contentWindow,
- data: { type: '__edit_mode_available', visible: false },
- }),
- );
-
- await waitFor(() => expect(tweaksButton()?.disabled).toBe(false));
- expect(tweaksButton()?.getAttribute('aria-pressed')).toBe('false');
- });
});
describe('applyInspectOverridesToSource', () => {
@@ -2782,14 +2842,14 @@ describe('LiveArtifactViewer', () => {
expect(container.querySelector('.ghost-link')?.getAttribute('tabindex')).toBe('-1');
});
- fireEvent.click(screen.getByRole('button', { name: /preview/i }));
+ fireEvent.click(screen.getByRole('button', { name: 'Preview' }));
await waitFor(() => {
expect(screen.getByRole('link', { name: /^open$/i }).getAttribute('tabindex')).not.toBe('-1');
});
});
- it('keeps the live preview iframe mounted across viewport and tab changes', async () => {
+ it('preserves the live preview iframe when switching away from preview and back', async () => {
const fetchMock = vi.fn(async (input: string | URL | Request) => {
const url = typeof input === 'string' ? input : input instanceof Request ? input.url : String(input);
if (url === '/api/live-artifacts/la_1?projectId=proj_1') {
@@ -2798,41 +2858,36 @@ describe('LiveArtifactViewer', () => {
if (url === '/api/live-artifacts/la_1/refreshes?projectId=proj_1') {
return new Response(JSON.stringify({ refreshes: [] }), { status: 200 });
}
- if (url === '/api/live-artifacts/la_1/code?projectId=proj_1&variant=template') {
- return new Response('Preview', { status: 200 });
- }
return new Response(JSON.stringify({}), { status: 404 });
});
vi.stubGlobal('fetch', fetchMock);
- render(
+ const { container } = render(
,
);
- const frame = await screen.findByTestId('live-artifact-preview-frame');
- fireEvent.click(screen.getByRole('button', { name: /preview viewport/i }));
- fireEvent.click(screen.getByRole('option', { name: /mobile/i }));
+ await screen.findByRole('link', { name: /^open$/i });
- const previewLayer = frame.closest('.live-artifact-preview-layer');
- expect(previewLayer?.classList.contains('preview-viewport-mobile')).toBe(true);
+ const previewFrame = container.querySelector('[data-testid="live-artifact-preview-frame"]');
+ expect(previewFrame).toBeTruthy();
+ expect(container.querySelector('.live-artifact-preview-layer')?.getAttribute('data-active')).toBe('true');
fireEvent.click(screen.getByRole('button', { name: /code/i }));
await waitFor(() => {
- expect(previewLayer?.getAttribute('data-active')).toBe('false');
+ expect(container.querySelector('.live-artifact-preview-layer')?.getAttribute('data-active')).toBe('false');
});
- expect(screen.getByTestId('live-artifact-preview-frame')).toBe(frame);
+ expect(container.querySelector('[data-testid="live-artifact-preview-frame"]')).toBe(previewFrame);
- fireEvent.click(screen.getByRole('button', { name: /preview/i }));
+ fireEvent.click(screen.getByRole('button', { name: 'Preview' }));
await waitFor(() => {
- expect(previewLayer?.getAttribute('data-active')).toBe('true');
+ expect(container.querySelector('.live-artifact-preview-layer')?.getAttribute('data-active')).toBe('true');
});
- expect(screen.getByTestId('live-artifact-preview-frame')).toBe(frame);
- expect(frame.getAttribute('src')).toBe('/api/live-artifacts/la_1/preview?projectId=proj_1&v=0');
+ expect(container.querySelector('[data-testid="live-artifact-preview-frame"]')).toBe(previewFrame);
});
it('closes the present menu on Escape without tearing down the viewer', async () => {
diff --git a/apps/web/tests/components/HandoffButton.test.tsx b/apps/web/tests/components/HandoffButton.test.tsx
index 5102619a5..7b7824376 100644
--- a/apps/web/tests/components/HandoffButton.test.tsx
+++ b/apps/web/tests/components/HandoffButton.test.tsx
@@ -6,6 +6,7 @@ import { afterEach, describe, expect, it, vi } from 'vitest';
import { HandoffButton } from '../../src/components/HandoffButton';
import { I18nProvider, type Locale } from '../../src/i18n';
+import { readExpandedIndexCss } from '../helpers/read-expanded-css';
afterEach(() => {
cleanup();
@@ -34,14 +35,26 @@ function renderLocalized(locale: Locale) {
}
describe('HandoffButton i18n', () => {
+ it('keeps the header trigger as an icon-sized split control', () => {
+ const css = readExpandedIndexCss();
+
+ expect(css).toContain('.app .handoff-split');
+ expect(css).toContain('border: 1px solid transparent;');
+ expect(css).toContain('.app .handoff-trigger');
+ expect(css).toContain('width: 32px;');
+ expect(css).toContain('height: 30px;');
+ expect(css).toContain('.app .handoff-caret');
+ expect(css).toContain('width: 24px;');
+ });
+
it('localizes the primary handoff label', async () => {
stubEditors([{ id: 'finder', label: 'Finder', available: true }]);
renderLocalized('en');
const trigger = await screen.findByTestId('handoff-trigger');
- expect(trigger.getAttribute('title')).toBe('Hand off to Finder');
- expect(trigger.textContent).toContain('Hand off to Finder');
+ expect(trigger.getAttribute('title')).toBe('Open in Finder');
+ expect(trigger.querySelector('.handoff-trigger-label')?.classList.contains('sr-only')).toBe(true);
});
it('localizes the unavailable editor section', async () => {
diff --git a/apps/web/tests/components/ManualEditPanel.test.tsx b/apps/web/tests/components/ManualEditPanel.test.tsx
index 87e11e871..466aa0636 100644
--- a/apps/web/tests/components/ManualEditPanel.test.tsx
+++ b/apps/web/tests/components/ManualEditPanel.test.tsx
@@ -3,7 +3,6 @@ import { act } from 'react';
import { createRoot, type Root } from 'react-dom/client';
import { Simulate } from 'react-dom/test-utils';
import { JSDOM } from 'jsdom';
-import { I18nProvider } from '../../src/i18n';
import { ManualEditPanel, emptyManualEditDraft, manualEditPatchSummary, normalizeManualEditStyles, type ManualEditDraft } from '../../src/components/ManualEditPanel';
import { emptyManualEditStyles, type ManualEditPatch, type ManualEditStyles, type ManualEditTarget } from '../../src/edit-mode/types';
@@ -53,57 +52,11 @@ describe('ManualEditPanel', () => {
Reflect.deleteProperty(globalThis, 'IS_REACT_ACT_ENVIRONMENT');
});
- it('restores manual edit tabs for content, HTML, and source edits', () => {
+ it('renders the style inspector without the advanced editor entry', () => {
renderPanel();
expect(host.textContent).toContain('TYPOGRAPHY');
- expect(host.textContent).toContain('Content');
- expect(host.textContent).toContain('HTML');
- expect(host.textContent).toContain('Source');
- });
-
- it('applies selected-element HTML from the manual edit panel', () => {
- const onApplyPatch = vi.fn();
- renderPanel({
- onApplyPatch,
- outerHtml: 'Updated
',
- });
-
- clickTab('HTML');
- const htmlArea = host.querySelector('.manual-edit-code.tall') as HTMLTextAreaElement | null;
- if (!htmlArea) throw new Error('HTML editor not found');
- expect(htmlArea.value).toBe('Updated
');
- const apply = buttonByText('Apply HTML');
- act(() => {
- apply.dispatchEvent(new dom.window.MouseEvent('click', { bubbles: true }));
- });
-
- expect(onApplyPatch).toHaveBeenCalledWith(
- { id: 'hero-title', kind: 'set-outer-html', html: 'Updated
' },
- 'HTML: Hero Title',
- );
- });
-
- it('applies full source edits from the manual edit panel', () => {
- const onApplyPatch = vi.fn();
- renderPanel({
- onApplyPatch,
- fullSource: 'Updated source
',
- });
-
- clickTab('Source');
- const sourceArea = host.querySelector('.manual-edit-code.tall') as HTMLTextAreaElement | null;
- if (!sourceArea) throw new Error('Source editor not found');
- expect(sourceArea.value).toBe('Updated source
');
- const apply = buttonByText('Apply Source');
- act(() => {
- apply.dispatchEvent(new dom.window.MouseEvent('click', { bubbles: true }));
- });
-
- expect(onApplyPatch).toHaveBeenCalledWith(
- { kind: 'set-full-source', source: 'Updated source
' },
- 'Full source',
- );
+ expect(host.textContent).not.toContain('Advanced');
});
it('allows returning from an element inspector to the page inspector', () => {
@@ -120,55 +73,6 @@ describe('ManualEditPanel', () => {
expect(onClearSelection).toHaveBeenCalledTimes(1);
});
- it('lists hidden targets so they can be selected outside the canvas', () => {
- const onSelectTarget = vi.fn();
- const hiddenTarget: ManualEditTarget = {
- ...target,
- id: 'authors',
- label: 'Authors',
- tagName: 'section',
- kind: 'container',
- rect: { x: 0, y: 0, width: 0, height: 0 },
- isHidden: true,
- };
- renderPanel({ targets: [target, hiddenTarget], selectedTarget: null, onSelectTarget });
-
- const hiddenRow = Array.from(host.querySelectorAll('.manual-edit-layer-row'))
- .find((row) => row.textContent?.includes('Authors')) as HTMLButtonElement | undefined;
- if (!hiddenRow) throw new Error('Hidden target row not found');
- expect(hiddenRow.textContent).toContain('Hidden');
-
- act(() => {
- hiddenRow.dispatchEvent(new dom.window.MouseEvent('click', { bubbles: true }));
- });
-
- expect(onSelectTarget).toHaveBeenCalledWith(hiddenTarget);
- });
-
- it('renders layer panel labels from the active locale', () => {
- const hiddenTarget: ManualEditTarget = {
- ...target,
- id: 'authors',
- label: 'Authors',
- tagName: 'section',
- kind: 'container',
- isHidden: true,
- };
- renderPanel({ targets: [hiddenTarget], selectedTarget: null, locale: 'fr' });
-
- expect(host.textContent).toContain('Calques');
- expect(host.textContent).toContain('Masqué');
- expect(host.textContent).not.toContain('Layers');
- expect(host.textContent).not.toContain('Hidden');
- });
-
- it('renders the empty layers message from the active locale', () => {
- renderPanel({ targets: [], selectedTarget: null, locale: 'fr' });
-
- expect(host.textContent).toContain('Aucun calque modifiable trouvé.');
- expect(host.textContent).not.toContain('No editable layers found.');
- });
-
it('normalizes font stacks and writes a usable font-family value', () => {
const onDraftChange = vi.fn();
const onStyleChange = vi.fn();
@@ -514,48 +418,6 @@ describe('ManualEditPanel', () => {
expect(onStyleChange).toHaveBeenCalledWith('hero-title', { flexDirection: 'column' }, 'Style: Hero Title');
});
- it('keeps layout controls enabled for hidden layout containers', () => {
- const onStyleChange = vi.fn();
- const hiddenLayoutTarget: ManualEditTarget = {
- ...target,
- id: 'hidden-section',
- label: 'Hidden Section',
- tagName: 'section',
- kind: 'container',
- rect: { x: 0, y: 0, width: 0, height: 0 },
- isHidden: true,
- isLayoutContainer: true,
- };
- renderPanel({
- onStyleChange,
- targets: [hiddenLayoutTarget],
- selectedTarget: hiddenLayoutTarget,
- styles: {
- ...emptyManualEditStyles(),
- gap: '12px',
- flexDirection: 'row',
- },
- });
-
- const layoutSection = sectionByTitle('LAYOUT');
- expect(layoutSection.classList.contains('cc-section-inactive')).toBe(false);
- expect(layoutSection.textContent).not.toContain('Select a container or group to edit layout.');
- const gapIncrease = layoutSection.querySelector('button[aria-label="Gap increase"]') as HTMLButtonElement | null;
- const directionSelect = layoutSection.querySelector('select') as HTMLSelectElement | null;
- if (!gapIncrease || !directionSelect) throw new Error('Layout controls not found');
- expect(gapIncrease.disabled).toBe(false);
- expect(directionSelect.disabled).toBe(false);
-
- act(() => {
- gapIncrease.dispatchEvent(new dom.window.MouseEvent('click', { bubbles: true }));
- directionSelect.value = 'column';
- directionSelect.dispatchEvent(new dom.window.Event('change', { bubbles: true }));
- });
-
- expect(onStyleChange).toHaveBeenCalledWith('hidden-section', { gap: '13px' }, 'Style: Hidden Section');
- expect(onStyleChange).toHaveBeenCalledWith('hidden-section', { flexDirection: 'column' }, 'Style: Hidden Section');
- });
-
it('summarizes full-source history entries without rendering the full file', () => {
const source = '' + 'x'.repeat(10_000) + '';
@@ -572,20 +434,6 @@ describe('ManualEditPanel', () => {
return section;
}
- function buttonByText(text: string): HTMLButtonElement {
- const button = Array.from(host.querySelectorAll('button'))
- .find((candidate) => candidate.textContent === text) as HTMLButtonElement | undefined;
- if (!button) throw new Error(`${text} button not found`);
- return button;
- }
-
- function clickTab(text: string) {
- const button = buttonByText(text);
- act(() => {
- button.dispatchEvent(new dom.window.MouseEvent('click', { bubbles: true }));
- });
- }
-
function renderPanel({
onDraftChange = vi.fn(),
onApplyPatch = vi.fn(),
@@ -593,15 +441,10 @@ describe('ManualEditPanel', () => {
onStyleChange = vi.fn(),
onInvalidStyle = vi.fn(),
onClearSelection = vi.fn(),
- onSelectTarget = vi.fn<(target: ManualEditTarget) => void>(),
attributesText = '{}',
- targets = [target],
selectedTarget = target,
styles = emptyManualEditStyles(),
pageStylesEnabled = true,
- outerHtml = target.outerHtml,
- fullSource = '',
- locale,
}: {
onDraftChange?: OnDraftChange;
onApplyPatch?: OnApplyPatch;
@@ -609,27 +452,22 @@ describe('ManualEditPanel', () => {
onStyleChange?: OnStyleChange;
onInvalidStyle?: OnInvalidStyle;
onClearSelection?: OnClearSelection;
- onSelectTarget?: (target: ManualEditTarget) => void;
attributesText?: string;
- targets?: ManualEditTarget[];
selectedTarget?: ManualEditTarget | null;
styles?: ReturnType;
pageStylesEnabled?: boolean;
- outerHtml?: string;
- fullSource?: string;
- locale?: 'en' | 'fr';
} = {}) {
const draft = {
- ...emptyManualEditDraft(fullSource),
+ ...emptyManualEditDraft(''),
text: 'Updated copy',
attributesText,
styles,
- outerHtml,
+ outerHtml: target.outerHtml,
};
act(() => {
- const panel = (
+ root.render(
{
canUndo={false}
canRedo={false}
pageStylesEnabled={pageStylesEnabled}
- onSelectTarget={onSelectTarget}
+ onSelectTarget={vi.fn<(target: ManualEditTarget) => void>()}
onDraftChange={onDraftChange}
onStyleChange={onStyleChange}
onInvalidStyle={onInvalidStyle}
@@ -647,10 +485,7 @@ describe('ManualEditPanel', () => {
onCancelDraft={vi.fn<() => void>()}
onUndo={vi.fn<() => void>()}
onRedo={vi.fn<() => void>()}
- />
- );
- root.render(
- locale ? {panel} : panel,
+ />,
);
});
}
diff --git a/apps/web/tests/components/PreviewDrawOverlay.test.tsx b/apps/web/tests/components/PreviewDrawOverlay.test.tsx
index b515162a2..ad3d00198 100644
--- a/apps/web/tests/components/PreviewDrawOverlay.test.tsx
+++ b/apps/web/tests/components/PreviewDrawOverlay.test.tsx
@@ -1,10 +1,14 @@
// @vitest-environment jsdom
-import { fireEvent, render, waitFor } from '@testing-library/react';
-import { describe, expect, it, vi } from 'vitest';
+import { cleanup, fireEvent, render, waitFor } from '@testing-library/react';
+import { afterEach, describe, expect, it, vi } from 'vitest';
import { PreviewDrawOverlay } from '../../src/components/PreviewDrawOverlay';
+afterEach(() => {
+ cleanup();
+});
+
describe('PreviewDrawOverlay', () => {
it('uses the visible primary send action when Enter submits a note', async () => {
const annotation = vi.fn();
@@ -105,4 +109,17 @@ describe('PreviewDrawOverlay', () => {
expect(scrollBy).toHaveBeenCalledWith({ left: 12, top: 180, behavior: 'auto' });
});
+
+ it('closes the draw toolbar from an explicit close button', async () => {
+ const onActiveChange = vi.fn();
+ const { getByRole } = render(
+
+
+ ,
+ );
+
+ fireEvent.click(getByRole('button', { name: 'Close draw toolbar' }));
+
+ expect(onActiveChange).toHaveBeenCalledWith(false);
+ });
});
diff --git a/apps/web/tests/components/ProjectView.projectInstructions.test.tsx b/apps/web/tests/components/ProjectView.projectInstructions.test.tsx
index e5e141f00..2ae0ecc2f 100644
--- a/apps/web/tests/components/ProjectView.projectInstructions.test.tsx
+++ b/apps/web/tests/components/ProjectView.projectInstructions.test.tsx
@@ -89,7 +89,21 @@ vi.mock('../../src/state/projects', async () => {
});
vi.mock('../../src/components/AppChromeHeader', () => ({
- AppChromeHeader: ({ children }: { children: ReactNode }) => ,
+ AppChromeHeader: ({
+ children,
+ fileActionsBefore,
+ actions,
+ }: {
+ children: ReactNode;
+ fileActionsBefore?: ReactNode;
+ actions?: ReactNode;
+ }) => (
+
+ {children}
+ {fileActionsBefore}
+ {actions}
+
+ ),
}));
vi.mock('../../src/components/AvatarMenu', () => ({
@@ -170,6 +184,10 @@ function ProjectViewHarness({ initialProject }: { initialProject: Project }) {
const SAVED = 'Always use tabs, never spaces.';
+async function openProjectInstructionsFromSettings() {
+ fireEvent.click(await screen.findByTestId('project-settings-trigger'));
+}
+
describe('ProjectView – saved Project instructions surface (#1822)', () => {
beforeEach(() => {
mockedListConversations.mockResolvedValue([conversation]);
@@ -222,10 +240,10 @@ describe('ProjectView – saved Project instructions surface (#1822)', () => {
it('offers an add affordance and opens an empty editor when no instructions are saved', async () => {
render();
- const add = await screen.findByTestId('project-instructions-add');
+ expect(await screen.findByTestId('project-settings-trigger')).toBeTruthy();
expect(screen.queryByTestId('project-instructions-chip')).toBeNull();
- fireEvent.click(add);
+ await openProjectInstructionsFromSettings();
const textarea = screen.getByTestId('project-instructions-textarea') as HTMLTextAreaElement;
expect(textarea.value).toBe('');
@@ -235,7 +253,7 @@ describe('ProjectView – saved Project instructions surface (#1822)', () => {
mockedPatchProject.mockResolvedValue({ ...baseProject, customInstructions: SAVED });
render();
- fireEvent.click(await screen.findByTestId('project-instructions-add'));
+ await openProjectInstructionsFromSettings();
fireEvent.change(screen.getByTestId('project-instructions-textarea'), {
target: { value: SAVED },
});
diff --git a/apps/web/tests/components/ProjectView.run-cleanup.test.tsx b/apps/web/tests/components/ProjectView.run-cleanup.test.tsx
index 7b36707ec..7e4e5de88 100644
--- a/apps/web/tests/components/ProjectView.run-cleanup.test.tsx
+++ b/apps/web/tests/components/ProjectView.run-cleanup.test.tsx
@@ -9,6 +9,7 @@ import {
findExistingArtifactProjectFile,
resolveRetryTarget,
resolveSucceededRunStatus,
+ selectPrimaryProjectFile,
shouldClearActiveRunRefs,
} from '../../src/components/ProjectView';
import type { Artifact, ChatMessage, ProjectFile } from '../../src/types';
@@ -65,6 +66,22 @@ function artifactProjectFile(name: string, mtime: number): ProjectFile {
};
}
+function projectFile(
+ name: string,
+ kind: ProjectFile['kind'],
+ mtime: number,
+ artifactManifest?: ProjectFile['artifactManifest'],
+): ProjectFile {
+ return {
+ artifactManifest,
+ kind,
+ mime: kind === 'html' ? 'text/html' : 'application/octet-stream',
+ mtime,
+ name,
+ size: 100,
+ };
+}
+
vi.mock('../../src/i18n', () => ({
useI18n: () => ({
locale: 'en',
@@ -168,6 +185,30 @@ describe('terminal replay artifact recovery', () => {
});
});
+describe('selectPrimaryProjectFile', () => {
+ it('prefers explicit primary manifests over newer renderable files', () => {
+ const newer = projectFile('preview.html', 'html', 2_000);
+ const primary = projectFile('index.html', 'html', 1_000, {
+ entry: 'index.html',
+ exports: ['html'],
+ kind: 'html',
+ primary: true,
+ renderer: 'html',
+ title: 'Index',
+ version: 1,
+ });
+
+ expect(selectPrimaryProjectFile([newer, primary])).toBe(primary);
+ });
+
+ it('ignores sidecar manifest files when choosing a fallback', () => {
+ const sidecar = projectFile('index.html.artifact.json', 'text', 2_000);
+ const html = projectFile('index.html', 'html', 1_000);
+
+ expect(selectPrimaryProjectFile([sidecar, html])).toBe(html);
+ });
+});
+
describe('retry target resolution', () => {
const userMessage: ChatMessage = {
id: 'user-1',
diff --git a/apps/web/tests/components/ProjectView.run-isolation.test.tsx b/apps/web/tests/components/ProjectView.run-isolation.test.tsx
index 9d323014a..e9c8ac925 100644
--- a/apps/web/tests/components/ProjectView.run-isolation.test.tsx
+++ b/apps/web/tests/components/ProjectView.run-isolation.test.tsx
@@ -108,12 +108,30 @@ vi.mock('../../src/components/FileWorkspace', () => ({
FileWorkspace: ({
streaming,
onSendBoardCommentAttachments,
+ onCommentModeChange,
+ onFocusModeChange,
}: {
streaming: boolean;
onSendBoardCommentAttachments: (attachments: unknown[]) => void;
+ onCommentModeChange?: (active: boolean) => void;
+ onFocusModeChange?: (focused: boolean) => void;
}) => (
<>
+
+