fix(responsive): audit and fix FlowPilot + analytics components for mobile/tablet

Add responsive Tailwind classes across 11 FlowPilot-related components:
- FlowPilotSession: collapsible mobile sidebar summary, responsive padding
- FlowPilotActionBar: stacked buttons on mobile, responsive resolve modal
- FlowPilotIntake: responsive submit area, padding, heading sizes
- FlowPilotStepCard: responsive padding (p-3/p-4/p-5), stacked action buttons
- FlowPilotOptions: responsive padding, 44px touch targets
- SessionDocView: responsive card padding, touch-friendly star ratings
- EscalateModal: stacked buttons on mobile with min touch targets
- EscalationQueue: responsive card padding, touch targets
- InSessionScriptGenerator: responsive padding, stacked continue buttons
- ReviewQueuePage: responsive two-panel layout (stacked on mobile)
- FlowPilotAnalyticsPage: responsive header, chart card padding

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-19 20:19:52 +00:00
parent 967a2b2c59
commit 1f4a8a6389
11 changed files with 143 additions and 76 deletions

View File

@@ -55,18 +55,18 @@ export function EscalateModal({ open, onClose, onEscalate, isProcessing, hasPsaT
</p>
</div>
<div className="flex gap-2">
<div className="flex flex-col-reverse gap-2 sm:flex-row">
<button
onClick={handleClose}
disabled={isProcessing}
className="flex-1 rounded-lg bg-[rgba(255,255,255,0.04)] border border-[rgba(255,255,255,0.06)] px-4 py-2.5 text-sm font-medium text-foreground hover:border-[rgba(255,255,255,0.12)] transition-colors disabled:opacity-50"
className="flex-1 rounded-lg bg-[rgba(255,255,255,0.04)] border border-[rgba(255,255,255,0.06)] px-4 py-2.5 min-h-[44px] text-sm font-medium text-foreground hover:border-[rgba(255,255,255,0.12)] transition-colors disabled:opacity-50"
>
Cancel
</button>
<button
onClick={handleSubmit}
disabled={!reason.trim() || reason.trim().length < 5 || isProcessing}
className="flex-1 flex items-center justify-center gap-2 rounded-lg bg-amber-500/90 px-4 py-2.5 text-sm font-semibold text-[#101114] hover:bg-amber-500 active:scale-[0.97] disabled:opacity-40 transition-all"
className="flex-1 flex items-center justify-center gap-2 rounded-lg bg-amber-500/90 px-4 py-2.5 min-h-[44px] text-sm font-semibold text-[#101114] hover:bg-amber-500 active:scale-[0.97] disabled:opacity-40 transition-all"
>
{isProcessing ? (
<Loader2 size={14} className="animate-spin" />

View File

@@ -93,7 +93,7 @@ export function EscalationQueue({ onPickup }: EscalationQueueProps) {
</div>
{sessions.map((session) => (
<div key={session.id} className="glass-card p-4 space-y-3">
<div key={session.id} className="glass-card p-3 sm:p-4 space-y-3">
<div>
<p className="text-sm font-semibold text-foreground">
{session.problem_summary || 'Untitled session'}
@@ -129,7 +129,7 @@ export function EscalationQueue({ onPickup }: EscalationQueueProps) {
<button
onClick={() => handlePickup(session.id)}
className="w-full rounded-lg bg-gradient-brand px-4 py-2 text-sm font-semibold text-[#101114] shadow-lg shadow-primary/20 hover:opacity-90 active:scale-[0.97] transition-all"
className="w-full min-h-[44px] rounded-lg bg-gradient-brand px-4 py-2 text-sm font-semibold text-[#101114] shadow-lg shadow-primary/20 hover:opacity-90 active:scale-[0.97] transition-all"
>
Pick Up Session
</button>

View File

@@ -53,30 +53,32 @@ export function FlowPilotActionBar({
<>
{/* Bottom bar */}
<div
className="flex items-center gap-3 border-t px-5 py-3"
className="flex flex-col gap-2 sm:flex-row sm:items-center sm:gap-3 border-t px-3 py-3 sm:px-5"
style={{ borderColor: 'var(--glass-border)', background: 'rgba(16, 17, 20, 0.8)', backdropFilter: 'blur(12px)' }}
>
<button
onClick={() => { setShowResolve(true); setShowEscalate(false) }}
disabled={!canResolve || isProcessing}
className="flex items-center gap-2 rounded-lg bg-emerald-500/10 border border-emerald-500/20 px-4 py-2 text-sm font-medium text-emerald-400 hover:bg-emerald-500/20 disabled:opacity-40 disabled:pointer-events-none transition-colors"
>
<CheckCircle2 size={16} />
Resolve
</button>
<button
onClick={() => setShowEscalate(true)}
disabled={!canEscalate || isProcessing}
className="flex items-center gap-2 rounded-lg bg-amber-500/10 border border-amber-500/20 px-4 py-2 text-sm font-medium text-amber-400 hover:bg-amber-500/20 disabled:opacity-40 disabled:pointer-events-none transition-colors"
>
<ArrowUpRight size={16} />
Escalate
</button>
<div className="flex gap-2 sm:gap-3">
<button
onClick={() => { setShowResolve(true); setShowEscalate(false) }}
disabled={!canResolve || isProcessing}
className="flex flex-1 sm:flex-initial items-center justify-center gap-2 rounded-lg bg-emerald-500/10 border border-emerald-500/20 px-4 py-2 min-h-[44px] text-sm font-medium text-emerald-400 hover:bg-emerald-500/20 disabled:opacity-40 disabled:pointer-events-none transition-colors"
>
<CheckCircle2 size={16} />
Resolve
</button>
<button
onClick={() => setShowEscalate(true)}
disabled={!canEscalate || isProcessing}
className="flex flex-1 sm:flex-initial items-center justify-center gap-2 rounded-lg bg-amber-500/10 border border-amber-500/20 px-4 py-2 min-h-[44px] text-sm font-medium text-amber-400 hover:bg-amber-500/20 disabled:opacity-40 disabled:pointer-events-none transition-colors"
>
<ArrowUpRight size={16} />
Escalate
</button>
</div>
{onPause && (
<button
onClick={handlePause}
disabled={isProcessing || submitting}
className="flex items-center gap-2 rounded-lg bg-[rgba(255,255,255,0.04)] border border-[rgba(255,255,255,0.06)] px-4 py-2 text-sm font-medium text-muted-foreground hover:text-foreground hover:border-[rgba(255,255,255,0.12)] disabled:opacity-40 disabled:pointer-events-none transition-colors ml-auto"
className="flex items-center justify-center gap-2 rounded-lg bg-[rgba(255,255,255,0.04)] border border-[rgba(255,255,255,0.06)] px-4 py-2 min-h-[44px] text-sm font-medium text-muted-foreground hover:text-foreground hover:border-[rgba(255,255,255,0.12)] disabled:opacity-40 disabled:pointer-events-none transition-colors sm:ml-auto"
>
<Pause size={16} />
Pause
@@ -86,8 +88,8 @@ export function FlowPilotActionBar({
{/* Resolve modal */}
{showResolve && (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm">
<div className="glass-card-static w-full max-w-lg p-6">
<div className="fixed inset-0 z-50 flex items-end sm:items-center justify-center bg-black/60 backdrop-blur-sm">
<div className="glass-card-static w-full max-w-full sm:max-w-lg mx-0 sm:mx-4 p-4 sm:p-6 rounded-t-2xl sm:rounded-2xl">
<h3 className="font-heading text-lg font-semibold text-foreground mb-1">Resolve Session</h3>
<p className="text-sm text-muted-foreground mb-4">Summarize what fixed the issue. This will be included in the auto-generated documentation.</p>
<textarea
@@ -98,17 +100,17 @@ export function FlowPilotActionBar({
rows={4}
autoFocus
/>
<div className="mt-4 flex justify-end gap-2">
<div className="mt-4 flex flex-col-reverse gap-2 sm:flex-row sm:justify-end">
<button
onClick={() => setShowResolve(false)}
className="rounded-lg px-4 py-2 text-sm text-muted-foreground hover:text-foreground transition-colors"
className="rounded-lg px-4 py-2 min-h-[44px] text-sm text-muted-foreground hover:text-foreground transition-colors"
>
Cancel
</button>
<button
onClick={handleResolve}
disabled={resolutionSummary.length < 5 || submitting}
className="rounded-lg bg-emerald-500/20 border border-emerald-500/30 px-4 py-2 text-sm font-medium text-emerald-400 hover:bg-emerald-500/30 disabled:opacity-50 transition-colors"
className="rounded-lg bg-emerald-500/20 border border-emerald-500/30 px-4 py-2 min-h-[44px] text-sm font-medium text-emerald-400 hover:bg-emerald-500/30 disabled:opacity-50 transition-colors"
>
{submitting ? 'Resolving...' : 'Resolve Session'}
</button>

View File

@@ -109,10 +109,10 @@ export function FlowPilotIntake({ onSubmit, isLoading }: FlowPilotIntakeProps) {
: 'Start Session'
return (
<div className="flex items-start justify-center pt-[10vh]">
<div className="flex items-start justify-center px-3 sm:px-4 pt-[6vh] sm:pt-[10vh]">
<div className="w-full max-w-2xl">
<div className="text-center mb-6">
<h1 className="font-heading text-2xl font-bold tracking-tight text-foreground">
<div className="text-center mb-4 sm:mb-6">
<h1 className="font-heading text-xl sm:text-2xl font-bold tracking-tight text-foreground">
What are you troubleshooting?
</h1>
<p className="mt-2 text-sm text-muted-foreground">
@@ -120,7 +120,7 @@ export function FlowPilotIntake({ onSubmit, isLoading }: FlowPilotIntakeProps) {
</p>
</div>
<div className="glass-card-static p-5 space-y-4">
<div className="glass-card-static p-3 sm:p-5 space-y-4">
{/* Selected ticket card */}
{selectedTicket && selectedTicketId && (
<div className="rounded-xl border border-primary/20 bg-primary/5 p-4">
@@ -171,6 +171,12 @@ export function FlowPilotIntake({ onSubmit, isLoading }: FlowPilotIntakeProps) {
<textarea
value={text}
onChange={(e) => setText(e.target.value)}
onKeyDown={(e) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault()
if (text.trim() || logContent.trim()) handleSubmit()
}
}}
placeholder="e.g. User can't access shared drive after password reset, getting 'Access Denied' in Event Viewer..."
className="w-full rounded-lg border border-border bg-card px-4 py-3 text-sm text-foreground placeholder:text-muted-foreground focus:border-[rgba(6,182,212,0.3)] focus:outline-none resize-none"
rows={5}
@@ -230,14 +236,14 @@ export function FlowPilotIntake({ onSubmit, isLoading }: FlowPilotIntakeProps) {
)}
{/* Submit */}
<div className="flex items-center justify-between">
<p className="text-[0.6875rem] text-[#5a6170]">
<div className="flex flex-col-reverse gap-3 sm:flex-row sm:items-center sm:justify-between">
<p className="text-[0.6875rem] text-[#5a6170] text-center sm:text-left">
FlowPilot will analyze your input and guide you through diagnosis
</p>
<button
onClick={handleSubmit}
disabled={!hasContent}
className="rounded-lg bg-gradient-brand px-5 py-2.5 text-sm font-semibold text-[#101114] shadow-lg shadow-primary/20 hover:opacity-90 active:scale-[0.97] disabled:opacity-40 disabled:shadow-none transition-all whitespace-nowrap"
className="w-full sm:w-auto min-h-[44px] rounded-lg bg-gradient-brand px-5 py-2.5 text-sm font-semibold text-[#101114] shadow-lg shadow-primary/20 hover:opacity-90 active:scale-[0.97] disabled:opacity-40 disabled:shadow-none transition-all whitespace-nowrap"
>
{submitLabel}
</button>

View File

@@ -28,7 +28,7 @@ export function FlowPilotOptions({ options, onSelect, disabled }: FlowPilotOptio
onClick={() => handleSelect(option.value)}
disabled={disabled}
className={cn(
'group relative rounded-xl border p-4 text-left transition-all',
'group relative rounded-xl border p-3 sm:p-4 text-left transition-all min-h-[44px]',
'hover:border-[rgba(6,182,212,0.3)] hover:shadow-[0_0_20px_rgba(6,182,212,0.08)]',
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40',
isSelected

View File

@@ -1,5 +1,5 @@
import { useEffect, useRef, useState } from 'react'
import { Network, Clock, Hash, Play, Ticket } from 'lucide-react'
import { Network, Clock, Hash, Play, Ticket, ChevronDown, ChevronUp } from 'lucide-react'
import type {
AISessionDetail,
AISessionStepResponse,
@@ -60,6 +60,7 @@ export function FlowPilotSession({
const scrollRef = useRef<HTMLDivElement>(null)
const [showTicketPicker, setShowTicketPicker] = useState(false)
const [linkingTicket, setLinkingTicket] = useState(false)
const [showMobileSidebar, setShowMobileSidebar] = useState(false)
const handleLinkTicket = async (ticketId: string, _ticket: PSATicketInfo) => {
if (!session.psa_connection_id && !session.ticket_data) {
@@ -112,7 +113,7 @@ export function FlowPilotSession({
if (isCompleted && documentation) {
return (
<div className="flex h-full flex-col">
<div className="flex-1 overflow-y-auto p-6">
<div className="flex-1 overflow-y-auto p-3 sm:p-4 lg:p-6">
<SessionDocView
documentation={documentation}
onRate={onRate}
@@ -130,10 +131,68 @@ export function FlowPilotSession({
return (
<div className="flex h-full flex-col">
{/* Mobile sidebar summary (collapsible) */}
<div className="lg:hidden border-b" style={{ borderColor: 'var(--glass-border)' }}>
<button
onClick={() => setShowMobileSidebar(!showMobileSidebar)}
className="flex w-full items-center justify-between px-3 py-2 sm:px-4"
>
<div className="flex items-center gap-3 text-xs text-muted-foreground overflow-x-auto">
{session.problem_domain && (
<span className="font-label rounded-md bg-primary/10 px-1.5 py-0.5 text-[0.5625rem] uppercase tracking-wider text-primary shrink-0">
{session.problem_domain}
</span>
)}
<span className="flex items-center gap-1 shrink-0">
<Hash size={10} />
{session.step_count} steps
</span>
<ConfidenceIndicator
tier={session.confidence_tier}
score={currentStep?.confidence_score ?? 0}
/>
</div>
{showMobileSidebar ? <ChevronUp size={14} className="text-muted-foreground shrink-0" /> : <ChevronDown size={14} className="text-muted-foreground shrink-0" />}
</button>
{showMobileSidebar && (
<div className="px-3 pb-3 sm:px-4 space-y-3">
{session.psa_ticket_id ? (
<SessionTicketCard
ticketId={session.psa_ticket_id}
ticketData={session.ticket_data as Record<string, unknown> | null}
/>
) : session.status === 'active' ? (
<button
onClick={() => setShowTicketPicker(true)}
disabled={linkingTicket}
className="w-full flex items-center gap-2 rounded-xl border border-dashed border-border px-3 py-2.5 text-xs text-muted-foreground hover:text-foreground hover:border-primary/30 transition-colors disabled:opacity-50 min-h-[44px]"
>
<Ticket size={14} />
{linkingTicket ? 'Linking...' : 'Link Ticket'}
</button>
) : null}
{session.problem_summary && (
<div>
<h4 className="font-label text-[0.625rem] uppercase tracking-wider text-[#5a6170] mb-1">Problem</h4>
<p className="text-sm text-foreground">{session.problem_summary}</p>
</div>
)}
{session.matched_flow_id && (
<div className="flex items-center gap-2">
<Network size={14} className="text-muted-foreground" />
<span className="text-xs text-foreground">
{session.match_score ? `${Math.round(session.match_score * 100)}% match` : 'Match found'}
</span>
</div>
)}
</div>
)}
</div>
{/* Main content area: conversation + sidebar */}
<div className="flex flex-1 min-h-0">
{/* Conversation column */}
<div ref={scrollRef} className="flex-1 overflow-y-auto p-6">
<div ref={scrollRef} className="flex-1 overflow-y-auto p-3 sm:p-4 lg:p-6">
<div className="mx-auto max-w-2xl space-y-3">
{allSteps.map((step) => (
<FlowPilotStepCard
@@ -148,7 +207,7 @@ export function FlowPilotSession({
</div>
</div>
{/* Sidebar */}
{/* Sidebar — desktop only */}
<div
className="hidden w-72 shrink-0 overflow-y-auto border-l p-4 lg:block"
style={{ borderColor: 'var(--glass-border)' }}
@@ -252,7 +311,7 @@ export function FlowPilotSession({
{/* Paused banner */}
{session.status === 'paused' && onResume && (
<div
className="flex items-center justify-between border-t px-5 py-3"
className="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between border-t px-3 py-3 sm:px-5"
style={{ borderColor: 'var(--glass-border)', background: 'rgba(16, 17, 20, 0.8)', backdropFilter: 'blur(12px)' }}
>
<span className="text-sm text-muted-foreground">Session paused</span>

View File

@@ -70,7 +70,7 @@ export function FlowPilotStepCard({ step, isCurrentStep, isProcessing, sessionId
return (
<button
onClick={() => setIsCollapsed(false)}
className="w-full text-left glass-card-static p-4 opacity-70 hover:opacity-90 transition-opacity"
className="w-full text-left glass-card-static p-3 sm:p-4 opacity-70 hover:opacity-90 transition-opacity"
>
<div className="flex items-center gap-3">
<Icon size={16} className="shrink-0 text-muted-foreground" />
@@ -84,7 +84,7 @@ export function FlowPilotStepCard({ step, isCurrentStep, isProcessing, sessionId
// Expanded completed step
if (!isCurrentStep && !isCollapsed) {
return (
<div className="glass-card-static p-4 opacity-80">
<div className="glass-card-static p-3 sm:p-4 opacity-80">
<button
onClick={() => setIsCollapsed(true)}
className="mb-2 flex w-full items-center justify-between text-left"
@@ -106,7 +106,7 @@ export function FlowPilotStepCard({ step, isCurrentStep, isProcessing, sessionId
return (
<div
className={cn(
'glass-card-static p-5',
'glass-card-static p-3 sm:p-4 lg:p-5',
isResolutionSuggestion && 'border-emerald-500/30'
)}
>
@@ -140,16 +140,16 @@ export function FlowPilotStepCard({ step, isCurrentStep, isProcessing, sessionId
<div className="space-y-3">
{/* Resolution suggestion buttons */}
{isResolutionSuggestion && (
<div className="flex gap-2">
<div className="flex flex-col gap-2 sm:flex-row">
<button
onClick={() => handleResolutionResponse(true)}
className="flex-1 rounded-lg bg-emerald-500/10 border border-emerald-500/20 px-4 py-2.5 text-sm font-medium text-emerald-400 hover:bg-emerald-500/20 transition-colors"
className="flex-1 min-h-[44px] rounded-lg bg-emerald-500/10 border border-emerald-500/20 px-4 py-2.5 text-sm font-medium text-emerald-400 hover:bg-emerald-500/20 transition-colors"
>
Yes, this is resolved
</button>
<button
onClick={() => handleResolutionResponse(false)}
className="flex-1 rounded-lg bg-card/50 border border-border px-4 py-2.5 text-sm font-medium text-foreground hover:bg-card transition-colors"
className="flex-1 min-h-[44px] rounded-lg bg-card/50 border border-border px-4 py-2.5 text-sm font-medium text-foreground hover:bg-card transition-colors"
>
No, keep investigating
</button>
@@ -178,16 +178,16 @@ export function FlowPilotStepCard({ step, isCurrentStep, isProcessing, sessionId
{/* Action step buttons */}
{!isResolutionSuggestion && step.step_type === 'action' && (content.action_type as string) !== 'script_generation' && (
<div className="flex gap-2">
<div className="flex flex-col gap-2 sm:flex-row">
<button
onClick={() => handleActionComplete(true)}
className="flex-1 rounded-lg bg-primary/10 border border-primary/20 px-4 py-2.5 text-sm font-medium text-primary hover:bg-primary/20 transition-colors"
className="flex-1 min-h-[44px] rounded-lg bg-primary/10 border border-primary/20 px-4 py-2.5 text-sm font-medium text-primary hover:bg-primary/20 transition-colors"
>
I've completed this action
</button>
<button
onClick={() => handleActionComplete(false)}
className="flex-1 rounded-lg bg-card/50 border border-border px-4 py-2.5 text-sm font-medium text-foreground hover:bg-card transition-colors"
className="flex-1 min-h-[44px] rounded-lg bg-card/50 border border-border px-4 py-2.5 text-sm font-medium text-foreground hover:bg-card transition-colors"
>
This didn't work
</button>

View File

@@ -63,7 +63,7 @@ export function InSessionScriptGenerator({
}
return (
<div className="mt-3 rounded-xl border border-primary/20 bg-primary/5 p-4 space-y-3">
<div className="mt-3 rounded-xl border border-primary/20 bg-primary/5 p-3 sm:p-4 space-y-3">
<div className="flex items-center gap-2">
<Terminal size={14} className="text-primary" />
<span className="font-label text-[0.625rem] uppercase tracking-wider text-primary">
@@ -106,7 +106,7 @@ export function InSessionScriptGenerator({
<button
onClick={handleGenerate}
disabled={isGenerating}
className="w-full flex items-center justify-center gap-2 rounded-lg bg-gradient-brand px-4 py-2 text-sm font-semibold text-[#101114] shadow-lg shadow-primary/20 hover:opacity-90 active:scale-[0.97] disabled:opacity-40 transition-all"
className="w-full min-h-[44px] flex items-center justify-center gap-2 rounded-lg bg-gradient-brand px-4 py-2 text-sm font-semibold text-[#101114] shadow-lg shadow-primary/20 hover:opacity-90 active:scale-[0.97] disabled:opacity-40 transition-all"
>
{isGenerating ? (
<Loader2 size={14} className="animate-spin" />
@@ -138,16 +138,16 @@ export function InSessionScriptGenerator({
</div>
{/* Continue buttons */}
<div className="flex gap-2 pt-1">
<div className="flex flex-col gap-2 pt-1 sm:flex-row">
<button
onClick={() => handleContinue(true)}
className="flex-1 rounded-lg bg-primary/10 border border-primary/20 px-4 py-2 text-sm font-medium text-primary hover:bg-primary/20 transition-colors"
className="flex-1 min-h-[44px] rounded-lg bg-primary/10 border border-primary/20 px-4 py-2 text-sm font-medium text-primary hover:bg-primary/20 transition-colors"
>
Script worked continue
</button>
<button
onClick={() => handleContinue(false)}
className="flex-1 rounded-lg bg-card/50 border border-border px-4 py-2 text-sm font-medium text-foreground hover:bg-card transition-colors"
className="flex-1 min-h-[44px] rounded-lg bg-card/50 border border-border px-4 py-2 text-sm font-medium text-foreground hover:bg-card transition-colors"
>
Didn't resolve it
</button>

View File

@@ -47,11 +47,11 @@ export function SessionDocView({
}
return (
<div className="space-y-5">
<div className="space-y-4 sm:space-y-5">
{/* PSA Push Status */}
{currentPushStatus && currentPushStatus !== 'no_psa' && (
<div
className={`rounded-xl border px-4 py-3 flex items-center gap-3 ${
className={`rounded-xl border px-3 py-3 sm:px-4 flex flex-wrap items-center gap-2 sm:gap-3 ${
currentPushStatus === 'sent'
? 'border-emerald-400/20 bg-emerald-400/5'
: currentPushStatus === 'pending_retry'
@@ -107,7 +107,7 @@ export function SessionDocView({
)}
{/* Header */}
<div className="glass-card-static p-5">
<div className="glass-card-static p-3 sm:p-4 lg:p-5">
<div className="flex items-start gap-3">
<span className="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-primary/10 text-primary">
<FileText size={16} />
@@ -155,7 +155,7 @@ export function SessionDocView({
)}
{/* Intake summary */}
<div className="glass-card-static p-4">
<div className="glass-card-static p-3 sm:p-4">
<h4 className="font-label text-[0.625rem] uppercase tracking-wider text-muted-foreground mb-2">
Original intake
</h4>
@@ -168,7 +168,7 @@ export function SessionDocView({
Diagnostic trail
</h4>
{documentation.diagnostic_steps.map((step) => (
<div key={step.step_number} className="glass-card-static p-4">
<div key={step.step_number} className="glass-card-static p-3 sm:p-4">
<div className="flex items-start gap-3">
<span className="font-label flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-card text-[0.625rem] text-muted-foreground border border-border">
{step.step_number}
@@ -189,14 +189,14 @@ export function SessionDocView({
{/* Rating */}
{onRate && (
<div className="glass-card-static p-4 text-center">
<div className="glass-card-static p-3 sm:p-4 text-center">
<p className="text-sm text-muted-foreground mb-2">How helpful was this session?</p>
<div className="flex items-center justify-center gap-1">
{[1, 2, 3, 4, 5].map((star) => (
<button
key={star}
onClick={() => onRate(star)}
className="p-1 transition-colors"
className="p-2 sm:p-1 transition-colors"
>
<Star
size={20}

View File

@@ -65,12 +65,12 @@ export default function FlowPilotAnalyticsPage() {
return (
<div className="container mx-auto px-4 py-6 sm:px-6 sm:py-8 space-y-6">
{/* Header */}
<div className="flex items-center justify-between">
<div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
<div className="flex items-center gap-3">
<span title="FlowPilot Analytics">
<BarChart3 size={24} className="text-foreground" />
</span>
<h1 className="text-2xl font-bold font-heading text-foreground">FlowPilot Analytics</h1>
<h1 className="text-xl sm:text-2xl font-bold font-heading text-foreground">FlowPilot Analytics</h1>
</div>
<div className="flex items-center gap-3">
<Link
@@ -128,7 +128,7 @@ export default function FlowPilotAnalyticsPage() {
{/* Second row — Charts */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
{/* MTTR Trend */}
<div className="glass-card-static p-5">
<div className="glass-card-static p-3 sm:p-5">
<h3 className="font-heading text-sm font-semibold text-foreground mb-4">
MTTR Trend
</h3>
@@ -173,7 +173,7 @@ export default function FlowPilotAnalyticsPage() {
</div>
{/* Domain Breakdown */}
<div className="glass-card-static p-5">
<div className="glass-card-static p-3 sm:p-5">
<h3 className="font-heading text-sm font-semibold text-foreground mb-4">
Sessions by Domain
</h3>
@@ -207,7 +207,7 @@ export default function FlowPilotAnalyticsPage() {
{/* Third row — Confidence + Knowledge Coverage */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
{/* Confidence Breakdown */}
<div className="glass-card-static p-5">
<div className="glass-card-static p-3 sm:p-5">
<h3 className="font-heading text-sm font-semibold text-foreground mb-4">
Confidence Tiers
</h3>
@@ -237,7 +237,7 @@ export default function FlowPilotAnalyticsPage() {
</div>
{/* Knowledge Coverage */}
<div className="glass-card-static p-5">
<div className="glass-card-static p-3 sm:p-5">
<h3 className="font-heading text-sm font-semibold text-foreground mb-4">
Knowledge Coverage
</h3>
@@ -305,10 +305,10 @@ function MetricCard({
iconColor: string
}) {
return (
<div className="glass-card-static p-4">
<div className="glass-card-static p-3 sm:p-4">
<div className="flex items-center gap-3">
<span
className="flex h-8 w-8 items-center justify-center rounded-lg"
className="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg"
style={{ background: `${iconColor}15` }}
>
<Icon size={16} style={{ color: iconColor }} />

View File

@@ -85,11 +85,11 @@ export default function ReviewQueuePage() {
}
return (
<div className="flex h-full">
<div className="flex h-full flex-col lg:flex-row overflow-hidden">
{/* Left panel — Proposal list */}
<div className="w-[380px] shrink-0 border-r overflow-y-auto" style={{ borderColor: 'var(--glass-border)' }}>
<div className="w-full shrink-0 border-b lg:border-b-0 lg:border-r lg:w-[380px] overflow-y-auto" style={{ borderColor: 'var(--glass-border)' }}>
{/* Header */}
<div className="sticky top-0 z-10 p-4 space-y-3" style={{ background: 'rgba(16, 17, 20, 0.95)', backdropFilter: 'blur(12px)' }}>
<div className="sticky top-0 z-10 p-3 sm:p-4 space-y-3" style={{ background: 'rgba(16, 17, 20, 0.95)', backdropFilter: 'blur(12px)' }}>
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
<Lightbulb size={16} className="text-amber-400" />
@@ -119,12 +119,12 @@ export default function ReviewQueuePage() {
)}
{/* Tabs */}
<div className="flex gap-1">
<div className="flex gap-1 overflow-x-auto">
{STATUS_TABS.map((tab) => (
<button
key={tab.key}
onClick={() => setActiveTab(tab.key)}
className={`rounded-lg px-2.5 py-1 text-xs font-medium transition-colors ${
className={`shrink-0 rounded-lg px-2.5 py-1 text-xs font-medium transition-colors ${
activeTab === tab.key
? 'bg-primary/10 text-primary'
: 'text-muted-foreground hover:text-foreground'
@@ -177,7 +177,7 @@ export default function ReviewQueuePage() {
</div>
{/* Right panel — Detail */}
<div className="flex-1 overflow-y-auto">
<div className={`flex-1 overflow-y-auto ${!detail && !isLoadingDetail ? 'hidden lg:flex' : ''}`}>
{isLoadingDetail ? (
<div className="flex items-center justify-center h-full">
<Loader2 size={20} className="animate-spin text-muted-foreground" />