/* TalkToDoc design system. Palette: "Olive Garden Feast" (user-supplied Coolors palette): #606C38 (olive), #283618 (dark forest green), #FEFAE0 (cream), #DDA15E (tan/gold), #BC6C25 (rust). Patient view uses the olive as its primary color, provider view uses a darkened variant of the rust, one color family per role, same approach as the previous palette. Raw #BC6C25 and raw #DDA15E both fail WCAG contrast as text on light backgrounds, so darkened variants are used anywhere either color needs to be read as text rather than a fill. System fonts only, no external font download, this matters for the low-bandwidth rural settings this system is built for. */ :root { /* Base */ --color-bg: #FEFAE0; --color-surface: #FFFFFF; --color-border: #E8DFC0; /* Text */ --color-text: #283618; --color-text-secondary: #5C6650; --color-text-on-primary: #FFFFFF; --color-text-on-provider-accent: #FFFFFF; /* Primary (shared, patient role) */ --color-primary: #606C38; --color-primary-dark: #283618; --color-primary-light: #E8ECDC; /* Accent */ --color-accent: #DDA15E; /* Raw #DDA15E fails WCAG contrast as text (2.14:1), this darkened variant clears AA at 5.33:1, used anywhere it needs to be text. */ --color-accent-text: #8A5F26; /* Provider-only accent */ /* Raw #BC6C25 gives only 3.95:1 with white text, not enough for normal-size text, this darkened variant clears AA at 5.25:1. */ --color-provider-accent: #A15A1F; --color-provider-accent-light: #FBEADB; --color-provider-accent-text: #7A431A; /* Semantic */ --color-success: #2E7D32; --color-error: #B3261E; --color-error-light: #FBEAE9; /* Spacing scale */ --space-1: 4px; --space-2: 8px; --space-3: 12px; --space-4: 16px; --space-5: 24px; --space-6: 32px; --space-7: 48px; --space-8: 64px; /* Type scale */ --text-sm: 0.875rem; --text-base: 1rem; --text-lg: 1.125rem; --text-xl: 1.5rem; --text-2xl: 2rem; --radius: 20px; --radius-sm: 14px; --radius-lg: 28px; /* Soft elevation, replaces hard 1px borders on cards and controls */ --shadow-sm: 0 1px 2px rgba(40, 54, 24, 0.05), 0 2px 6px rgba(40, 54, 24, 0.04); --shadow-md: 0 6px 20px rgba(40, 54, 24, 0.08), 0 2px 6px rgba(40, 54, 24, 0.05); --shadow-lg: 0 16px 40px rgba(40, 54, 24, 0.14); } * { box-sizing: border-box; } body { margin: 0; font-family: -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; background: var(--color-bg); color: var(--color-text); font-size: var(--text-base); line-height: 1.5; -webkit-font-smoothing: antialiased; } h1, h2, h3 { margin: 0 0 var(--space-2) 0; font-weight: 700; line-height: 1.25; letter-spacing: -0.02em; } h1 { font-size: var(--text-2xl); } h2 { font-size: var(--text-xl); } h3 { font-size: var(--text-lg); letter-spacing: -0.01em; } p { margin: 0 0 var(--space-4) 0; color: var(--color-text-secondary); } .app-shell { max-width: 480px; margin: 0 auto; min-height: 100vh; display: flex; flex-direction: column; background: var(--color-bg); } .app-header { padding: var(--space-5) var(--space-4) var(--space-6); background: linear-gradient(155deg, var(--color-primary) 0%, var(--color-primary-dark) 130%); color: var(--color-text-on-primary); border-radius: 0 0 var(--radius-lg) var(--radius-lg); display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-3); } .header-icon-btn { width: 40px; height: 40px; border-radius: 50%; border: none; background: rgba(255, 255, 255, 0.18); color: inherit; display: flex; align-items: center; justify-content: center; cursor: pointer; flex-shrink: 0; transition: background 150ms ease, transform 100ms ease; } .header-icon-btn:hover { background: rgba(255, 255, 255, 0.28); } .header-icon-btn:active { transform: scale(0.94); } .header-icon-btn svg { width: 20px; height: 20px; } .app-header.provider { background: linear-gradient(155deg, var(--color-provider-accent) 0%, var(--color-provider-accent-text) 160%); color: var(--color-text-on-provider-accent); } .brand { display: flex; align-items: center; gap: var(--space-2); } .brand-mark { width: 28px; height: 28px; border-radius: 50%; background: rgba(255, 255, 255, 0.18); display: flex; align-items: center; justify-content: center; flex-shrink: 0; } .brand-mark svg { width: 16px; height: 16px; } .app-header h1 { font-size: var(--text-lg); margin: 0; } .app-header .role-tag { display: inline-block; margin-top: var(--space-1); font-size: var(--text-sm); opacity: 0.85; } .app-main { flex: 1; padding: var(--space-5) var(--space-4) var(--space-7); } .card { background: var(--color-surface); border-radius: var(--radius); padding: var(--space-5); margin-bottom: var(--space-4); box-shadow: var(--shadow-sm); } .step { display: none; } .step.active { display: block; animation: step-in 220ms ease; } @keyframes step-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: translateY(0); } } @media (prefers-reduced-motion: reduce) { .step.active { animation: none; } } /* Buttons */ .btn { display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2); width: 100%; padding: var(--space-3) var(--space-4); font-size: var(--text-base); font-weight: 600; border-radius: var(--radius-sm); border: none; cursor: pointer; transition: background-color 120ms ease, box-shadow 120ms ease, transform 120ms ease; } .btn:active { transform: scale(0.98); } .btn:focus-visible { outline: 2px solid var(--color-primary-dark); outline-offset: 2px; } .btn-primary { background: var(--color-primary); color: var(--color-text-on-primary); box-shadow: 0 4px 14px rgba(96, 108, 56, 0.32); } .btn-primary:hover { background: var(--color-primary-dark); } .btn-primary:disabled { background: var(--color-border); color: var(--color-text-secondary); box-shadow: none; cursor: not-allowed; } .btn-secondary { background: var(--color-primary-light); color: var(--color-primary-dark); } .btn-secondary:hover { background: #DAE1CD; } .btn-provider { background: var(--color-provider-accent); color: var(--color-text-on-provider-accent); box-shadow: 0 4px 14px rgba(161, 90, 31, 0.32); } .btn-provider:hover { background: var(--color-provider-accent-text); } .btn-row { display: flex; gap: var(--space-3); margin-top: var(--space-4); } /* Language grid */ .language-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-3); margin-top: var(--space-4); } .language-option { padding: var(--space-4); text-align: center; font-weight: 600; border: none; border-radius: var(--radius-sm); background: var(--color-surface); box-shadow: var(--shadow-sm); cursor: pointer; transition: box-shadow 120ms ease, transform 120ms ease, background-color 120ms ease; } .language-option:hover { box-shadow: var(--shadow-md); transform: translateY(-1px); } .language-option:active { transform: scale(0.96); } .language-option[aria-pressed="true"] { background: var(--color-primary); color: var(--color-text-on-primary); box-shadow: 0 4px 14px rgba(96, 108, 56, 0.32); animation: select-pop 260ms ease; } @keyframes select-pop { 0% { transform: scale(1); } 40% { transform: scale(1.06); } 100% { transform: scale(1); } } @media (prefers-reduced-motion: reduce) { .language-option[aria-pressed="true"] { animation: none; } } /* Inputs */ label { display: block; font-weight: 600; font-size: var(--text-sm); margin-bottom: var(--space-2); } textarea, input[type="text"] { width: 100%; padding: var(--space-3) var(--space-4); font-size: var(--text-base); font-family: inherit; border: 1.5px solid var(--color-border); border-radius: var(--radius-sm); background: var(--color-surface); color: var(--color-text); resize: vertical; transition: border-color 120ms ease, box-shadow 120ms ease; } textarea:focus, input[type="text"]:focus { outline: none; border-color: var(--color-primary); box-shadow: 0 0 0 4px var(--color-primary-light); } .helper-text { font-size: var(--text-sm); color: var(--color-text-secondary); margin-top: var(--space-2); } .divider { display: flex; align-items: center; gap: var(--space-3); margin: var(--space-4) 0; color: var(--color-text-secondary); font-size: var(--text-sm); } .divider::before, .divider::after { content: ""; flex: 1; height: 1px; background: var(--color-border); } /* Recording indicator */ .record-btn { display: flex; align-items: center; justify-content: center; gap: var(--space-2); } .record-dot { width: 10px; height: 10px; border-radius: 50%; background: var(--color-error); display: none; } .record-btn.recording .record-dot { display: inline-block; animation: pulse 1s infinite; } @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } } /* Status / results */ .status-banner { padding: var(--space-3) var(--space-4); border-radius: var(--radius-sm); font-size: var(--text-sm); margin-bottom: var(--space-4); } .status-banner.error { background: var(--color-error-light); color: var(--color-error); } .status-banner.info { background: var(--color-primary-light); color: var(--color-primary-dark); } .result-block { margin-bottom: var(--space-4); } .search-input { width: 100%; padding: var(--space-3) var(--space-4); border: 1px solid var(--color-border); border-radius: var(--radius); font-size: var(--text-base); font-family: inherit; color: var(--color-text); background: var(--color-surface); } .search-input:focus { outline: none; border-color: var(--color-primary); box-shadow: 0 0 0 3px var(--color-primary-light); } .history-row { cursor: pointer; border: 1px solid var(--color-border); border-radius: var(--radius); padding: var(--space-3) var(--space-4); margin-bottom: var(--space-3); transition: box-shadow 150ms ease, border-color 150ms ease, transform 100ms ease; } .history-row:hover { border-color: var(--color-primary); box-shadow: var(--shadow-sm); } .history-row:active { transform: scale(0.99); } .history-row:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; } .history-row .timestamp { font-size: var(--text-sm); color: var(--color-text-secondary); font-weight: 400; float: right; } /* Provider queue tabs (Waiting / Active / Completed) */ .queue-tabs { display: flex; gap: var(--space-2); margin-bottom: var(--space-4); } .queue-tab { flex: 1; padding: var(--space-2) var(--space-3); border: 1px solid var(--color-border); border-radius: var(--radius); background: var(--color-surface); color: var(--color-text-secondary); font-size: var(--text-sm); font-weight: 600; cursor: pointer; transition: background 150ms ease, color 150ms ease, border-color 150ms ease; } .queue-tab:hover { border-color: var(--color-provider-accent); } .queue-tab.active { background: var(--color-provider-accent); border-color: var(--color-provider-accent); color: var(--color-text-on-provider-accent); } .queue-tab .tab-count { opacity: 0.8; margin-left: var(--space-1); } /* Workspace: reference/status line above the patient's message */ .workspace-meta { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: var(--space-2); margin-bottom: var(--space-2); } /* Original-language transcript, collapsed by default under the English translation so the provider isn't required to read a language they may not speak, but can always verify against the source. */ .original-transcript { margin-top: var(--space-3); font-size: var(--text-sm); } .original-transcript summary { cursor: pointer; color: var(--color-text-secondary); font-weight: 600; } .original-transcript summary:hover { color: var(--color-provider-accent-text); } .original-transcript p { margin: var(--space-2) 0 0; color: var(--color-text); background: var(--color-bg); border-radius: var(--radius-sm); padding: var(--space-3); } /* Read-only rows for a patient's other consultations, shown for context in the workspace. Deliberately not clickable - see the comment next to #patient-history-list in provider.html for why. */ .history-row-static { border: 1px solid var(--color-border); border-radius: var(--radius); padding: var(--space-3) var(--space-4); margin-bottom: var(--space-3); } .history-row-static .timestamp { float: none; margin-left: auto; font-weight: 400; } /* Response composer preview: a real translation + real generated speech, so it's visually set apart as "this is what actually gets sent", distinct from the (still-editable, not-yet-committed) reply above it. */ .preview-block { margin-top: var(--space-4); padding: var(--space-4); border: 1px dashed var(--color-provider-accent); border-radius: var(--radius); background: var(--color-provider-accent-light); } .preview-label { font-size: var(--text-sm); font-weight: 600; color: var(--color-provider-accent-text); margin-bottom: var(--space-3); } .preview-block .chat-bubble.from-provider { margin-bottom: var(--space-3); } /* Keep the shared audio player on-brand in the provider context (rust accent) instead of the patient page's green. */ .provider .audio-btn { background: var(--color-provider-accent); color: var(--color-text-on-provider-accent); } .provider .audio-btn:hover { background: var(--color-provider-accent-text); } .provider .audio-btn-sm { background: var(--color-provider-accent-light); color: var(--color-provider-accent-text); } .provider .audio-seek { accent-color: var(--color-provider-accent); } .result-label { font-size: var(--text-sm); font-weight: 600; color: var(--color-text-secondary); margin-bottom: var(--space-1); } .result-text { font-size: var(--text-base); color: var(--color-text); } audio { width: 100%; margin-top: var(--space-3); } .interaction-id { font-family: ui-monospace, monospace; background: var(--color-primary-light); color: var(--color-primary-dark); padding: 2px 8px; border-radius: 4px; font-size: var(--text-sm); } .provider .interaction-id { background: var(--color-provider-accent-light); color: var(--color-provider-accent-text); } .nlu-summary { background: var(--color-provider-accent-light); border-left: 3px solid var(--color-provider-accent-text); padding: var(--space-3) var(--space-4); border-radius: var(--radius-sm); font-size: var(--text-base); margin-bottom: 0; } .nav-link { display: block; text-align: center; margin-top: var(--space-5); font-size: var(--text-sm); color: var(--color-text-secondary); } .nav-link a { color: var(--color-primary); font-weight: 600; text-decoration: none; } .nav-link.provider a { color: var(--color-provider-accent-text); } /* ============================================================ Hero section: greeting + ambient presence orb ============================================================ */ .hero { text-align: center; padding: var(--space-4) 0 var(--space-6); } .hero-orb-wrap { position: relative; width: 132px; height: 132px; margin: 0 auto var(--space-5); display: flex; align-items: center; justify-content: center; } .hero-orb-glow { position: absolute; inset: -20px; border-radius: 50%; background: radial-gradient(circle, var(--color-primary) 0%, rgba(96, 108, 56, 0) 70%); opacity: 0.35; animation: breathe 3400ms ease-in-out infinite; } .provider .hero-orb-glow { background: radial-gradient(circle, var(--color-provider-accent) 0%, rgba(161, 90, 31, 0) 70%); } .hero-orb { position: relative; width: 96px; height: 96px; border-radius: 50%; background: linear-gradient(155deg, #7C8A47 0%, var(--color-primary) 45%, var(--color-primary-dark) 100%); display: flex; align-items: center; justify-content: center; box-shadow: 0 12px 32px rgba(40, 54, 24, 0.32), inset 0 1px 1px rgba(255, 255, 255, 0.25); } .provider .hero-orb { background: linear-gradient(155deg, #C97D3A 0%, var(--color-provider-accent) 45%, var(--color-provider-accent-text) 100%); box-shadow: 0 12px 32px rgba(122, 67, 26, 0.32), inset 0 1px 1px rgba(255, 255, 255, 0.25); } .hero-orb svg { width: 36px; height: 36px; color: var(--color-bg); } @keyframes breathe { 0%, 100% { transform: scale(1); opacity: 0.35; } 50% { transform: scale(1.12); opacity: 0.55; } } @media (prefers-reduced-motion: reduce) { .hero-orb-glow { animation: none; } } .hero h2 { margin-bottom: var(--space-1); } .hero p { max-width: 320px; margin-left: auto; margin-right: auto; } /* ============================================================ Unified input bar (textarea + inline mic button) ============================================================ */ .input-bar { position: relative; } .input-bar textarea { padding-right: 52px; } .mic-inline-btn { position: absolute; right: 8px; bottom: 8px; width: 38px; height: 38px; border-radius: 50%; border: none; background: var(--color-primary); color: var(--color-text-on-primary); display: flex; align-items: center; justify-content: center; cursor: pointer; overflow: visible; box-shadow: 0 4px 12px rgba(96, 108, 56, 0.35); transition: background-color 120ms ease, transform 120ms ease; } .mic-inline-btn:hover { background: var(--color-primary-dark); } .mic-inline-btn.recording { background: var(--color-error); animation: pulse-ring 1400ms ease-in-out infinite; } @keyframes pulse-ring { 0%, 100% { box-shadow: 0 0 0 0 rgba(179, 38, 30, 0.35); } 50% { box-shadow: 0 0 0 8px rgba(179, 38, 30, 0); } } .mic-inline-btn svg { width: 18px; height: 18px; } /* ============================================================ Listening state: replaces the input bar while recording ============================================================ */ .listening-panel { text-align: center; padding: var(--space-6) 0 var(--space-4); } .listening-orb-wrap { position: relative; width: 128px; height: 128px; margin: 0 auto var(--space-4); display: flex; align-items: center; justify-content: center; } .listening-ring { position: absolute; inset: 0; border-radius: 50%; border: 2px solid var(--color-primary); opacity: 0; animation: ripple 2200ms ease-out infinite; } .listening-ring:nth-child(2) { animation-delay: 700ms; } .listening-ring:nth-child(3) { animation-delay: 1400ms; } @keyframes ripple { 0% { transform: scale(0.55); opacity: 0.5; } 100% { transform: scale(1); opacity: 0; } } .listening-core { position: relative; width: 72px; height: 72px; border-radius: 50%; background: var(--color-primary); color: var(--color-text-on-primary); border: none; display: flex; align-items: center; justify-content: center; cursor: pointer; } .listening-core svg { width: 28px; height: 28px; } @media (prefers-reduced-motion: reduce) { .listening-ring { animation: none; opacity: 0.25; transform: scale(0.8); } } .listening-caption { font-weight: 600; margin-bottom: var(--space-1); } /* ============================================================ Quick symptom chips ============================================================ */ .chip-row { display: flex; flex-wrap: wrap; gap: var(--space-2); margin: var(--space-3) 0 var(--space-4); } .chip { padding: 8px 16px; border-radius: 999px; border: none; background: var(--color-surface); color: var(--color-text); font-size: var(--text-sm); font-weight: 600; box-shadow: var(--shadow-sm); cursor: pointer; transition: box-shadow 120ms ease, transform 120ms ease, background-color 120ms ease; } .chip:hover { box-shadow: var(--shadow-md); background: var(--color-primary-light); transform: translateY(-1px); } .chip:active { transform: scale(0.95); } /* ============================================================ Chat bubbles, used for the conversation view and history ============================================================ */ .chat-thread { display: flex; flex-direction: column; gap: var(--space-3); } .chat-bubble { max-width: 85%; padding: var(--space-3) var(--space-4); border-radius: var(--radius); font-size: var(--text-base); line-height: 1.45; } .chat-bubble .chat-label { display: block; font-size: var(--text-sm); font-weight: 600; margin-bottom: 2px; opacity: 0.75; } .chat-bubble.from-patient { align-self: flex-end; background: var(--color-primary); color: var(--color-text-on-primary); border-bottom-right-radius: 4px; } .chat-bubble.from-provider { align-self: flex-start; background: var(--color-surface); box-shadow: var(--shadow-sm); color: var(--color-text); border-bottom-left-radius: 4px; } .provider .chat-bubble.from-provider { background: var(--color-provider-accent-light); box-shadow: none; } /* ============================================================ Provider queue cards ============================================================ */ .queue-card { display: flex; align-items: flex-start; gap: var(--space-3); width: 100%; text-align: left; padding: var(--space-3) var(--space-4); margin-bottom: var(--space-3); background: var(--color-surface); border: none; border-radius: var(--radius-sm); box-shadow: var(--shadow-sm); cursor: pointer; transition: box-shadow 120ms ease, transform 120ms ease; } .queue-card:hover { box-shadow: var(--shadow-md); transform: translateY(-1px); } .queue-card:active { transform: scale(0.98); } .queue-avatar { width: 36px; height: 36px; border-radius: 50%; background: var(--color-provider-accent-light); color: var(--color-provider-accent-text); display: flex; align-items: center; justify-content: center; font-weight: 700; flex-shrink: 0; } .queue-body { flex: 1; min-width: 0; } .queue-top-row { display: flex; justify-content: space-between; align-items: center; gap: var(--space-2); margin-bottom: 2px; } .queue-top-right { display: flex; align-items: center; gap: var(--space-2); flex-shrink: 0; } .queue-lang { font-size: var(--text-sm); font-weight: 600; color: var(--color-text-secondary); text-transform: capitalize; } .queue-preview { color: var(--color-text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } /* ============================================================ Micro-animations: list entrance, mic ripple, skeleton loading ============================================================ */ .list-item-in { animation: list-item-in 260ms ease both; } @keyframes list-item-in { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } @media (prefers-reduced-motion: reduce) { .list-item-in { animation: none; } } /* One-shot ripple on the inline mic button when tapped */ .mic-inline-btn::after { content: ""; position: absolute; inset: 0; border-radius: 50%; border: 2px solid var(--color-primary); opacity: 0; } .mic-inline-btn.tapped::after { animation: mic-ripple 500ms ease-out; } @keyframes mic-ripple { 0% { opacity: 0.6; transform: scale(1); } 100% { opacity: 0; transform: scale(1.9); } } @media (prefers-reduced-motion: reduce) { .mic-inline-btn.tapped::after { animation: none; } } /* Skeleton loading shimmer, shown briefly while the queue or history is being fetched, instead of a blank gap */ .skeleton-row { height: 64px; border-radius: var(--radius-sm); margin-bottom: var(--space-3); background: linear-gradient(100deg, var(--color-border) 30%, #F3EDD3 50%, var(--color-border) 70%); background-size: 200% 100%; animation: skeleton-shimmer 1300ms ease-in-out infinite; } @keyframes skeleton-shimmer { from { background-position: 140% 0; } to { background-position: -40% 0; } } @media (prefers-reduced-motion: reduce) { .skeleton-row { animation: none; opacity: 0.6; } } /* Queue heading count, smooth transition when the number changes */ .queue-heading-text { display: inline-block; animation: count-change 220ms ease; } @keyframes count-change { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: translateY(0); } } /* Relative timestamps on queue cards and history entries */ .timestamp { font-size: var(--text-sm); color: var(--color-text-secondary); white-space: nowrap; flex-shrink: 0; } /* Offline banner */ .offline-banner { display: none; align-items: center; gap: var(--space-2); background: var(--color-error-light); color: var(--color-error); padding: var(--space-3) var(--space-4); border-radius: var(--radius-sm); font-size: var(--text-sm); font-weight: 600; margin-bottom: var(--space-4); animation: step-in 220ms ease; } .offline-banner.visible { display: flex; } .offline-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--color-error); flex-shrink: 0; animation: pulse 1.4s ease-in-out infinite; } /* ============================================================ Web / desktop environment (min-width: 900px) Mobile layout above this point is untouched. ============================================================ */ @media (min-width: 900px) { body { background: radial-gradient(640px circle at 12% 8%, rgba(96, 108, 56, 0.10), transparent 60%), radial-gradient(520px circle at 92% 85%, rgba(221, 161, 94, 0.16), transparent 60%), var(--color-bg); min-height: 100vh; padding: var(--space-7) var(--space-5); } .app-shell { max-width: 640px; margin: 0 auto; min-height: auto; border-radius: 20px; box-shadow: 0 30px 70px rgba(40, 54, 24, 0.16); overflow: hidden; } /* The provider shell is wider, to make room for the two-column layout */ .app-shell.provider-shell { max-width: 1080px; } .provider-page .app-main { padding-bottom: var(--space-6); } .provider-layout { display: grid; grid-template-columns: 380px 1fr; gap: var(--space-5); align-items: start; } /* On desktop both panes stay visible, mobile's one-at-a-time step system is only used below this breakpoint. */ .provider-layout .step { display: block !important; animation: none !important; } .provider-layout [data-step="list"] .hero { text-align: left; padding: 0 0 var(--space-4); } .provider-layout [data-step="list"] .hero-orb-wrap { margin: 0 0 var(--space-3); width: 64px; height: 64px; } .provider-layout [data-step="list"] .hero-orb { width: 56px; height: 56px; } .provider-layout [data-step="list"] .hero-orb svg { width: 24px; height: 24px; } .provider-layout [data-step="list"] .hero-orb-glow { inset: -10px; } .provider-layout [data-step="respond"] #back-to-list { display: none; } .provider-layout [data-step="respond"] .btn-row { justify-content: flex-end; } .provider-layout [data-step="respond"] .btn-provider { width: auto; padding-left: var(--space-6); padding-right: var(--space-6); } .detail-placeholder { display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; gap: var(--space-3); min-height: 320px; border: 1px dashed var(--color-border); border-radius: var(--radius); padding: var(--space-6); color: var(--color-text-secondary); } .detail-placeholder-mark { position: static; width: 44px; height: 44px; background: var(--color-provider-accent-light); } .detail-placeholder-mark svg { width: 20px; height: 20px; color: var(--color-provider-accent-text); } /* Patient shell: a composed, contained card on a filled background, rather than a phone screen stretched across a wide window. */ .patient-shell .hero { padding-top: var(--space-3); } } /* Icons inside buttons and labels */ .icon { width: 18px; height: 18px; flex-shrink: 0; } .icon-sm { width: 14px; height: 14px; } /* Loading spinner, shown inside buttons while an AI step is running */ .spinner { width: 16px; height: 16px; border-radius: 50%; border: 2px solid rgba(255, 255, 255, 0.4); border-top-color: currentColor; animation: spin 700ms linear infinite; flex-shrink: 0; } .btn-secondary .spinner, .btn[disabled] .spinner { border: 2px solid rgba(0, 0, 0, 0.15); border-top-color: currentColor; } @keyframes spin { to { transform: rotate(360deg); } } @media (prefers-reduced-motion: reduce) { .spinner { animation-duration: 1400ms; } } /* Recording timer */ .record-timer { font-variant-numeric: tabular-nums; font-weight: 600; } /* Status badges, used in the provider queue and patient history */ .status-badge { display: inline-flex; align-items: center; gap: 4px; font-size: var(--text-sm); font-weight: 600; padding: 2px 10px; border-radius: 999px; } .status-badge.waiting { background: var(--color-provider-accent-light); color: var(--color-provider-accent-text); } .status-badge.answered { background: #E3EDE3; color: var(--color-success); } /* Waiting-state status timeline: 3 honest steps (submitted / waiting / ready). Only "submitted" and "waiting" are ever shown as reached, because that's genuinely all two states the backend tracks; the app never fabricates an in-between "provider is reviewing" stage. */ .status-timeline { display: flex; align-items: flex-start; margin: var(--space-4) 0 var(--space-5); } .timeline-step { display: flex; flex-direction: column; align-items: center; flex: 1; min-width: 0; text-align: center; } .timeline-dot { width: 16px; height: 16px; border-radius: 50%; background: var(--color-surface); border: 2px solid var(--color-border); margin-bottom: var(--space-2); flex-shrink: 0; } .timeline-step.done .timeline-dot { background: var(--color-primary); border-color: var(--color-primary); } .timeline-step.current .timeline-dot { border-color: var(--color-primary); box-shadow: 0 0 0 4px var(--color-primary-light); animation: timeline-pulse 1.8s ease-in-out infinite; } @keyframes timeline-pulse { 0%, 100% { box-shadow: 0 0 0 4px var(--color-primary-light); } 50% { box-shadow: 0 0 0 7px var(--color-primary-light); } } @media (prefers-reduced-motion: reduce) { .timeline-step.current .timeline-dot { animation: none; } } .timeline-label { font-size: var(--text-sm); font-weight: 600; color: var(--color-text-secondary); line-height: 1.3; } .timeline-step.done .timeline-label, .timeline-step.current .timeline-label { color: var(--color-text); } .timeline-connector { flex: 0 0 auto; width: 32px; height: 2px; background: var(--color-border); margin: 7px -4px 0; } /* General, clearly-non-personalized safety guidance shown while waiting. Uses the primary-light tint rather than the error/warning colors, since it's reassurance and a standing safety note, not an alert. */ .waiting-note { background: var(--color-primary-light); border-left: 3px solid var(--color-primary); border-radius: var(--radius-sm); padding: var(--space-3) var(--space-4); font-size: var(--text-sm); color: var(--color-text); margin-bottom: var(--space-4); } .waiting-note strong { color: var(--color-primary-dark); } /* Custom audio player, replaces the bare native