/* ============================================================================ AI-Driven IEP Generator — "Vitals" Clinical-SaaS theme ---------------------------------------------------------------------------- Direction: calm medical teal/slate · top bar + left sidebar nav · progress stepper · dense EHR cards · Lora serif for the generated IEP document. Architecture ------------ 1. TOKENS — one set of --clinic-* custom properties. Light values on :root; dark values under .dark (Gradio toggles .dark from the OS preference, so dark mode "just follows the system"). 2. GRADIO BRIDGE — map Gradio's internal theme variables onto our tokens for BOTH light and dark, so framework-injected chrome follows. 3. RESETS — strip every structural wrapper to transparent; .clinic-card is the ONLY element allowed a visible surface (no bleed). 4. COMPONENTS — shell (top bar + sidebar) · stepper · cards · fields · required pill · chips · sliders · floating CTA · IEP doc. Because every component reads from --clinic-* tokens, flipping the token block under .dark re-themes the whole app with no per-component dark rules. ============================================================================ */ /* ============================================================ 1 · DESIGN TOKENS ============================================================ */ :root { /* type */ --clinic-font-ui: 'Plus Jakarta Sans', system-ui, -apple-system, 'Segoe UI', sans-serif; --clinic-font-doc: 'Lora', Georgia, 'Times New Roman', serif; --clinic-font-mono: 'JetBrains Mono', 'Fira Code', ui-monospace, monospace; /* surfaces / ink */ --clinic-bg: #eef3f4; --clinic-surface: #ffffff; --clinic-surface-2: #f3f7f7; --clinic-border: #dde7e8; --clinic-border-strong: #cad9da; --clinic-text: #18272d; --clinic-text-dim: #5c7079; --clinic-faint: #8aa0a8; /* teal accent ramp */ --clinic-accent: #0f766e; --clinic-accent-2: #0891b2; --clinic-accent-strong: #115e59; --clinic-accent-soft: #e6f4f2; --clinic-accent-ink: #134e4a; --clinic-ring: rgba(15, 118, 110, 0.16); /* status */ --clinic-good: #0d9488; --clinic-good-soft: #e6f4f2; --clinic-warn: #b45309; --clinic-warn-soft: #fef3e2; /* geometry */ --clinic-radius: 0px; --clinic-radius-sm: 0px; --clinic-radius-field: 0px; --clinic-pad: 20px; --clinic-gap: 14px; --clinic-field-pad-y: 10px; /* elevation */ --clinic-shadow: 0 1px 3px rgba(15, 39, 45, .05), 0 1px 2px rgba(15, 39, 45, .03); --clinic-shadow-md: 0 10px 28px -12px rgba(15, 39, 45, .18); --clinic-shadow-cta: 0 12px 26px -8px rgba(15, 118, 110, .5); --clinic-label-size: .78rem; /* Force light — no sidebar needed now that tabs are top-nav */ color-scheme: light; } /* ============================================================ 2 · GRADIO VARIABLE BRIDGE Map Gradio's internal theme variables onto our tokens for BOTH light and dark, so framework chrome can never out-vote us. ============================================================ */ /* Neutralise Gradio's automatic dark-class — always render as light */ html.dark, .dark { color-scheme: light !important; } /* ============================================================ 2 · GRADIO VARIABLE BRIDGE ============================================================ */ :root, .gradio-container { --body-background-fill: var(--clinic-bg) !important; --background-fill-primary: var(--clinic-surface) !important; --background-fill-secondary: var(--clinic-surface) !important; --border-color-primary: var(--clinic-border) !important; --border-color-accent: var(--clinic-accent) !important; --border-color-accent-subdued: var(--clinic-accent-soft) !important; --block-background-fill: transparent !important; --block-border-width: 0px !important; --block-border-color: transparent !important; --block-shadow: none !important; --block-label-background-fill: transparent !important; --block-label-border-width: 0px !important; --block-label-text-color: var(--clinic-text-dim) !important; --block-title-background-fill: transparent !important; --block-title-text-color: var(--clinic-text) !important; --body-text-color: var(--clinic-text) !important; --body-text-color-subdued: var(--clinic-text-dim) !important; --input-background-fill: var(--clinic-surface) !important; --input-border-color: var(--clinic-border-strong) !important; --input-placeholder-color: var(--clinic-faint) !important; --checkbox-background-color: var(--clinic-surface) !important; --checkbox-border-color: var(--clinic-border-strong) !important; --checkbox-label-background-fill: var(--clinic-surface) !important; --checkbox-label-border-color: var(--clinic-border-strong) !important; --checkbox-label-text-color: var(--clinic-text-dim) !important; --checkbox-background-color-selected: var(--clinic-accent) !important; --checkbox-border-color-selected: var(--clinic-accent) !important; --checkbox-label-background-fill-selected: var(--clinic-accent) !important; --checkbox-label-text-color-selected: #ffffff !important; --panel-background-fill: var(--clinic-surface) !important; --panel-border-color: var(--clinic-border) !important; --slider-color: var(--clinic-accent) !important; --color-accent: var(--clinic-accent) !important; --color-accent-soft: var(--clinic-accent-soft) !important; --link-text-color: var(--clinic-accent) !important; } /* ============================================================ 3 · GLOBAL CANVAS + STRUCTURAL RESETS (bulletproof, no bleed) ============================================================ */ html, body, html body .gradio-container, html body .gradio-container .main, gradio-app, html body gradio-app { background: var(--clinic-bg) !important; color: var(--clinic-text) !important; font-family: var(--clinic-font-ui) !important; } .gradio-container { max-width: 1320px !important; margin: 0 auto !important; } * { scrollbar-width: thin; scrollbar-color: var(--clinic-border-strong) transparent; } *::-webkit-scrollbar { width: 9px; height: 9px; } *::-webkit-scrollbar-track { background: transparent; } *::-webkit-scrollbar-thumb { background: var(--clinic-border-strong); border-radius: 5px; border: 2px solid var(--clinic-bg); } /* Strip all chrome from structural wrappers — only .clinic-card is visible */ .gradio-container .block, .gradio-container .form, .gradio-container .gr-group, .gradio-container .gr-panel, .gradio-container .gr-box, .gradio-container fieldset, .gradio-container .prose, .gradio-container .tabitem, .gradio-container .padded, .gradio-container > div { background: transparent !important; border: none !important; box-shadow: none !important; color: var(--clinic-text) !important; } .gradio-container .form > .block, .gradio-container .gr-group > .form { padding: 0 !important; } .gradio-container .prose, .gradio-container .prose * { color: var(--clinic-text) !important; } /* NUCLEAR — .clinic-card is the only allowed visible surface */ html body .gradio-container .clinic-card, html body .gradio-container div.clinic-card, html body .gradio-container .clinic-card.block, html body .gradio-container .clinic-card.gr-group, html body .gradio-container .clinic-card.gr-panel { background: var(--clinic-surface) !important; background-image: none !important; border: 1px solid var(--clinic-border) !important; border-radius: var(--clinic-radius) !important; padding: var(--clinic-pad) !important; margin-bottom: var(--clinic-gap) !important; box-shadow: var(--clinic-shadow) !important; } html body .gradio-container .clinic-card *:not(input):not(textarea):not(select):not(button):not(label):not(.required-badge):not(.cta-shine) { background-color: transparent !important; background-image: none !important; } /* labels are excluded above so the pill rules own their fill; force the unselected/selected states explicitly to beat any residual reset weight */ html body .gradio-container .clinic-card .wrap label { background-color: var(--clinic-surface) !important; } html body .gradio-container .clinic-card .wrap label:has(input:checked) { background-color: var(--clinic-accent) !important; } html body .gradio-container .clinic-card input[type="text"], html body .gradio-container .clinic-card input[type="number"], html body .gradio-container .clinic-card textarea, html body .gradio-container .clinic-card select { background-color: var(--clinic-surface) !important; } html body .gradio-container .clinic-card .wrap label:has(input:checked) { background-color: var(--clinic-accent) !important; } /* ============================================================ 4 · APP SHELL — horizontal brand bar + top-nav pill tabs (Sidebar relay removed — top nav works reliably across all Gradio versions and viewport sizes) ============================================================ */ /* brand bar */ #brand-header { background: var(--clinic-surface) !important; border: 1px solid var(--clinic-border) !important; border-radius: var(--clinic-radius) !important; padding: 14px 22px !important; margin-bottom: var(--clinic-gap) !important; box-shadow: var(--clinic-shadow) !important; } #brand-header .html-container, #brand-header > div { padding: 0 !important; } #brand-header .brand-inner { display: flex; align-items: center; gap: 13px; } #brand-header .brand-mark { width: 38px; height: 38px; border-radius: 11px; flex: none; background: linear-gradient(135deg, var(--clinic-accent-2), var(--clinic-accent)); display: grid; place-items: center; color: #fff; font-size: 1.2rem; font-weight: 800; box-shadow: 0 6px 16px -6px var(--clinic-ring); } #brand-header .brand-text b { display: block; font-size: 1.1rem; font-weight: 800; letter-spacing: -.02em; color: var(--clinic-text); } #brand-header .brand-text span { display: block; font-size: .78rem; color: var(--clinic-text-dim); font-weight: 500; margin-top: 2px; } #brand-header .brand-local { margin-left: auto; display: inline-flex; align-items: center; gap: 6px; font-size: .7rem; font-weight: 700; color: var(--clinic-good); background: var(--clinic-good-soft); border: 1px solid color-mix(in srgb, var(--clinic-good) 30%, transparent); border-radius: 999px; padding: 6px 14px; } #brand-header .brand-local::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: var(--clinic-good); box-shadow: 0 0 0 3px color-mix(in srgb, var(--clinic-good) 22%, transparent); } /* horizontal pill tab nav */ .gradio-container .tabs > .tab-nav { display: flex !important; flex-direction: row !important; flex-wrap: wrap !important; gap: 4px !important; background: var(--clinic-surface) !important; border: 1px solid var(--clinic-border) !important; border-radius: var(--clinic-radius) !important; padding: 6px !important; margin-bottom: var(--clinic-gap) !important; box-shadow: var(--clinic-shadow) !important; } .gradio-container .tabs > .tabitem { padding: 0 !important; } /* tab buttons */ .gradio-container button[role="tab"] { color: var(--clinic-text-dim) !important; font-weight: 600 !important; font-size: .86rem !important; border: 1px solid transparent !important; border-radius: 0px !important; padding: 9px 18px !important; white-space: nowrap !important; transition: background .15s ease, color .15s ease !important; } .gradio-container button[role="tab"]:hover { background: var(--clinic-surface-2) !important; color: var(--clinic-text) !important; } .gradio-container button[role="tab"][aria-selected="true"] { color: var(--clinic-accent) !important; background: var(--clinic-accent-soft) !important; border-color: color-mix(in srgb, var(--clinic-accent) 20%, transparent) !important; box-shadow: inset 0 -2.5px 0 var(--clinic-accent) !important; } /* ============================================================ 4c · PROGRESS STEPPER (gr.HTML at top of Assessment tab) ============================================================ */ #iep-stepper { display: flex; align-items: center; background: var(--clinic-surface); border: 1px solid var(--clinic-border); border-radius: var(--clinic-radius); padding: 13px 20px; margin-bottom: var(--clinic-gap); box-shadow: var(--clinic-shadow); } #iep-stepper .step { display: flex; align-items: center; gap: 9px; font-size: .78rem; font-weight: 600; color: var(--clinic-text-dim); white-space: nowrap; } #iep-stepper .step .num { width: 22px; height: 22px; border-radius: 50%; display: grid; place-items: center; font-size: .72rem; font-weight: 700; background: var(--clinic-surface-2); border: 1.5px solid var(--clinic-border-strong); color: var(--clinic-text-dim); } #iep-stepper .step.on { color: var(--clinic-text); } #iep-stepper .step.on .num { background: var(--clinic-accent); border-color: var(--clinic-accent); color: #fff; } #iep-stepper .step.done .num { background: var(--clinic-good); border-color: var(--clinic-good); color: #fff; } #iep-stepper .line { flex: 1; height: 1.5px; background: var(--clinic-border); margin: 0 14px; } /* ============================================================ 5 · CARDS (dense EHR) — left teal rule on titles ============================================================ */ .clinic-card-title { font-size: .98rem !important; font-weight: 700 !important; letter-spacing: -.01em; color: var(--clinic-text) !important; margin: 0 0 14px !important; padding-left: 11px; border-left: 3px solid var(--clinic-accent); display: flex; align-items: center; gap: 8px; line-height: 1.3; } .clinic-card-sub { margin-left: auto; font-size: .74rem; color: var(--clinic-text-dim); font-weight: 500; } .gradio-container h3 { color: var(--clinic-text) !important; font-weight: 700 !important; font-size: .9rem !important; margin: 4px 0 10px !important; } /* required pill */ .required-badge { display: inline-block; background: var(--clinic-accent-soft); color: var(--clinic-accent); border: 1px solid color-mix(in srgb, var(--clinic-accent) 30%, transparent); border-radius: 999px; padding: 2px 9px; font-size: .6rem; font-weight: 800; letter-spacing: .07em; text-transform: uppercase; margin-left: 8px; vertical-align: middle; line-height: 1.5; } /* ============================================================ 6 · FIELDS — compact pill inputs ============================================================ */ .gradio-container input[type="text"], .gradio-container textarea, .gradio-container select, .gradio-container .multimodal-textbox, .gradio-container [data-testid="number"] input[type="number"] { background: var(--clinic-surface) !important; border: 1.5px solid var(--clinic-border-strong) !important; border-radius: var(--clinic-radius-field) !important; color: var(--clinic-text) !important; padding: var(--clinic-field-pad-y) 13px !important; font-size: .88rem !important; font-family: var(--clinic-font-ui) !important; transition: border-color .15s ease, box-shadow .15s ease !important; } .gradio-container input::placeholder, .gradio-container textarea::placeholder { color: var(--clinic-faint) !important; font-weight: 400 !important; } .gradio-container textarea { min-height: 84px !important; width: 100% !important; line-height: 1.55 !important; resize: vertical !important; } /* single-line textboxes (lines=1) stay short */ .gradio-container textarea[rows="1"] { min-height: 44px !important; } .gradio-container input[type="text"]:focus, .gradio-container input[type="number"]:focus, .gradio-container textarea:focus, .gradio-container select:focus { border-color: var(--clinic-accent) !important; box-shadow: 0 0 0 3px var(--clinic-ring) !important; outline: none !important; } .gradio-container label > span:first-child, .gradio-container .gr-text-input label span { color: var(--clinic-text) !important; font-size: var(--clinic-label-size) !important; font-weight: 600 !important; margin-bottom: 5px !important; } /* sliders — compact numeric readout */ .gradio-container .gr-slider, .gradio-container [data-testid="slider"] { padding-top: 4px !important; } .gradio-container .gr-slider input[type="number"], .gradio-container [data-testid="slider"] input[type="number"] { background: var(--clinic-surface) !important; border: 1.5px solid var(--clinic-border-strong) !important; border-radius: 7px !important; padding: 4px 8px !important; font-size: .82rem !important; width: 62px !important; min-width: 54px !important; text-align: center !important; } .gradio-container .gr-slider label, .gradio-container [data-testid="slider"] label { display: flex !important; flex-wrap: wrap; align-items: flex-start; gap: 8px; } input[type="range"] { accent-color: var(--clinic-accent) !important; } .gradio-container .gr-slider .head, .gradio-container output { color: var(--clinic-accent) !important; font-weight: 700 !important; } /* ============================================================ 6b · LAYOUT SPACING & FIELDSET RESET (kills overlap + crowding) Gradio renders Radio/CheckboxGroup as
, which carry browser-default min-inline-size:min-content (can't shrink → they overflow into the neighbouring column) plus stray margin/padding. We zero those, then re-establish explicit flex gaps so stacked fields and side-by-side rows breathe like the approved mockup. ============================================================ */ .gradio-container fieldset, .gradio-container .clinic-card fieldset { min-inline-size: 0 !important; min-width: 0 !important; margin: 0 !important; padding: 0 !important; border: none !important; } /* vertical rhythm: every direct child block inside a card gets breathing room */ .gradio-container .clinic-card > .block + .block, .gradio-container .clinic-card .column > .block + .block, .gradio-container .clinic-card .form + .block, .gradio-container .clinic-card .block + .form, .gradio-container .clinic-card .row + .row, .gradio-container .clinic-card .row + .block, .gradio-container .clinic-card .block + .row { margin-top: 13px !important; } /* side-by-side rows: explicit column gap + top alignment + shrinkable children */ .gradio-container .clinic-card .row, .gradio-container .clinic-card [class*="row"] { display: flex !important; flex-wrap: wrap !important; gap: 14px !important; align-items: flex-start !important; } .gradio-container .clinic-card .row > *, .gradio-container .clinic-card .row > .block { min-width: 0 !important; flex: 1 1 0 !important; } /* label gets consistent space below it before its control */ .gradio-container .clinic-card label > span:first-child, .gradio-container .clinic-card .block > label > span:first-child { display: inline-block !important; margin-bottom: 6px !important; } /* ============================================================ 7 · CHECKBOX / RADIO — solid teal pill selectors ============================================================ */ .gradio-container .wrap.svelte-1p9xokt, .gradio-container fieldset .wrap { gap: 7px !important; } .gradio-container .wrap label, .gradio-container fieldset label { border: 1.5px solid var(--clinic-border-strong) !important; border-radius: 999px !important; background: var(--clinic-surface) !important; color: var(--clinic-text-dim) !important; padding: 7px 16px !important; font-size: .82rem !important; font-weight: 600 !important; transition: background .15s ease, border-color .15s ease, color .15s ease !important; cursor: pointer !important; } .gradio-container .wrap label span, .gradio-container fieldset label span { color: inherit !important; } .gradio-container .wrap label:hover, .gradio-container fieldset label:hover { border-color: var(--clinic-accent) !important; color: var(--clinic-accent) !important; } .gradio-container .wrap label.selected, .gradio-container .wrap label:has(input:checked), .gradio-container fieldset label:has(input:checked) { background: var(--clinic-accent) !important; border-color: var(--clinic-accent) !important; color: #ffffff !important; box-shadow: 0 2px 6px -1px var(--clinic-ring) !important; } .gradio-container .wrap label input[type="checkbox"], .gradio-container .wrap label input[type="radio"] { display: none !important; } /* ============================================================ 8 · FLOATING CTA — isolated, frosted sticky action bar ============================================================ */ #cta-row { position: sticky; bottom: 0; z-index: 30; margin-top: var(--clinic-gap); padding: 14px; border-radius: calc(var(--clinic-radius) + 2px); background: color-mix(in srgb, var(--clinic-surface) 80%, transparent) !important; backdrop-filter: blur(10px); border: 1px solid var(--clinic-border) !important; box-shadow: var(--clinic-shadow-md); display: flex; gap: 14px; align-items: center; } #generate-btn { background: linear-gradient(135deg, var(--clinic-accent-2) 0%, var(--clinic-accent) 100%) !important; border: none !important; border-radius: 13px !important; color: #fff !important; font-weight: 800 !important; font-size: 1rem !important; letter-spacing: .04em; text-transform: uppercase; padding: 16px 0 !important; box-shadow: var(--clinic-shadow-cta) !important; transition: transform .18s cubic-bezier(.2,.7,.3,1), box-shadow .18s ease, filter .18s ease !important; cursor: pointer !important; position: relative; overflow: hidden; } #generate-btn:hover { transform: translateY(-2px) scale(1.01) !important; box-shadow: 0 18px 36px -8px color-mix(in srgb, var(--clinic-accent) 55%, transparent) !important; filter: brightness(1.07); } #generate-btn:active { transform: translateY(-1px) scale(.995) !important; } /* sheen sweep on hover */ #generate-btn::after { content: ""; position: absolute; inset: 0; background: linear-gradient(120deg, transparent 28%, rgba(255,255,255,.30) 50%, transparent 72%); transform: translateX(-130%); transition: transform .6s ease; } #generate-btn:hover::after { transform: translateX(130%); } /* status pill */ #status-pill textarea, #status-pill input { text-align: center !important; font-weight: 700 !important; font-size: .82rem !important; background: var(--clinic-accent-soft) !important; border: 1px solid color-mix(in srgb, var(--clinic-accent) 24%, transparent) !important; color: var(--clinic-accent) !important; border-radius: 999px !important; } /* secondary buttons */ .gradio-container button.secondary, #load-btn, #export-btn, #search-btn { background: var(--clinic-surface) !important; border: 1.5px solid var(--clinic-border-strong) !important; color: var(--clinic-text) !important; border-radius: var(--clinic-radius-sm) !important; font-weight: 600 !important; transition: all .15s ease !important; } .gradio-container button.secondary:hover, #load-btn:hover, #export-btn:hover, #search-btn:hover { border-color: var(--clinic-accent) !important; color: var(--clinic-accent) !important; background: var(--clinic-accent-soft) !important; } /* ============================================================ 9 · IEP DOCUMENT VIEWER — Lora serif body (editorial report) ============================================================ */ #iep-document-wrap { background: var(--clinic-surface); border: 1px solid var(--clinic-border); border-radius: var(--clinic-radius); box-shadow: var(--clinic-shadow-md); } #iep-document { padding: 38px 44px !important; min-height: 50vh; max-height: 76vh; overflow-y: auto; font-family: var(--clinic-font-doc) !important; font-size: 1.02rem; line-height: 1.74; color: var(--clinic-text); } #iep-document h1 { font-family: var(--clinic-font-doc); font-size: 1.7rem; font-weight: 700; color: var(--clinic-accent-ink); margin-top: 0; letter-spacing: -.01em; border-bottom: 2px solid var(--clinic-accent-soft); padding-bottom: 12px; } #iep-document h2 { font-family: var(--clinic-font-doc); font-size: 1.22rem; font-weight: 700; color: var(--clinic-accent); margin-top: 26px; } #iep-document h3 { font-family: var(--clinic-font-ui); font-size: .82rem; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--clinic-text-dim); margin: 18px 0 6px; } #iep-document p { margin: 0 0 12px; } #iep-document strong { color: var(--clinic-accent-ink); font-weight: 700; } #iep-document ul { padding-left: 4px; list-style: none; } #iep-document li { position: relative; padding-left: 22px; margin-bottom: 7px; } #iep-document li::before { content: ""; position: absolute; left: 4px; top: .62em; width: 6px; height: 6px; border-radius: 50%; background: var(--clinic-accent-2); } #iep-document table { border-collapse: collapse; width: 100%; font-family: var(--clinic-font-ui); font-size: .85rem; } #iep-document th, #iep-document td { border: 1px solid var(--clinic-border); padding: 8px 11px; } #iep-document th { background: var(--clinic-accent-soft); color: var(--clinic-accent-ink); } /* editable markdown textarea */ #iep-editor textarea { background: var(--clinic-surface) !important; border: 1.5px solid var(--clinic-border-strong) !important; border-radius: var(--clinic-radius) !important; color: var(--clinic-text) !important; font-family: var(--clinic-font-mono) !important; font-size: .86rem !important; line-height: 1.65 !important; padding: 22px 26px !important; min-height: 220px !important; max-height: 38vh !important; overflow-y: auto !important; resize: vertical !important; } /* about-tab markdown tables */ .gradio-container .prose table { border: 1px solid var(--clinic-border) !important; } .gradio-container .prose th, .gradio-container .prose td { border: 1px solid var(--clinic-border) !important; padding: 6px 10px !important; } .gradio-container .prose th { background: var(--clinic-accent-soft) !important; color: var(--clinic-accent-ink) !important; } /* ============================================================ 10 · RESPONSIVE ============================================================ */ @media (max-width: 720px) { .gradio-container .tabs > .tab-nav { overflow-x: auto !important; flex-wrap: nowrap !important; } #brand-header .brand-local { display: none !important; } }