/* ============================================================ DENTAL SOAP — Design System: "Clinical Editorial" (ivory/ink/amber) Implemented from the Dental SOAP Design System bundle: warm near-monochrome ink + ivory; amber is the ONLY chromatic accent and is reserved exclusively for safety. No red. No green. Flat warm surfaces — no gradients, no glassmorphism. ============================================================ */ /* ---------- Google Fonts ---------- */ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Inter+Tight:wght@500;600;700&family=IBM+Plex+Mono:wght@400;500;600&family=IBM+Plex+Sans+Arabic:wght@400;500;600;700&display=swap'); @import url('https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap'); /* ---------- Design tokens ---------- */ :root { /* Ink ramp (warm near-blacks → warm grays) */ --ink-900: #0D0D0D; --ink-800: #1A1815; --ink-700: #2B2823; --ink-600: #46423B; --ink-500: #6B665C; --ink-400: #8C887E; --ink-300: #B4AFA4; --ink-200: #D2CDC2; /* Ivory ramp (warm off-whites → warm paper greys) */ --ivory-50: #FBFAF7; --ivory-100: #F5F4F0; --ivory-200: #EDEBE4; --ivory-300: #E2DFD6; --ivory-400: #D2CEC2; /* Amber — SAFETY ONLY */ --amber-700: #B45309; --amber-600: #D97706; --amber-500: #F59E0B; --amber-400: #FBBF24; --amber-100: #FCEFD2; --amber-50: #FDF6E7; /* Legacy alias map (kept so every existing rule keeps resolving) */ --primary: var(--ink-900); --primary-container: var(--ink-700); --on-primary: var(--ivory-50); --on-primary-container: var(--ivory-50); --primary-fixed: var(--ivory-200); --primary-fixed-dim: var(--ivory-400); --surface: var(--ivory-100); --surface-bright: var(--ivory-100); --surface-container-lowest: var(--ivory-50); --surface-container-low: var(--ivory-200); --surface-container: var(--ivory-200); --surface-container-high: var(--ivory-300); --surface-container-highest: var(--ivory-300); --surface-dim: var(--ivory-400); --surface-tint: var(--ink-700); --on-surface: var(--ink-900); --on-surface-variant: var(--ink-600); --inverse-surface: var(--ink-800); --outline: var(--ink-300); --outline-variant: var(--ivory-400); /* "Error"/danger now routes to the amber safety system (no red) */ --error: var(--amber-700); --error-container: var(--amber-100); --on-error: var(--ink-900); --on-error-container: var(--amber-700); /* Tertiary: neutral ink (the old clinical green-teal is retired) */ --tertiary: var(--ink-300); --tertiary-container: var(--ink-500); --on-tertiary: var(--ivory-50); --secondary: var(--ink-600); --secondary-container: var(--ivory-200); --on-secondary: var(--ivory-50); --on-secondary-container: var(--ink-600); /* Functional aliases */ --brand: var(--ink-900); --brand-deep: var(--ink-800); --ink: var(--ink-900); --muted: var(--ink-500); --page: var(--ivory-100); --paper: var(--ivory-50); /* "Gradients" — retired; vars now resolve to flat ink fills */ --grad-brand: var(--ink-900); --grad-brand-hover: var(--ink-700); --grad-deep: var(--ink-900); /* "Glass" — retired; solid warm surfaces */ --glass-bg: var(--ivory-50); --glass-blur: none; --glass-border: var(--ivory-300); /* Safety (amber system — urgency by intensity, never hue) */ --safety-accent: var(--amber-500); --safety-fg: var(--amber-700); --safety-bg: var(--amber-50); --safety-bg-strong: var(--amber-100); --safety-border: #E8C98A; --safe-bg: var(--ivory-50); /* clear state: neutral, never green */ --safe-line: var(--ivory-400); --danger: var(--amber-500); --danger-bg: var(--amber-50); --danger-line: #E8C98A; --amber: var(--amber-700); /* Radius — sheet feels like paper (4px); inputs 8px; cards 12px */ --radius: 12px; --radius-sm: 8px; --radius-xs: 6px; --radius-sheet: 4px; /* Shadows — soft, warm-tinted, ambient */ --shadow-card: 0 1px 3px rgba(26, 24, 21, 0.05), 0 6px 16px -8px rgba(26, 24, 21, 0.08); --shadow-card-hover: 0 2px 6px rgba(26, 24, 21, 0.05), 0 14px 32px -12px rgba(26, 24, 21, 0.12); --shadow-float: 0 1px 2px rgba(26, 24, 21, 0.05), 0 18px 48px -20px rgba(26, 24, 21, 0.22); /* Typography */ --font-headline: 'Inter Tight', 'Inter', system-ui, sans-serif; --font-body: 'Inter', system-ui, sans-serif; --font-mono: 'IBM Plex Mono', 'Fira Mono', monospace; --font-arabic: 'IBM Plex Sans Arabic', 'Noto Sans Arabic', 'Geeza Pro', sans-serif; } /* ---------- Color scheme lock (always light) ---------- */ :root { color-scheme: light; } /* ---------- Single-theme guard (safety net) ---------- Dental SOAP has no dark variant. A synchronous script forces ?__theme=light before the Gradio bundle loads. THIS block is the fallback for the rare case that redirect is blocked (sandboxed iframe / strict CSP): it re-pins Gradio's dark-theme variables to the light palette so .dark renders identically to light. Without it, Gradio's dark --body-text-color (#f5f5f4) repaints every text rule lacking !important to near-white on our forced-ivory surfaces — invisible. */ .dark { /* !important on each custom property is required: Gradio's own .dark variable block has equal specificity and loads after this stylesheet, so a plain re-pin loses the source-order tie (verified: --body-text-color stayed #f5f5f4). !important wins the cascade regardless of order. */ color-scheme: light; --body-text-color: var(--ink-900) !important; --body-text-color-subdued: var(--ink-500) !important; --background-fill-primary: var(--ivory-100) !important; --background-fill-secondary: var(--ivory-50) !important; --block-background-fill: var(--ivory-50) !important; --block-label-text-color: var(--ink-600) !important; --block-title-text-color: var(--ink-900) !important; --input-background-fill: var(--ivory-50) !important; --input-border-color: var(--ivory-400) !important; --border-color-primary: var(--ivory-300) !important; --border-color-accent: var(--ink-700) !important; --panel-background-fill: var(--ivory-100) !important; --color-accent: var(--ink-700) !important; --link-text-color: var(--ink-900) !important; } /* ---------- Base / Background — flat warm ivory, no gradients ---------- */ html, body, gradio-app, .main, .wrap, main.contain, .gradio-container { background: var(--surface) !important; color: var(--ink) !important; font-family: var(--font-body) !important; } body { background-attachment: fixed; } /* ---------- Form controls ---------- */ textarea, input, select, .gradio-container textarea, .gradio-container input { background: var(--surface-container-lowest) !important; color: var(--ink) !important; border: 1px solid var(--outline-variant) !important; border-radius: var(--radius-sm) !important; font-family: var(--font-body) !important; transition: border-color 0.2s ease, box-shadow 0.2s ease !important; } textarea:focus, input:focus, .gradio-container textarea:focus, .gradio-container input:focus { border-color: var(--ink-900) !important; box-shadow: 0 0 0 3px rgba(13, 13, 13, 0.08) !important; outline: none !important; } /* ---------- Ghost document (pre-build empty state) ---------- */ /* A faint preview of the REAL handoff card: same paper, same ink band, real section headings over unfilled lines — the empty state sells the artifact. Static on purpose: the shimmer skeleton means "composing now"; the ghost means "awaiting your story". */ .ghost-line { height: 11px; margin: 7px 0; border-radius: 4px; background: var(--ivory-200); border: 1px dashed var(--ivory-400); } .ghost-sec { margin-top: 2px; } .handoff-card.ghost .doc-body h3 { color: var(--ink-400) !important; } .doc-badge.ghost-badge { background: transparent; border-style: dashed; } .ghost-cta { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-500); margin: 14px 0 2px; } /* ---------- Container ---------- */ .gradio-container { max-width: 1280px !important; margin: 0 auto !important; font-family: var(--font-body) !important; color: var(--ink); background: transparent !important; padding-bottom: 80px !important; /* Gradio accent (progress bars, generating pulse) on ink */ --color-accent: var(--ink-700); } /* ---------- Header ---------- */ .app-header { display: flex; justify-content: space-between; align-items: flex-end; gap: 16px; flex-wrap: wrap; padding: 20px 4px 10px; } .brand-row { display: flex; align-items: center; gap: 14px; } .brand-mark { flex: none; width: 46px; height: 46px; border-radius: 12px; background: var(--ink-900); box-shadow: var(--shadow-card); display: flex; align-items: center; justify-content: center; } .brand-name { font-family: var(--font-headline); font-size: 26px; font-weight: 600; line-height: 1; color: var(--ink); letter-spacing: -0.02em; } .brand-tag { color: var(--muted); font-size: 13px; margin-top: 4px; font-weight: 500; font-family: var(--font-body); } .privacy-pill { border: 1px solid var(--outline-variant); background: var(--ivory-50); color: var(--ink-600); font-family: var(--font-mono); font-size: 10.5px; font-weight: 500; letter-spacing: 0.10em; text-transform: uppercase; padding: 7px 16px; border-radius: 9999px; box-shadow: var(--shadow-card); } /* ---------- Step rail ---------- */ .step-rail { display: flex; gap: 8px; flex-wrap: wrap; margin: 4px 0 8px; } .rail-chip { display: flex; align-items: center; gap: 7px; border: 1px solid var(--outline-variant); background: var(--ivory-50); border-radius: 9999px; padding: 5px 14px 5px 6px; font-size: 12px; font-weight: 600; letter-spacing: 0.01em; color: var(--ink-700); box-shadow: var(--shadow-card); font-family: var(--font-body); } .rail-chip .n { width: 20px; height: 20px; border-radius: 9999px; background: var(--ink-900); color: var(--ivory-50); display: flex; align-items: center; justify-content: center; font-size: 11px; font-weight: 600; font-family: var(--font-mono); } /* ---------- Step cards ---------- */ /* Hairline borders + tonal layering; faint warm shadow. */ .step-card { background: var(--surface-container-lowest) !important; border: 1px solid var(--ivory-300) !important; border-radius: var(--radius) !important; padding: 22px 22px 18px !important; box-shadow: var(--shadow-card) !important; transition: box-shadow 0.25s ease, border-color 0.25s ease; margin-bottom: 12px; } .step-card:hover { box-shadow: var(--shadow-card-hover) !important; border-color: var(--ivory-400) !important; } .step-card .block, .step-card .form, .step-card .styler { border: none !important; box-shadow: none !important; background: transparent !important; } /* Flatten Gradio Soft theme's block-info chip — eyebrow style: mono, tracked */ span[data-testid="block-info"] { background: transparent !important; color: var(--muted) !important; font-weight: 500 !important; font-size: 11px !important; letter-spacing: 0.10em !important; text-transform: uppercase !important; font-family: var(--font-mono) !important; } .step-head { display: flex; gap: 14px; align-items: flex-start; margin-bottom: 14px; } .step-num { flex: none; width: 32px; height: 32px; border-radius: 9999px; background: var(--ink-900); color: var(--ivory-50); font-weight: 600; font-size: 14px; display: flex; align-items: center; justify-content: center; margin-top: 1px; box-shadow: var(--shadow-card); font-family: var(--font-mono); } .step-title { font-family: var(--font-headline); font-weight: 600; font-size: 16px; color: var(--ink); letter-spacing: -0.01em; } .step-sub { color: var(--muted); font-size: 12.5px; margin-top: 3px; font-family: var(--font-body); } /* ---------- Buttons ---------- */ /* Primary = ink fill with ivory text (never amber). */ button.primary, .primary.svelte-cmf5ev { background: var(--ink-900) !important; border: 1px solid transparent !important; color: var(--ivory-50) !important; border-radius: var(--radius) !important; font-weight: 600 !important; font-family: var(--font-body) !important; letter-spacing: 0.01em !important; box-shadow: var(--shadow-card) !important; transition: background 0.14s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.14s cubic-bezier(0.4, 0, 0.2, 1), transform 0.14s cubic-bezier(0.4, 0, 0.2, 1) !important; } button.primary:hover { background: var(--ink-700) !important; box-shadow: var(--shadow-card-hover) !important; } button.primary:active { transform: translateY(0.5px) scale(0.992); } /* Secondary / ghost buttons — outline on warm paper */ button:not(.primary) { background: var(--ivory-50) !important; border: 1px solid var(--outline-variant) !important; color: var(--on-surface-variant) !important; border-radius: var(--radius) !important; font-family: var(--font-body) !important; font-weight: 500 !important; transition: background 0.2s ease, border-color 0.2s ease !important; } button:not(.primary):hover { background: var(--surface-container) !important; border-color: var(--ink-300) !important; color: var(--ink-900) !important; } /* Example chips */ .example-chip { border: 1px solid var(--outline-variant) !important; background: var(--ivory-50) !important; color: var(--ink-700) !important; font-weight: 600 !important; font-size: 12.5px !important; border-radius: 9999px !important; letter-spacing: 0.01em !important; box-shadow: var(--shadow-card) !important; transition: border-color 0.2s ease, box-shadow 0.2s ease, background 0.2s ease !important; font-family: var(--font-body) !important; } .example-chip:hover { border-color: var(--ink-300) !important; background: var(--surface-container) !important; box-shadow: var(--shadow-card-hover) !important; color: var(--ink-900) !important; } /* ---------- Status line ---------- */ .status-line, .status-line p { color: var(--muted) !important; font-size: 12px !important; font-weight: 500 !important; letter-spacing: 0.03em !important; font-family: var(--font-body) !important; } /* ---------- Safety panel ---------- */ /* Amber wash + 3px amber left accent for a fired rule. Clear state stays NEUTRAL ink/ivory — never green. */ .safety-panel { border: 1px solid var(--safety-border); border-left: 3px solid var(--safety-accent); background: var(--safety-bg); color: var(--ink-900); border-radius: var(--radius); padding: 18px 20px; box-shadow: var(--shadow-card); transition: border-color 0.25s ease; } .safety-panel, .safety-panel strong, .safety-panel p, .safety-panel .flag-title, .safety-panel .flag-body { color: var(--ink-900) !important; } .safety-panel.clear { border-color: var(--ivory-400); border-left: 3px solid var(--ink-300); background: var(--ivory-50); color: var(--ink-600); box-shadow: var(--shadow-card); } .safety-panel.clear, .safety-panel.clear strong, .safety-panel.clear p { color: var(--ink-600) !important; } .safety-kicker { font-size: 10.5px; letter-spacing: 0.12em; text-transform: uppercase; font-weight: 500; opacity: 0.9; margin-bottom: 6px; font-family: var(--font-mono); } .safety-kicker { color: var(--safety-fg) !important; } .safety-panel.clear .safety-kicker { color: var(--ink-400) !important; } .safety-panel p { margin: 4px 0 0; font-size: 13.5px; line-height: 1.65; } /* Flag blocks within safety panel */ .flag { border-top: 1px solid var(--safety-border); padding-top: 14px; margin-top: 14px; } /* Tier pills — amber intensity encodes urgency (solid → tint → outline) */ .tier-pill { display: inline-block; font-size: 10.5px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; border-radius: var(--radius-xs); padding: 4px 10px; margin-bottom: 8px; font-family: var(--font-mono); } .tier-emergency { background: var(--amber-500); color: var(--ink-900); border: 1px solid var(--amber-500); box-shadow: 0 2px 10px rgba(245, 158, 11, 0.35); } .tier-urgent { background: var(--safety-bg-strong); color: var(--safety-fg); border: 1px solid var(--safety-accent); } .tier-discuss { background: transparent; color: var(--ink-600); border: 1px solid var(--ink-300); } .flag-title { font-family: var(--font-headline); font-weight: 600; font-size: 14.5px; letter-spacing: -0.01em; } .flag-body { font-size: 13.5px; line-height: 1.65; margin-top: 4px; } .evidence { color: var(--muted); font-size: 12.5px; margin-top: 8px; border-left: 2px solid var(--safety-accent); padding-left: 10px; font-style: italic; font-family: var(--font-body); } /* Safety-flag provenance disclosure — collapsed by default, expands to the exact rule + matched evidence spans. The deterministic "show your work". */ .flag-rule { margin-top: 9px; } .flag-rule > summary { cursor: pointer; list-style: none; display: inline-flex; align-items: center; gap: 8px; font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-500); -webkit-user-select: none; user-select: none; } .flag-rule > summary::-webkit-details-marker { display: none; } .flag-rule > summary::before { content: "\25B8"; /* ▸ */ color: var(--ink-400); font-size: 9px; transition: transform 0.15s ease; } .flag-rule[open] > summary::before { transform: rotate(90deg); } .flag-rule-k { color: var(--ink-600); } .flag-rule-id { background: var(--ivory-200); border: 1px solid var(--ink-300); border-radius: var(--radius-xs); padding: 1px 6px; color: var(--ink-700); } .flag-evidence { margin-top: 8px; border-left: 2px solid var(--safety-accent); padding-left: 10px; } /* Static evidence copy for paper only — the interactive
twin above cannot render its content when printed closed. */ .flag-evidence-print { display: none; } .ev-span { font-size: 12.5px; color: var(--ink-600); font-style: italic; margin: 3px 0; line-height: 1.5; } .ev-src { font-style: normal; font-family: var(--font-mono); font-size: 9.5px; text-transform: uppercase; letter-spacing: 0.05em; color: var(--ink-400); margin-right: 6px; } /* ---------- Handoff document card ---------- */ /* The one element with a real lift (paper on desk); near-sharp corners so it reads as a physical Letter/A4 sheet. */ .handoff-card { border: 1px solid var(--ivory-300); background: var(--paper); border-radius: var(--radius-sheet); overflow: hidden; box-shadow: 0 1px 2px rgba(26, 24, 21, 0.05), 0 18px 48px -20px rgba(26, 24, 21, 0.22); } /* Result reveal: the finished document settles onto the desk. Gradio swaps the HTML node on every render, so the animation re-fires exactly once per build. */ @keyframes cardSettle { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } } @media (prefers-reduced-motion: no-preference) { .handoff-card, .safety-panel, .interrupt-card { animation: cardSettle 0.45s cubic-bezier(0.19, 0.66, 0.28, 0.99) both; } } .doc-band { background: var(--ink-900); padding: 20px 28px; display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap; } /* Force ivory text in band (Gradio prose overrides inherited) */ .doc-band, .doc-band * { color: var(--ivory-50) !important; } .interrupt-band, .interrupt-band * { color: var(--ink-900) !important; } .doc-band .product { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.16em; text-transform: uppercase; opacity: 0.7; font-weight: 500; } .doc-band .artifact { font-family: var(--font-headline); font-size: 22px; font-weight: 600; margin-top: 4px; letter-spacing: -0.02em; } .doc-meta { font-family: var(--font-body); font-size: 11.5px; text-align: right; line-height: 1.6; max-width: 62%; } .doc-meta .patient-line { font-weight: 600; font-size: 13px; letter-spacing: 0.01em; margin-bottom: 7px; } .doc-badges { display: flex; flex-wrap: wrap; gap: 6px; justify-content: flex-end; } .doc-badge { display: inline-flex; align-items: center; padding: 3px 11px; border-radius: 999px; font-size: 10.5px; font-weight: 500; letter-spacing: 0.05em; font-family: var(--font-mono); background: rgba(255, 255, 255, 0.10); border: 1px solid rgba(255, 255, 255, 0.26); white-space: nowrap; } .doc-badge.flag-clear { background: rgba(255, 255, 255, 0.10); border-color: rgba(255, 255, 255, 0.30); } .doc-badge.flag-alert { background: rgba(245, 158, 11, 0.22); border-color: rgba(245, 158, 11, 0.60); } .doc-body { padding: 10px 28px 28px; } .doc-body, .doc-body p, .doc-body li, .doc-body ol, .doc-body ul { color: var(--ink) !important; } /* Section headers: Title-Case content, mono tracked label treatment */ .doc-body h3 { font-family: var(--font-mono); font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.12em; color: var(--ink-500); border-top: 1px solid var(--ivory-300); padding-top: 16px; margin: 20px 0 8px; font-weight: 500; } .doc-body h3 { color: var(--ink-500) !important; } .doc-body p, .doc-body li { font-size: 13.5px; line-height: 1.70; font-family: var(--font-body); } .doc-body p { margin: 5px 0 0; } .doc-body ul, .doc-body ol { margin: 6px 0 0 20px; padding: 0; } .doc-body li { margin-bottom: 6px; } /* Plain section bullets — quiet ink dot. Classed lists (tracker/bring checkboxes) keep their own markers. */ .doc-body ul:not([class]) { list-style: none; margin-left: 0; } .doc-body ul:not([class]) > li { position: relative; padding-left: 22px; } .doc-body ul:not([class]) > li::before { content: ""; position: absolute; left: 6px; top: 0.62em; width: 5px; height: 5px; border-radius: 50%; background: var(--ink-400); } /* Numbered dentist questions — circled mono counters */ .doc-body ol { list-style: none; counter-reset: dq; margin-left: 0; } .doc-body ol > li { counter-increment: dq; position: relative; padding-left: 32px; margin-bottom: 9px; } .doc-body ol > li::before { content: counter(dq); position: absolute; left: 0; top: 1px; width: 21px; height: 21px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-family: var(--font-mono); font-size: 11px; font-weight: 600; background: transparent; border: 1px solid var(--ink-300); color: var(--ink-700) !important; } /* RTL mirror for the Arabic card */ .arabic .doc-body ul:not([class]) > li { padding-right: 22px; padding-left: 0; } .arabic .doc-body ul:not([class]) > li::before { right: 6px; left: auto; } .arabic .doc-body ol > li { padding-right: 32px; padding-left: 0; } .arabic .doc-body ol > li::before { right: 0; left: auto; } .arabic .doc-badges { justify-content: flex-start; } /* Tracker checklist — custom checkbox via ::before */ ul.tracker { margin-left: 0 !important; } ul.tracker li { list-style: none; position: relative; padding-left: 28px; } ul.tracker li::before { content: ""; position: absolute; left: 0; top: 4px; width: 14px; height: 14px; border: 1.5px solid var(--ink-400); border-radius: 4px; background: var(--ivory-50); } /* IBM Plex Mono for clinical vitals/data values in the handoff card */ .doc-body .mono-value, .doc-body code, .doc-body kbd { font-family: var(--font-mono); font-size: 12.5px; font-variant-numeric: tabular-nums; background: var(--surface-container-low); padding: 1px 6px; border-radius: 4px; color: var(--ink-700); } .doc-foot { border-top: 1px solid var(--ivory-300); margin-top: 20px; padding-top: 14px; color: var(--muted); font-size: 11.5px; line-height: 1.60; font-family: var(--font-body); } .doc-foot { color: var(--muted) !important; } .doc-foot-meta { font-family: var(--font-mono); font-size: 9.5px; letter-spacing: 0.04em; color: var(--ink-400) !important; margin-bottom: 7px; } /* ---------- Hard interrupt card ---------- */ /* The ONLY solid-amber-filled element in the product: maximal urgency is encoded by fill + scale + contrast, not by red. Ink text on amber. */ .interrupt-card { border: 1.5px solid var(--amber-500); background: var(--surface-container-lowest); border-radius: var(--radius-sm); overflow: hidden; box-shadow: 0 1px 2px rgba(26, 24, 21, 0.05), 0 12px 32px rgba(245, 158, 11, 0.18), 0 28px 56px -16px rgba(26, 24, 21, 0.14); } .interrupt-band { background: var(--amber-500); color: var(--ink-900); padding: 18px 28px; font-family: var(--font-headline); font-weight: 700; font-size: 18px; letter-spacing: -0.01em; } .interrupt-body { padding: 12px 28px 24px; } .interrupt-body, .interrupt-body p, .interrupt-body li, .interrupt-body strong { color: var(--ink-800) !important; } .interrupt-body h3 { font-family: var(--font-mono); font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.12em; color: var(--amber-700); margin: 16px 0 5px; font-weight: 600; } .interrupt-body h3 { color: var(--amber-700) !important; } .interrupt-body p, .interrupt-body li { font-size: 13.5px; line-height: 1.65; } /* ---------- Arabic RTL ---------- */ /* IBM Plex Sans Arabic; Arabic text ~10% larger than the English equivalent, line-height 2.0 so descenders breathe (headline feature). */ .arabic { direction: rtl; text-align: right; font-family: var(--font-arabic); } .arabic .doc-meta { text-align: left; } .arabic .doc-body p, .arabic .doc-body li { font-size: 15px; /* 10% larger than 13.5px English base */ line-height: 2.0; } /* Untranslated patient/model narrative inside the Arabic card carries a small "(as written by the patient)" annotation so English under an Arabic heading reads as provenance, not a rendering bug. */ .arabic .as-written { font-size: 12px; color: var(--ink-400) !important; font-style: normal; } /* Arabic script connects letters — Latin tracking rules (uppercase letter-spacing on h3/artifact) visibly break the joins, and the mono heading stack has no Arabic glyphs (random system fallback). Use the loaded Plex Arabic and reset tracking. */ .arabic .doc-body h3, .arabic .doc-band .artifact { letter-spacing: 0; font-family: var(--font-arabic); } .arabic .doc-body h3 { font-weight: 600; font-size: 12px; } /* Patient text fields auto-detect direction: an Egyptian Arabic story aligns right as it is typed, English stays left — no settings toggle needed. */ .gradio-container textarea, .gradio-container input[type="text"] { unicode-bidi: plaintext; } /* ---------- Disclaimer ribbon ---------- */ #disclaimer-block, .block:has(.disclaimer-bar) { position: relative !important; z-index: 2; } .disclaimer-bar { display: flex; align-items: flex-start; gap: 14px; background: var(--ivory-50); border: 1px solid var(--ivory-300); color: var(--on-surface-variant); text-align: left; font-size: 12.5px; line-height: 1.55; padding: 12px 16px; border-radius: var(--radius); margin: 8px 0 16px; box-shadow: var(--shadow-card); } .disclaimer-bar, .disclaimer-bar * { color: var(--on-surface-variant) !important; } .disclaimer-bar strong { color: var(--ink) !important; font-weight: 600; } .disclaimer-kicker { flex: none; color: var(--ink-700) !important; background: var(--ivory-200); border-radius: 9999px; padding: 4px 9px; font-family: var(--font-mono); font-size: 10px; font-weight: 500; letter-spacing: 0.10em; line-height: 1.35; text-transform: uppercase; } .disclaimer-copy { padding-top: 2px; } /* ---------- Agent Activity Dashboard ---------- */ .agent-dashboard { border: 1px solid var(--ivory-300); background: var(--surface-container-lowest); border-radius: var(--radius); margin-bottom: 12px; box-shadow: var(--shadow-card); overflow: hidden; } /* Ink header band — mirrors the handoff card's doc-band so the workflow reads as a first-class, authoritative panel rather than a footnote. */ .agent-dashboard-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; background: var(--ink-900); padding: 12px 16px; } .agent-dashboard-title { font-family: var(--font-mono); font-size: 10.5px; letter-spacing: 0.12em; text-transform: uppercase; font-weight: 500; /* !important: the Space's SSR bundle loads prose CSS after this sheet and wins the cascade tie. */ color: var(--ivory-50) !important; } .agent-dashboard-note { color: var(--ink-300) !important; font-size: 11.5px; line-height: 1.45; margin-top: 3px; } .workflow-route { flex: none; border: 1px solid var(--ink-600); background: var(--ink-700); color: var(--ivory-50) !important; border-radius: 9999px; padding: 4px 9px; font-size: 9.5px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; font-family: var(--font-mono); } .agent-list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; padding: 14px 16px 16px; } .agent-row { display: flex; justify-content: space-between; align-items: center; gap: 8px; min-width: 0; padding: 8px 10px; border-radius: var(--radius-sm); background: var(--surface-container-low); font-size: 12.5px; font-family: var(--font-body); } .agent-name { display: block; font-weight: 600; color: var(--ink); line-height: 1.25; } .agent-role { display: block; color: var(--muted); font-size: 10.5px; line-height: 1.35; margin-top: 2px; } /* Provenance type badge: RULE = deterministic (emphasized solid ink) vs LLM = model-driven (light outline). Makes "the model can never author a safety flag" legible at a glance — the core trust differentiator. */ .agent-type { font-family: var(--font-mono); font-size: 8.5px; font-weight: 600; letter-spacing: 0.07em; padding: 1px 5px; border-radius: var(--radius-xs); margin-left: 7px; text-transform: uppercase; white-space: nowrap; } .type-llm { background: var(--ivory-200); color: var(--ink-600) !important; border: 1px solid var(--ink-300); } .type-rule { background: var(--ink-900); color: var(--ivory-50) !important; border: 1px solid var(--ink-900); } /* Tabular figures everywhere clinical numbers appear (tooth #, pain x/10, dates, counts) so columns and updating values stay aligned — a quiet but strong "this was designed" signal. */ .doc-band, .doc-meta, .patient-line, .doc-badge, .tier-pill, .agent-status, .workflow-route, .agent-type, .privacy-pill, .doc-body, .mono-value { font-variant-numeric: tabular-nums; } /* ---------- Loading skeleton (handoff cold-start) ---------- */ @keyframes skelShimmer { 0% { background-position: -240px 0; } 100% { background-position: 240px 0; } } .skel-line, .skel-h3 { background: linear-gradient(90deg, var(--ivory-200) 25%, var(--ivory-300) 50%, var(--ivory-200) 75%); background-size: 240px 100%; animation: skelShimmer 1.25s linear infinite; border-radius: 4px; } .skel-line { height: 11px; margin: 7px 0; } .skel-sec { margin-top: 15px; } .skel-sec .skel-line:last-child { width: 62%; } .skel-h3 { height: 8px; width: 116px; margin-bottom: 10px; } .skel-title, .skel-badge { background: linear-gradient(90deg, rgba(251,250,247,0.14) 25%, rgba(251,250,247,0.34) 50%, rgba(251,250,247,0.14) 75%); background-size: 240px 100%; animation: skelShimmer 1.25s linear infinite; } .skel-title { height: 16px; width: 172px; margin-top: 8px; border-radius: 4px; } .skel-badges { display: flex; gap: 6px; } .skel-badge { width: 62px; height: 17px; border-radius: 9999px; } .skel-note { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-400); margin-bottom: 4px; } .agent-status { font-family: var(--font-mono); font-size: 9.5px; padding: 3px 7px; border-radius: var(--radius-xs); font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em; display: inline-block; min-width: 64px; text-align: center; white-space: nowrap; } /* Workflow statuses — neutral ink system (process info, not safety): intensity encodes state. No green, no red, no off-palette hues. color is !important: the live Space SSR bundle wins cascade ties and repaints chip text ink-on-ink (Cached/Passed/flag-count unreadable). */ .status-idle { background: var(--surface-container); color: var(--muted) !important; border: 1px solid var(--outline-variant); } .status-ready { background: var(--ivory-50); color: var(--ink-700) !important; border: 1px solid var(--ink-300); } .status-active { background: var(--ink-700); color: var(--ivory-50) !important; border: 1px solid var(--ink-700); } .status-complete { background: var(--ink-900); color: var(--ivory-50) !important; border: 1px solid var(--ink-900); } .status-bypass { background: var(--ivory-200); color: var(--ink-600) !important; border: 1px dashed var(--ink-300); } .status-template { background: var(--ivory-50); color: var(--ink-500) !important; border: 1px dashed var(--ivory-400); } @keyframes agentPulse { 0% { opacity: 0.70; } 50% { opacity: 1.00; transform: scale(1.02); } 100% { opacity: 0.70; } } /* ---------- Tabs styling ---------- */ .gradio-container .tab-nav button { font-family: var(--font-body) !important; font-weight: 500 !important; font-size: 13.5px !important; color: var(--muted) !important; background: transparent !important; border: none !important; border-bottom: 2px solid transparent !important; border-radius: 0 !important; padding: 10px 16px !important; box-shadow: none !important; transition: color 0.2s ease, border-color 0.2s ease !important; } .gradio-container .tab-nav button.selected, .gradio-container .tab-nav button[aria-selected="true"] { color: var(--ink-900) !important; border-bottom-color: var(--ink-900) !important; font-weight: 600 !important; background: transparent !important; box-shadow: none !important; } .gradio-container .tab-nav button:hover:not(.selected) { color: var(--on-surface) !important; background: var(--surface-container-low) !important; } /* ---------- Chatbot bubbles ---------- */ /* Guided interview identity and progress */ .interview-guide-card { background: var(--ivory-50); border: 1px solid var(--ivory-300); border-radius: var(--radius); box-shadow: var(--shadow-card); padding: 16px 18px 14px; margin-bottom: 10px; } .guide-identity { display: flex; align-items: center; gap: 11px; } .guide-mini-avatar { width: 38px; height: 38px; border-radius: 12px; display: grid; place-items: center; flex: none; color: var(--ivory-50); background: var(--ink-900); box-shadow: var(--shadow-card); } .guide-mini-avatar .material-symbols-outlined { font-size: 23px; } .guide-name { font-family: var(--font-headline); font-weight: 600; font-size: 14px; color: var(--ink); } .guide-role { color: var(--muted); font-size: 11.5px; margin-top: 1px; } .guide-stage { margin-left: auto; color: var(--ink-700); background: var(--ivory-200); border-radius: 9999px; padding: 5px 10px; font-size: 11.5px; font-weight: 600; white-space: nowrap; } .interview-progress-track { height: 5px; overflow: hidden; border-radius: 9999px; background: var(--surface-container); margin: 13px 0 11px; } .interview-progress-track span { display: block; height: 100%; border-radius: inherit; background: var(--ink-900); transition: width 0.35s cubic-bezier(0.4, 0, 0.2, 1); } .odipara-heading { color: var(--muted); font-family: var(--font-mono); font-size: 9.5px; font-weight: 500; letter-spacing: 0.10em; text-transform: uppercase; margin-bottom: 6px; } .odipara-row { display: flex; flex-wrap: wrap; gap: 6px; } .odipara-chip { display: inline-flex; align-items: center; gap: 5px; border: 1px solid var(--outline-variant); border-radius: 9999px; padding: 4px 8px 4px 5px; color: var(--muted); background: var(--ivory-50); font-size: 10.5px; font-weight: 600; } .odipara-letter { width: 18px; height: 18px; display: grid; place-items: center; border-radius: 9999px; background: var(--surface-container); color: var(--muted); font-size: 9px; font-weight: 600; font-family: var(--font-mono); } .odipara-chip.current { color: var(--ink-900); border-color: var(--ink-300); background: var(--ivory-200); } .odipara-chip.current .odipara-letter { color: var(--ivory-50); background: var(--ink-900); } .odipara-chip.covered { color: var(--ink-600); border-color: var(--ivory-400); background: var(--ivory-100); } .odipara-chip.covered .odipara-letter { color: var(--ivory-50); background: var(--ink-500); } .guide-guidance { color: var(--muted); font-size: 11.5px; line-height: 1.45; margin: 9px 0 0; } /* Assistant bubbles: sunken warm tint on left */ .gradio-container .message.bot, .gradio-container .message.assistant { background: var(--ivory-200) !important; border: 1px solid var(--ivory-300) !important; border-radius: 0 var(--radius) var(--radius) var(--radius) !important; font-family: var(--font-body) !important; font-size: 14px !important; color: var(--ink) !important; } /* User bubbles: paper, right-aligned */ .gradio-container .message.user, .gradio-container .message.human { background: var(--surface-container-lowest) !important; border: 1px solid var(--outline-variant) !important; border-radius: var(--radius) 0 var(--radius) var(--radius) !important; font-family: var(--font-body) !important; font-size: 14px !important; color: var(--ink) !important; } /* Chatbot container */ #interview-chat { background: var(--ivory-100) !important; border: 1px solid var(--outline-variant) !important; border-radius: var(--radius) !important; } #interview-chat img[alt="avatar"], #interview-chat .avatar-container img { border-radius: 12px !important; box-shadow: var(--shadow-card); } /* Gradio 6 leaves this pending bubble behind when unrelated example buttons update the page. Interview requests still use the top-level progress bar. */ #interview-chat [role="status"][aria-label="Loading response"] { display: none !important; } /* ---------- Checkbox groups as interactive tiles ---------- */ .gradio-container .checkbox-group label, .gradio-container .radio-group label { font-family: var(--font-body) !important; font-size: 13.5px !important; color: var(--on-surface-variant) !important; padding: 8px 12px !important; border-radius: var(--radius-xs) !important; transition: background 0.15s ease, color 0.15s ease !important; cursor: pointer; } .gradio-container .checkbox-group label:hover, .gradio-container .radio-group label:hover { background: var(--surface-container-low) !important; color: var(--ink-900) !important; } /* Checked state: ink emphasis */ .gradio-container .checkbox-group input:checked + span, .gradio-container .checkbox-group label:has(input:checked), .gradio-container .radio-group input:checked + span { color: var(--ink-900) !important; font-weight: 600 !important; } /* Checkbox accent color */ .gradio-container input[type="checkbox"], .gradio-container input[type="radio"] { accent-color: var(--ink-900) !important; } /* ---------- Slider ---------- */ .gradio-container input[type="range"] { accent-color: var(--ink-900) !important; } /* ---------- Section separators via whitespace ---------- */ .gradio-container .gap-6, .gradio-container .gap-4 { gap: 1.5rem !important; } /* ---------- Run-state polish (pending / generating) ---------- */ /* Gradio fades in-flight output components to opacity .2. During a ZeroGPU cold start that can last a minute, the whole artifact column reads as a broken, washed-out page. Keep pending content readable. */ .gradio-container .pending { opacity: 0.75 !important; transition: opacity 0.25s ease; } /* Gradio's generating pulse ships as a hard 2px accent frame. Re-brand it: thin, ink, rounded to match the card radius. */ .gradio-container .generating { border: 1.5px solid var(--ink-300) !important; border-radius: var(--radius-sm) !important; } /* ---------- Accordion chrome (Validated handoff JSON) ---------- */ /* NOTE: deliberately placed AFTER the generic `button:not(.primary)` rule — both carry !important, so source order breaks the tie. Keep this below it. */ .gradio-container button.label-wrap { font-family: var(--font-body) !important; font-size: 12.5px !important; font-weight: 600 !important; color: var(--muted) !important; background: var(--surface-container-low) !important; border: 1px solid var(--outline-variant) !important; border-radius: var(--radius-sm) !important; padding: 9px 12px !important; transition: background 0.15s ease, color 0.15s ease; } .gradio-container button.label-wrap:hover { color: var(--ink-900) !important; background: var(--surface-container) !important; } /* ---------- Keyboard focus ring — neutral ink, never amber ---------- */ .gradio-container :focus-visible { outline: 2px solid rgba(13, 13, 13, 0.55) !important; outline-offset: 2px; } /* ---------- Print: only the document zone ---------- */ @media print { body * { visibility: hidden; } .print-zone, .print-zone * { visibility: visible; } .print-zone { position: absolute; left: 0; top: 0; width: 100%; } .print-zone .no-print, .print-zone .no-print * { visibility: hidden; display: none !important; } .handoff-card { box-shadow: none; border: 1px solid #D2CEC2; background: #fff; } .safety-panel, .interrupt-card { backdrop-filter: none; -webkit-backdrop-filter: none; } /* Inline literal so Safari print engine renders correctly */ .doc-band { background: #0D0D0D !important; } .gradio-container { padding-bottom: 0 !important; } .disclaimer-bar { display: none; } /* Patient-safety: never split a flag or the handoff sections across a page */ .flag, .interrupt-card, .safety-panel, .skel-sec { page-break-inside: avoid; } /* Clinical print legibility (web px ≈ too small on paper) */ .doc-body p, .doc-body li { font-size: 11pt; line-height: 1.55; } .doc-body h3 { font-size: 8pt; } .doc-foot, .doc-foot-meta { font-size: 9pt; } /* Swap the interactive disclosure for its static print twin: a printed flag must still show the rule id and the patient's triggering words. */ .flag-rule { display: none; } .flag-evidence-print { display: block; } .flag-evidence-print .ev-span { font-size: 10pt; } /* Never let the reveal animation leave a half-faded card on paper. */ .handoff-card, .safety-panel, .interrupt-card { animation: none; } } /* ---------- Responsive ---------- */ @media (max-width: 900px) { .app-header { flex-direction: column; align-items: flex-start; } .privacy-pill { text-transform: none; } .agent-list { grid-template-columns: 1fr; } .doc-meta { text-align: left; } .disclaimer-bar { font-size: 11.5px; padding: 10px 12px; margin-bottom: 16px; } .doc-band .artifact { font-size: 18px; } .interrupt-band { font-size: 15px; } .step-card { padding: 16px 14px 12px !important; } } @media (max-width: 560px) { .disclaimer-bar { display: block; } .disclaimer-kicker { display: inline-block; margin-bottom: 7px; } .agent-dashboard-head { flex-direction: column; } .workflow-route { align-self: flex-start; } .agent-row { align-items: flex-start; } .agent-status { min-width: 58px; } } /* ---------- Bilingual side-by-side (the bilingual money shot) ---------- */ .bilingual-wrap { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; align-items: start; } @media (max-width: 900px) { .bilingual-wrap { grid-template-columns: 1fr; } } @media print { /* One card per printed page; never squeeze two columns onto A4 */ .bilingual-wrap { display: block; } .bilingual-wrap .handoff-card.arabic { page-break-before: always; margin-top: 14px; } } /* ---------- Mobile layout: stack the input/output columns ---------- */ @media (max-width: 768px) { /* Gradio's default column min-width (320px) cannot fit twice on a phone — force the two top-level columns to stack instead of colliding. */ .gradio-container .row > .column, .gradio-container .row > [class*="column"] { min-width: 100% !important; flex: 1 1 100% !important; } /* 44px minimum touch targets on the primary demo path */ .example-chip { min-height: 44px !important; } .no-print button { min-height: 44px !important; } .rail-chip { padding: 9px 14px; } .guide-identity { align-items: flex-start; } .guide-stage { white-space: normal; text-align: right; max-width: 42%; } .odipara-chip { font-size: 10px; } }