refactor(FN-1364): extract modal inline styles to CSS classes

- Add CSS classes in styles.css for planning and breakdown modal styling
- Refactor MissionInterviewModal to use CSS classes instead of inline styles (164 lines reduced)
- Refactor PlanningModeModal to use CSS classes (67 lines reduced)
- Refactor SubtaskBreakdownModal to use CSS classes (26 lines reduced)
- Improve maintainability and consistency of modal styling
This commit is contained in:
gsxdsm
2026-04-09 17:57:06 -07:00
parent bc9e919a06
commit e2367225a7
4 changed files with 304 additions and 176 deletions

View File

@@ -584,7 +584,7 @@ export function MissionInterviewModal({
<div className="modal modal-lg planning-modal">
<div className="modal-header">
<div className="detail-title-row">
<Target size={20} style={{ color: "var(--triage)" }} />
<Target size={20} className="icon-triage" />
<h3>Plan Mission with AI</h3>
</div>
<div className="modal-header-actions">
@@ -617,7 +617,7 @@ export function MissionInterviewModal({
<div className="planning-initial">
<div className="planning-view-scroll">
<div className="planning-intro">
<Sparkles size={32} style={{ color: "var(--triage)", marginBottom: "12px" }} />
<Sparkles size={32} className="icon-triage-lg" />
<h4>Transform your vision into a structured mission</h4>
<p className="text-muted">
Describe what you want to build. The AI will interview you to understand scope,
@@ -667,7 +667,7 @@ export function MissionInterviewModal({
onClick={() => handleStartInterview()}
disabled={!missionGoal.trim()}
>
<Target size={16} style={{ marginRight: "8px" }} />
<Target size={16} className="icon-mr-8" />
Start Interview
</button>
</div>
@@ -676,7 +676,7 @@ export function MissionInterviewModal({
{view.type === "loading" && (
<div className="planning-loading">
<Loader2 size={40} className="spin" style={{ color: "var(--todo)" }} />
<Loader2 size={40} className="spin icon-todo" />
<p>{streamingOutput ? "AI is thinking..." : "Preparing next question..."}</p>
<div className="planning-thinking-container">
<button
@@ -708,21 +708,13 @@ export function MissionInterviewModal({
<div
className="ai-error-panel"
role="alert"
style={{
border: "1px solid var(--color-error, #dc2626)",
borderRadius: "10px",
background: "color-mix(in srgb, var(--color-error, #dc2626) 10%, transparent)",
padding: "14px",
display: "grid",
gap: "10px",
}}
>
<div className="ai-error-icon" style={{ fontSize: "20px" }}></div>
<div className="ai-error-icon"></div>
<div className="ai-error-message">{view.errorMessage}</div>
<div className="ai-error-actions" style={{ display: "flex", gap: "8px" }}>
<div className="ai-error-actions">
<button className="btn btn-primary" onClick={() => void handleRetryFromError()} disabled={isRetrying}>
{isRetrying ? <Loader2 size={14} className="spin" /> : <RefreshCw size={14} />}
<span style={{ marginLeft: "6px" }}>{isRetrying ? "Retrying..." : "Retry"}</span>
<span className="icon-ml-6">{isRetrying ? "Retrying..." : "Retry"}</span>
</button>
<button className="btn" onClick={handleCancel} disabled={isRetrying}>Cancel</button>
</div>
@@ -960,7 +952,7 @@ function InterviewQuestionForm({ question, progress, historyEntries, onSubmit }:
disabled={!isValid()}
>
Continue
<ArrowRight size={16} style={{ marginLeft: "4px" }} />
<ArrowRight size={16} className="icon-ml-4" />
</button>
</div>
</div>
@@ -1093,7 +1085,7 @@ function MissionPlanReview({
)}
<div className="planning-summary-header">
<CheckCircle size={24} style={{ color: "var(--color-success)" }} />
<CheckCircle size={24} className="icon-success" />
<h4>Mission Plan Ready</h4>
<p className="text-muted">
{summary.milestones.length} milestones, {totalFeatures} features. Review and edit before approving.
@@ -1124,76 +1116,61 @@ function MissionPlanReview({
{/* Milestones hierarchy */}
<div className="form-group">
<label>Roadmap</label>
<div style={{ display: "flex", flexDirection: "column", gap: "8px" }}>
<div className="roadmap-list">
{summary.milestones.map((milestone, mi) => (
<div
key={mi}
style={{
border: "1px solid var(--border-primary)",
borderRadius: "8px",
overflow: "hidden",
}}
className="roadmap-card"
>
{/* Milestone header */}
<div
style={{
display: "flex",
alignItems: "center",
gap: "8px",
padding: "10px 12px",
background: "var(--bg-secondary)",
cursor: "pointer",
}}
className="roadmap-card-header"
onClick={() => toggleMilestone(mi)}
>
{expandedMilestones.has(mi) ? (
<ChevronDown size={16} style={{ color: "var(--text-secondary)", flexShrink: 0 }} />
<ChevronDown size={16} className="icon-text-secondary" />
) : (
<ChevronRight size={16} style={{ color: "var(--text-secondary)", flexShrink: 0 }} />
<ChevronRight size={16} className="icon-text-secondary" />
)}
<Layers size={16} style={{ color: "var(--icon-milestone)", flexShrink: 0 }} />
<Layers size={16} className="icon-milestone" />
<input
type="text"
className="form-input"
style={{ flex: 1, padding: "4px 8px", fontSize: "13px", fontWeight: 600 }}
className="form-input roadmap-input-title"
value={milestone.title}
onChange={(e) => updateMilestone(mi, { title: e.target.value })}
onClick={(e) => e.stopPropagation()}
/>
{summary.milestones.length > 1 && (
<button
className="btn-icon"
style={{ flexShrink: 0 }}
className="btn-icon roadmap-shrink"
onClick={(e) => {
e.stopPropagation();
removeMilestone(mi);
}}
title="Remove milestone"
>
<Trash2 size={14} style={{ color: "var(--text-secondary)" }} />
<Trash2 size={14} className="icon-text-secondary" />
</button>
)}
</div>
{expandedMilestones.has(mi) && (
<div style={{ padding: "0 12px 12px 36px" }}>
<div className="roadmap-card-body">
<textarea
className="planning-textarea"
className="planning-textarea roadmap-textarea-md"
rows={2}
placeholder="Milestone description..."
style={{ marginTop: "8px", fontSize: "12px" }}
value={milestone.description || ""}
onChange={(e) => updateMilestone(mi, { description: e.target.value })}
/>
<div style={{ marginTop: "6px" }}>
<label style={{ fontSize: "11px", color: "var(--text-secondary)", fontWeight: 500 }}>
<div className="roadmap-field-group">
<label className="roadmap-field-label">
Verification Criteria
</label>
<textarea
className="planning-textarea"
className="planning-textarea roadmap-textarea-sm"
rows={2}
placeholder="How to confirm this milestone is complete..."
style={{ fontSize: "12px", marginTop: "2px" }}
value={milestone.verification || ""}
onChange={(e) => updateMilestone(mi, { verification: e.target.value })}
/>
@@ -1205,65 +1182,50 @@ function MissionPlanReview({
return (
<div
key={si}
style={{
marginTop: "8px",
border: "1px solid var(--border-primary)",
borderRadius: "6px",
overflow: "hidden",
}}
className="roadmap-slice-card"
>
<div
style={{
display: "flex",
alignItems: "center",
gap: "6px",
padding: "8px 10px",
background: "var(--bg-tertiary)",
cursor: "pointer",
}}
className="roadmap-slice-header"
onClick={() => toggleSlice(sliceKey)}
>
{expandedSlices.has(sliceKey) ? (
<ChevronDown size={14} style={{ color: "var(--text-secondary)", flexShrink: 0 }} />
<ChevronDown size={14} className="icon-text-secondary" />
) : (
<ChevronRight size={14} style={{ color: "var(--text-secondary)", flexShrink: 0 }} />
<ChevronRight size={14} className="icon-text-secondary" />
)}
<Package size={14} style={{ color: "var(--icon-slice)", flexShrink: 0 }} />
<Package size={14} className="icon-slice" />
<input
type="text"
className="form-input"
style={{ flex: 1, padding: "3px 6px", fontSize: "12px", fontWeight: 500 }}
className="form-input roadmap-input-subtitle"
value={slice.title}
onChange={(e) => updateSlice(mi, si, { title: e.target.value })}
onClick={(e) => e.stopPropagation()}
/>
{milestone.slices.length > 1 && (
<button
className="btn-icon"
style={{ flexShrink: 0 }}
className="btn-icon roadmap-shrink"
onClick={(e) => {
e.stopPropagation();
removeSlice(mi, si);
}}
title="Remove slice"
>
<Trash2 size={12} style={{ color: "var(--text-secondary)" }} />
<Trash2 size={12} className="icon-text-secondary" />
</button>
)}
</div>
{expandedSlices.has(sliceKey) && (
<div style={{ padding: "8px 10px 10px 30px" }}>
<div className="roadmap-slice-body">
{/* Slice verification */}
<div style={{ marginBottom: "8px" }}>
<label style={{ fontSize: "11px", color: "var(--text-secondary)", fontWeight: 500 }}>
<div className="roadmap-slice-field-group">
<label className="roadmap-field-label">
Slice Verification
</label>
<textarea
className="planning-textarea"
className="planning-textarea roadmap-textarea-xs"
rows={1}
placeholder="How to confirm this slice is done..."
style={{ fontSize: "11px", marginTop: "2px" }}
value={slice.verification || ""}
onChange={(e) => updateSlice(mi, si, { verification: e.target.value })}
/>
@@ -1272,73 +1234,41 @@ function MissionPlanReview({
{slice.features.map((feature, fi) => (
<div
key={fi}
style={{
display: "flex",
alignItems: "flex-start",
gap: "6px",
padding: "6px 0",
borderBottom:
fi < slice.features.length - 1
? "1px solid var(--border-primary)"
: "none",
}}
className="roadmap-feature-row"
>
<Box size={12} style={{ color: "var(--icon-feature)", marginTop: "4px", flexShrink: 0 }} />
<div style={{ flex: 1, minWidth: 0 }}>
<Box size={12} className="icon-feature" />
<div className="roadmap-feature-content">
<input
type="text"
className="form-input"
style={{ width: "100%", padding: "2px 6px", fontSize: "12px" }}
className="form-input roadmap-input-feature"
value={feature.title}
onChange={(e) =>
updateFeature(mi, si, fi, { title: e.target.value })
}
/>
{feature.description && (
<p
style={{
fontSize: "11px",
color: "var(--text-secondary)",
margin: "2px 0 0 6px",
}}
>
<p className="roadmap-feature-text">
{feature.description}
</p>
)}
{feature.acceptanceCriteria && (
<p
style={{
fontSize: "11px",
color: "var(--text-secondary)",
margin: "2px 0 0 6px",
fontStyle: "italic",
}}
>
<p className="roadmap-feature-text--italic">
AC: {feature.acceptanceCriteria}
</p>
)}
</div>
<button
className="btn-icon"
style={{ flexShrink: 0 }}
className="btn-icon roadmap-shrink"
onClick={() => removeFeature(mi, si, fi)}
title="Remove feature"
>
<Trash2 size={12} style={{ color: "var(--text-secondary)" }} />
<Trash2 size={12} className="icon-text-secondary" />
</button>
</div>
))}
<button
className="btn"
style={{
fontSize: "11px",
padding: "4px 8px",
marginTop: "6px",
gap: "4px",
display: "flex",
alignItems: "center",
}}
className="btn roadmap-add-feature-btn"
onClick={() => addFeature(mi, si)}
>
<Plus size={12} />
@@ -1360,7 +1290,7 @@ function MissionPlanReview({
<div className="planning-actions planning-summary-actions">
<button className="btn" onClick={onStartOver} disabled={isCreating}>
<ArrowLeft size={16} style={{ marginRight: "4px" }} />
<ArrowLeft size={16} className="icon-mr-4" />
Start Over
</button>
<button
@@ -1370,12 +1300,12 @@ function MissionPlanReview({
>
{isCreating ? (
<>
<Loader2 size={16} className="spin" style={{ marginRight: "8px" }} />
<Loader2 size={16} className="spin icon-mr-8" />
Creating Mission...
</>
) : (
<>
<CheckCircle size={16} style={{ marginRight: "8px" }} />
<CheckCircle size={16} className="icon-mr-8" />
Approve Plan
</>
)}

View File

@@ -678,7 +678,7 @@ export function PlanningModeModal({ isOpen, onClose, onTaskCreated, onTasksCreat
<div className="modal modal-lg planning-modal">
<div className="modal-header">
<div className="detail-title-row">
<Lightbulb size={20} style={{ color: "var(--triage)" }} />
<Lightbulb size={20} className="icon-triage" />
<h3>Planning Mode</h3>
</div>
<div className="modal-header-actions">
@@ -711,7 +711,7 @@ export function PlanningModeModal({ isOpen, onClose, onTaskCreated, onTasksCreat
<div className="planning-initial">
<div className="planning-view-scroll">
<div className="planning-intro">
<Sparkles size={32} style={{ color: "var(--triage)", marginBottom: "12px" }} />
<Sparkles size={32} className="icon-triage-lg" />
<h4>Transform your idea into a detailed task</h4>
<p className="text-muted">
Describe what you want to build in plain language. The AI will ask clarifying
@@ -757,7 +757,7 @@ export function PlanningModeModal({ isOpen, onClose, onTaskCreated, onTasksCreat
<label htmlFor="planning-modal-model" className="form-label">
Planning Model
{modelsLoading && (
<span className="text-muted" style={{ marginLeft: "8px", fontSize: "12px" }}>
<span className="text-muted text-muted-sm">
Loading models
</span>
)}
@@ -779,28 +779,20 @@ export function PlanningModeModal({ isOpen, onClose, onTaskCreated, onTasksCreat
onToggleModelFavorite={handleToggleFavoriteModel}
/>
{modelsError && (
<div className="form-hint" style={{ marginTop: "6px", fontSize: "12px", color: "var(--color-error)" }}>
<div className="form-hint form-hint-error">
{modelsError}{" "}
<button
type="button"
className="text-link-btn"
onClick={() => {
void loadModels();
}}
style={{
fontSize: "12px",
background: "none",
border: "none",
color: "inherit",
textDecoration: "underline",
cursor: "pointer",
padding: 0,
}}
>
Retry
</button>
</div>
)}
<div className="model-selector-current" style={{ marginTop: "8px" }}>
<div className="model-selector-current model-selector-current--spaced">
<span
className={`model-badge ${
planningModelProvider && planningModelId
@@ -820,7 +812,7 @@ export function PlanningModeModal({ isOpen, onClose, onTaskCreated, onTasksCreat
onClick={() => handleStartPlanning()}
disabled={!initialPlan.trim()}
>
<Lightbulb size={16} style={{ marginRight: "8px" }} />
<Lightbulb size={16} className="icon-mr-8" />
Start Planning
</button>
</div>
@@ -829,7 +821,7 @@ export function PlanningModeModal({ isOpen, onClose, onTaskCreated, onTasksCreat
{view.type === "loading" && (
<div className="planning-loading">
<Loader2 size={40} className="spin" style={{ color: "var(--todo)" }} />
<Loader2 size={40} className="spin icon-todo" />
<p>{streamingOutput ? "AI is thinking..." : "Generating next question..."}</p>
<div className="planning-thinking-container">
<button
@@ -861,21 +853,13 @@ export function PlanningModeModal({ isOpen, onClose, onTaskCreated, onTasksCreat
<div
className="ai-error-panel"
role="alert"
style={{
border: "1px solid var(--color-error, #dc2626)",
borderRadius: "10px",
background: "color-mix(in srgb, var(--color-error, #dc2626) 10%, transparent)",
padding: "14px",
display: "grid",
gap: "10px",
}}
>
<div className="ai-error-icon" style={{ fontSize: "20px" }}></div>
<div className="ai-error-icon"></div>
<div className="ai-error-message">{view.errorMessage}</div>
<div className="ai-error-actions" style={{ display: "flex", gap: "8px" }}>
<div className="ai-error-actions">
<button className="btn btn-primary" onClick={() => void handleRetryFromError()} disabled={isRetrying}>
{isRetrying ? <Loader2 size={14} className="spin" /> : <RefreshCw size={14} />}
<span style={{ marginLeft: "6px" }}>{isRetrying ? "Retrying..." : "Retry"}</span>
<span className="icon-ml-6">{isRetrying ? "Retrying..." : "Retry"}</span>
</button>
<button className="btn" onClick={handleCancel} disabled={isRetrying}>Dismiss</button>
</div>
@@ -886,7 +870,7 @@ export function PlanningModeModal({ isOpen, onClose, onTaskCreated, onTasksCreat
{view.type === "creating" && (
<div className="planning-loading">
<Loader2 size={40} className="spin" style={{ color: "var(--todo)" }} />
<Loader2 size={40} className="spin icon-todo" />
<p>Creating tasks...</p>
</div>
)}
@@ -1139,7 +1123,7 @@ function QuestionForm({ question, progress, historyEntries, onSubmit, onBack }:
<div className="planning-actions">
{onBack && (
<button className="btn" onClick={onBack}>
<ArrowLeft size={16} style={{ marginRight: "4px" }} />
<ArrowLeft size={16} className="icon-mr-4" />
Back
</button>
)}
@@ -1149,7 +1133,7 @@ function QuestionForm({ question, progress, historyEntries, onSubmit, onBack }:
disabled={!isValid()}
>
Continue
<ArrowRight size={16} style={{ marginLeft: "4px" }} />
<ArrowRight size={16} className="icon-ml-4" />
</button>
</div>
</div>
@@ -1201,7 +1185,7 @@ function SummaryView({
)}
<div className="planning-summary-header">
<CheckCircle size={24} style={{ color: "var(--color-success)" }} />
<CheckCircle size={24} className="icon-success" />
<h4>Planning Complete!</h4>
<p className="text-muted">Review and refine your task before creating it.</p>
</div>
@@ -1282,7 +1266,7 @@ function SummaryView({
<div className="planning-actions planning-summary-actions">
<button className="btn" onClick={onRefine} disabled={isLoading}>
<ArrowLeft size={16} style={{ marginRight: "4px" }} />
<ArrowLeft size={16} className="icon-mr-4" />
Refine Further
</button>
<div className="planning-summary-actions-right">
@@ -1294,12 +1278,12 @@ function SummaryView({
>
{isLoading ? (
<>
<Loader2 size={16} className="spin" style={{ marginRight: "8px" }} />
<Loader2 size={16} className="spin icon-mr-8" />
Breaking down...
</>
) : (
<>
<ListTree size={16} style={{ marginRight: "8px" }} />
<ListTree size={16} className="icon-mr-8" />
Break into Tasks
</>
)}
@@ -1311,12 +1295,12 @@ function SummaryView({
>
{isLoading ? (
<>
<Loader2 size={16} className="spin" style={{ marginRight: "8px" }} />
<Loader2 size={16} className="spin icon-mr-8" />
Creating...
</>
) : (
<>
<CheckCircle size={16} style={{ marginRight: "8px" }} />
<CheckCircle size={16} className="icon-mr-8" />
Create Task
</>
)}
@@ -1480,7 +1464,7 @@ function BreakdownView({
<div className="planning-summary">
<div className="planning-view-scroll planning-summary-scroll">
<div className="planning-summary-header">
<ListTree size={24} style={{ color: "var(--triage)" }} />
<ListTree size={24} className="icon-triage" />
<h4>Break into Tasks</h4>
<p className="text-muted">
Review and edit the subtasks generated from your plan. Adjust titles,
@@ -1516,8 +1500,7 @@ function BreakdownView({
onDragLeave={handleDragLeave}
>
<div
className="detail-title-row subtask-item-header"
style={{ justifyContent: "space-between" }}
className="detail-title-row subtask-item-header subtask-item-header--between"
>
<div className="subtask-drag-handle" title="Drag to reorder">
<GripVertical size={16} />
@@ -1652,7 +1635,7 @@ function BreakdownView({
})}
<button type="button" className="btn" onClick={addSubtask} disabled={isLoading}>
<Plus size={16} style={{ marginRight: 6 }} /> Add subtask
<Plus size={16} className="icon-mr-6" /> Add subtask
</button>
{hasDependencyCycle(subtasks) && (
@@ -1665,7 +1648,7 @@ function BreakdownView({
<div className="planning-actions planning-summary-actions">
<button className="btn" onClick={onBack} disabled={isLoading}>
<ArrowLeft size={16} style={{ marginRight: "4px" }} />
<ArrowLeft size={16} className="icon-mr-4" />
Back to Summary
</button>
<button
@@ -1675,7 +1658,7 @@ function BreakdownView({
>
{isLoading ? (
<>
<Loader2 size={16} className="spin" style={{ marginRight: 8 }} />
<Loader2 size={16} className="spin icon-mr-6" />
Creating...
</>
) : (

View File

@@ -519,7 +519,7 @@ export function SubtaskBreakdownModal({ isOpen, onClose, initialDescription, onT
<div className="modal modal-lg planning-modal">
<div className="modal-header">
<div className="detail-title-row">
<ListTree size={20} style={{ color: "var(--triage)" }} />
<ListTree size={20} className="icon-triage" />
<h3>Subtask Breakdown</h3>
</div>
<div className="modal-header-actions">
@@ -565,7 +565,7 @@ export function SubtaskBreakdownModal({ isOpen, onClose, initialDescription, onT
<div className="conversation-separator" />
</>
)}
<Loader2 size={40} className="spin" style={{ color: "var(--todo)" }} />
<Loader2 size={40} className="spin icon-todo" />
<p>AI is generating subtasks...</p>
<div className="planning-thinking-container">
<button className="planning-thinking-toggle" onClick={() => setShowThinking(!showThinking)} type="button">
@@ -592,21 +592,13 @@ export function SubtaskBreakdownModal({ isOpen, onClose, initialDescription, onT
<div
className="ai-error-panel"
role="alert"
style={{
border: "1px solid var(--color-error, #dc2626)",
borderRadius: "10px",
background: "color-mix(in srgb, var(--color-error, #dc2626) 10%, transparent)",
padding: "14px",
display: "grid",
gap: "10px",
}}
>
<div className="ai-error-icon" style={{ fontSize: "20px" }}></div>
<div className="ai-error-icon"></div>
<div className="ai-error-message">{view.errorMessage}</div>
<div className="ai-error-actions" style={{ display: "flex", gap: "8px" }}>
<div className="ai-error-actions">
<button className="btn btn-primary" onClick={() => void handleRetry()} disabled={isRetrying}>
{isRetrying ? <Loader2 size={14} className="spin" /> : <RefreshCw size={14} />}
<span style={{ marginLeft: "6px" }}>{isRetrying ? "Retrying..." : "Retry"}</span>
<span className="icon-ml-6">{isRetrying ? "Retrying..." : "Retry"}</span>
</button>
<button className="btn" onClick={() => void handleClose()} disabled={isRetrying}>Cancel</button>
</div>
@@ -626,7 +618,7 @@ export function SubtaskBreakdownModal({ isOpen, onClose, initialDescription, onT
)}
<div className="planning-summary-header">
<CheckCircle size={24} style={{ color: "var(--color-success)" }} />
<CheckCircle size={24} className="icon-success" />
<h4>Review your subtasks</h4>
<p className="text-muted">Edit titles, descriptions, sizes, and dependencies before creating all tasks at once.</p>
</div>
@@ -656,7 +648,7 @@ export function SubtaskBreakdownModal({ isOpen, onClose, initialDescription, onT
onDrop={handleDrop(subtask.id)}
onDragLeave={handleDragLeave}
>
<div className="detail-title-row subtask-item-header" style={{ justifyContent: "space-between" }}>
<div className="detail-title-row subtask-item-header subtask-item-header--between">
<div className="subtask-drag-handle" title="Drag to reorder">
<GripVertical size={16} />
<strong>{subtask.id}</strong>
@@ -765,7 +757,7 @@ export function SubtaskBreakdownModal({ isOpen, onClose, initialDescription, onT
})}
<button type="button" className="btn" onClick={addSubtask} disabled={view.type === "creating"}>
<Plus size={16} style={{ marginRight: 6 }} /> Add subtask
<Plus size={16} className="icon-mr-6" /> Add subtask
</button>
{hasDependencyCycle(subtasks) && (
@@ -781,7 +773,7 @@ export function SubtaskBreakdownModal({ isOpen, onClose, initialDescription, onT
<button className="btn btn-primary" onClick={() => void handleCreateTasks()} disabled={view.type === "creating" || isInvalid}>
{view.type === "creating" ? (
<>
<Loader2 size={16} className="spin" style={{ marginRight: 8 }} />
<Loader2 size={16} className="spin icon-mr-6" />
Creating...
</>
) : (

View File

@@ -16004,6 +16004,229 @@ body[data-color-theme="terminal"][data-theme="light"]::before {
}
}
/* === Planning & Breakdown Modal — Inline Style Replacements === */
/* Icon color utilities */
.icon-triage {
color: var(--triage);
}
.icon-triage-lg {
color: var(--triage);
margin-bottom: 12px;
}
.icon-todo {
color: var(--todo);
}
.icon-success {
color: var(--color-success);
}
.icon-text-secondary {
color: var(--text-secondary);
flex-shrink: 0;
}
.icon-milestone {
color: var(--icon-milestone);
flex-shrink: 0;
}
.icon-slice {
color: var(--icon-slice);
flex-shrink: 0;
}
.icon-feature {
color: var(--icon-feature);
margin-top: 4px;
flex-shrink: 0;
}
/* Icon margin utilities */
.icon-mr-4 {
margin-right: 4px;
}
.icon-mr-6 {
margin-right: 6px;
}
.icon-mr-8 {
margin-right: 8px;
}
.icon-ml-4 {
margin-left: 4px;
}
.icon-ml-6 {
margin-left: 6px;
}
/* Error panel */
.ai-error-panel {
border: 1px solid var(--color-error);
border-radius: 10px;
background: color-mix(in srgb, var(--color-error) 10%, transparent);
padding: 14px;
display: grid;
gap: 10px;
}
.ai-error-icon {
font-size: 20px;
}
.ai-error-actions {
display: flex;
gap: 8px;
}
/* Text link button */
.text-link-btn {
font-size: 12px;
background: none;
border: none;
color: inherit;
text-decoration: underline;
cursor: pointer;
padding: 0;
}
/* Form hint error variant */
.form-hint-error {
margin-top: 6px;
font-size: 12px;
color: var(--color-error);
}
/* Text muted small */
.text-muted-sm {
margin-left: 8px;
font-size: 12px;
}
/* Model selector spacing */
.model-select-row--left {
margin-right: auto;
min-width: min(100%, 320px);
max-width: 420px;
text-align: left;
}
.model-selector-current--spaced {
margin-top: 8px;
}
/* Roadmap hierarchy (MissionInterviewModal) */
.roadmap-list {
display: flex;
flex-direction: column;
gap: 8px;
}
.roadmap-card {
border: 1px solid var(--border-primary);
border-radius: 8px;
overflow: hidden;
}
.roadmap-card-header {
display: flex;
align-items: center;
gap: 8px;
padding: 10px 12px;
background: var(--bg-secondary);
cursor: pointer;
}
.roadmap-card-body {
padding: 0 12px 12px 36px;
}
.roadmap-textarea-sm {
font-size: 12px;
margin-top: 2px;
}
.roadmap-textarea-md {
font-size: 12px;
margin-top: 8px;
}
.roadmap-textarea-xs {
font-size: 11px;
margin-top: 2px;
}
.roadmap-field-label {
font-size: 11px;
color: var(--text-secondary);
font-weight: 500;
}
.roadmap-field-group {
margin-top: 6px;
}
.roadmap-slice-card {
margin-top: 8px;
border: 1px solid var(--border-primary);
border-radius: 6px;
overflow: hidden;
}
.roadmap-slice-header {
display: flex;
align-items: center;
gap: 6px;
padding: 8px 10px;
background: var(--bg-tertiary);
cursor: pointer;
}
.roadmap-slice-body {
padding: 8px 10px 10px 30px;
}
.roadmap-slice-field-group {
margin-bottom: 8px;
}
.roadmap-input-title {
flex: 1;
padding: 4px 8px;
font-size: 13px;
font-weight: 600;
}
.roadmap-input-subtitle {
flex: 1;
padding: 3px 6px;
font-size: 12px;
font-weight: 500;
}
.roadmap-input-feature {
width: 100%;
padding: 2px 6px;
font-size: 12px;
}
.roadmap-feature-row {
display: flex;
align-items: flex-start;
gap: 6px;
padding: 6px 0;
}
.roadmap-feature-row + .roadmap-feature-row {
border-top: 1px solid var(--border-primary);
}
.roadmap-feature-text {
font-size: 11px;
color: var(--text-secondary);
margin: 2px 0 0 6px;
}
.roadmap-feature-text--italic {
font-size: 11px;
color: var(--text-secondary);
margin: 2px 0 0 6px;
font-style: italic;
}
.roadmap-feature-content {
flex: 1;
min-width: 0;
}
.roadmap-add-feature-btn {
font-size: 11px;
padding: 4px 8px;
margin-top: 6px;
gap: 4px;
display: flex;
align-items: center;
}
.roadmap-shrink {
flex-shrink: 0;
}
/* Subtask header override */
.subtask-item-header--between {
justify-content: space-between;
}
/* ============================================================
USAGE INDICATOR STYLES
============================================================ */