InsuranceBot / frontend /src /app /globals.css
rohitsar567's picture
#33: add "?" help affordance to every policy-calculation control
deefe3a
Raw
History Blame Contribute Delete
41 kB
@import "tailwindcss";
:root {
--background: #fafaf9;
--foreground: #1c1917;
--primary: #0f766e; /* deep teal β€” financial-services serious */
--primary-foreground: #ffffff;
--muted: #f5f5f4;
--muted-foreground: #57534e;
--border: #e7e5e4;
--card: #ffffff;
--accent: #fef3c7; /* warm amber for highlights */
--error: #dc2626;
}
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground);
--color-muted: var(--muted);
--color-muted-foreground: var(--muted-foreground);
--color-border: var(--border);
--color-card: var(--card);
--color-accent: var(--accent);
--color-error: var(--error);
--font-sans: var(--font-body), ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
--font-serif: var(--font-display), ui-serif, Georgia, "Times New Roman", serif;
--font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Monaco, Consolas, monospace;
}
@media (prefers-color-scheme: dark) {
:root {
--background: #0c0a09;
--foreground: #fafaf9;
--muted: #1c1917;
--muted-foreground: #a8a29e;
--border: #292524;
--card: #1c1917;
--primary: #2dd4bf;
--primary-foreground: #0a0a0a;
--accent: #422006;
}
}
body {
background: var(--background);
color: var(--foreground);
font-family: var(--font-sans);
-webkit-font-smoothing: antialiased;
}
/* utility β€” scrollbar styling */
.scrollbar-thin::-webkit-scrollbar { width: 8px; height: 8px; }
.scrollbar-thin::-webkit-scrollbar-thumb { background: var(--border); border-radius: 4px; }
.scrollbar-thin::-webkit-scrollbar-thumb:hover { background: var(--muted-foreground); }
.scrollbar-thin::-webkit-scrollbar-track { background: transparent; }
/* fade-in for chat messages */
@keyframes fade-up {
from { opacity: 0; transform: translateY(6px); }
to { opacity: 1; transform: translateY(0); }
}
.animate-fade-up { animation: fade-up 0.3s ease-out; }
/* pulse for recording indicator */
@keyframes record-pulse {
0%, 100% { box-shadow: 0 0 0 0 rgba(220, 38, 38, 0.7); }
50% { box-shadow: 0 0 0 12px rgba(220, 38, 38, 0); }
}
.animate-record-pulse { animation: record-pulse 1.4s infinite; }
/* Header chip-tile: locks every chip on a uniform min height + clean
* focus ring + keyboard accessibility. Two-line layout (kicker + sub) is
* guaranteed to align across chips even when one chip has more text. */
.chip-tile {
min-height: 52px;
display: inline-flex;
align-items: stretch;
}
.chip-tile:focus-visible {
outline: 2px solid var(--primary);
outline-offset: 2px;
}
/* ────────────────────────────────────────────────────────────────────
* PREMIUM LANDING (EmptyState) β€” editorial-fintech redesign
* Design direction: warm, trustworthy, magazine-grade. Fraunces display
* serif + Plus Jakarta body, layered soft depth, a faint grain + grid
* hero texture, a numbered "journey" spine, and one orchestrated
* page-load reveal. No generic AI card-grid look.
* ──────────────────────────────────────────────────────────────────── */
/* Display serif β€” applied to the hero headline + section titles. The
* optical-size + soft axes give large type a warm, set-by-hand feel. */
.font-display {
font-family: var(--font-serif);
font-optical-sizing: auto;
font-variation-settings: "SOFT" 40, "WONK" 0;
letter-spacing: -0.012em;
}
/* The landing root sets the editorial body face + a calm vertical wash
* (deep at the very top behind the hero, fading to paper) and a barely
* perceptible film grain so flat fills never look plastic. */
.landing-root {
font-family: var(--font-sans);
position: relative;
background:
radial-gradient(120% 60% at 50% -10%,
color-mix(in srgb, var(--primary) 11%, transparent) 0%,
transparent 60%),
linear-gradient(180deg,
color-mix(in srgb, var(--primary) 4%, var(--background)) 0%,
var(--background) 40%);
}
.landing-root::before {
content: "";
position: absolute;
inset: 0;
pointer-events: none;
opacity: 0.5;
mix-blend-mode: multiply;
/* tiny SVG fractal-noise grain, base64-free via data URI */
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='0.32'/%3E%3C/svg%3E");
}
/* HERO β€” generous, asymmetric-feeling slab with a layered teal glow,
* an inner hairline, and a faint engineering grid that signals "built,
* not marketing fluff". */
.hero-card {
position: relative;
isolation: isolate;
border-radius: 28px;
border: 1px solid color-mix(in srgb, var(--primary) 16%, var(--border));
background:
radial-gradient(90% 120% at 18% 0%,
color-mix(in srgb, var(--primary) 12%, var(--card)) 0%,
var(--card) 55%),
var(--card);
box-shadow:
0 1px 0 color-mix(in srgb, var(--primary) 14%, transparent) inset,
0 1px 2px color-mix(in srgb, var(--foreground) 5%, transparent),
0 24px 60px -30px color-mix(in srgb, var(--primary) 42%, transparent);
}
.hero-card::after {
content: "";
position: absolute;
inset: 0;
z-index: -1;
border-radius: inherit;
pointer-events: none;
opacity: 0.5;
-webkit-mask-image: radial-gradient(70% 90% at 22% 8%, #000 0%, transparent 70%);
mask-image: radial-gradient(70% 90% at 22% 8%, #000 0%, transparent 70%);
background-image:
linear-gradient(color-mix(in srgb, var(--primary) 12%, transparent) 1px, transparent 1px),
linear-gradient(90deg, color-mix(in srgb, var(--primary) 12%, transparent) 1px, transparent 1px);
background-size: 30px 30px;
}
/* Eyebrow / kicker pill β€” small caps, brand-tinted, with a live dot. */
.kicker {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 6px 13px 6px 11px;
border-radius: 999px;
font-size: 11.5px;
font-weight: 600;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--primary);
background: color-mix(in srgb, var(--primary) 9%, var(--card));
border: 1px solid color-mix(in srgb, var(--primary) 22%, var(--border));
box-shadow: 0 1px 1px color-mix(in srgb, var(--foreground) 4%, transparent);
}
.kicker .dot {
width: 6px;
height: 6px;
border-radius: 999px;
background: var(--primary);
box-shadow: 0 0 0 0 color-mix(in srgb, var(--primary) 70%, transparent);
animation: kicker-pulse 2.6s ease-out infinite;
}
@keyframes kicker-pulse {
0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--primary) 55%, transparent); }
70% { box-shadow: 0 0 0 7px color-mix(in srgb, var(--primary) 0%, transparent); }
100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--primary) 0%, transparent); }
}
/* SECTION SHELL β€” quieter than the hero: clean paper, hairline border,
* a soft long shadow so sections feel lifted off the page wash. */
.section-card {
border-radius: 22px;
border: 1px solid var(--border);
background: var(--card);
box-shadow:
0 1px 2px color-mix(in srgb, var(--foreground) 4%, transparent),
0 18px 48px -34px color-mix(in srgb, var(--foreground) 30%, transparent);
}
/* Section header: a hairline rule grows from the icon so each section
* reads as a titled chapter rather than a stacked box. */
.section-rule {
flex: 1;
height: 1px;
background: linear-gradient(90deg,
color-mix(in srgb, var(--primary) 30%, var(--border)) 0%,
var(--border) 30%,
transparent 100%);
}
.section-num {
font-family: var(--font-serif);
font-size: 13px;
font-weight: 600;
color: color-mix(in srgb, var(--primary) 70%, var(--muted-foreground));
letter-spacing: 0.02em;
}
/* STEP β€” the three "how it works" cards sit on a shared horizontal spine
* (a connecting line through the numbered medallions) so they read as one
* journey, not three disconnected tiles. */
.step-grid { position: relative; }
@media (min-width: 640px) {
.step-grid::before {
content: "";
position: absolute;
top: 50px; /* aligns to the centre of the 36px medallion + pt */
left: 16%;
right: 16%;
height: 2px;
background: repeating-linear-gradient(90deg,
color-mix(in srgb, var(--primary) 34%, var(--border)) 0 7px,
transparent 7px 14px);
z-index: 0;
}
}
.step-card {
position: relative;
z-index: 1;
border-radius: 18px;
border: 1px solid var(--border);
background:
linear-gradient(180deg,
color-mix(in srgb, var(--primary) 5%, var(--card)) 0%,
var(--card) 42%);
transition: transform .22s cubic-bezier(.2,.7,.3,1),
box-shadow .22s ease, border-color .22s ease;
}
.step-card:hover {
transform: translateY(-4px);
border-color: color-mix(in srgb, var(--primary) 34%, var(--border));
box-shadow:
0 1px 2px color-mix(in srgb, var(--foreground) 4%, transparent),
0 22px 44px -26px color-mix(in srgb, var(--primary) 46%, transparent);
}
.step-medallion {
width: 44px;
height: 44px;
border-radius: 14px;
display: flex;
align-items: center;
justify-content: center;
font-family: var(--font-serif);
font-size: 18px;
font-weight: 600;
color: var(--primary-foreground);
background: linear-gradient(150deg,
color-mix(in srgb, var(--primary) 92%, white) 0%,
var(--primary) 55%,
color-mix(in srgb, var(--primary) 78%, black) 100%);
box-shadow:
0 2px 6px color-mix(in srgb, var(--primary) 40%, transparent),
0 0 0 5px color-mix(in srgb, var(--primary) 10%, transparent);
}
/* Tight one-line fact bullets used inside step / callout bodies. */
.fact-list { display: flex; flex-direction: column; gap: 9px; }
.fact-list li {
display: flex;
align-items: flex-start;
gap: 9px;
font-size: 13.5px;
line-height: 1.45;
color: var(--muted-foreground);
}
.fact-list li .tick {
flex: none;
margin-top: 1px;
color: var(--primary);
}
.fact-list li strong {
color: var(--foreground);
font-weight: 600;
}
/* INPUT-MODE rows β€” refined list with a left accent rail on hover. */
.mode-row {
position: relative;
border-radius: 16px;
border: 1px solid var(--border);
background: var(--card);
overflow: hidden;
transition: transform .2s cubic-bezier(.2,.7,.3,1),
box-shadow .2s ease, border-color .2s ease;
}
.mode-row::before {
content: "";
position: absolute;
left: 0; top: 0; bottom: 0;
width: 3px;
background: var(--primary);
transform: scaleY(0);
transform-origin: top;
transition: transform .22s ease;
}
.mode-row:hover {
transform: translateY(-2px);
border-color: color-mix(in srgb, var(--primary) 30%, var(--border));
box-shadow: 0 16px 34px -24px color-mix(in srgb, var(--primary) 40%, transparent);
}
.mode-row:hover::before { transform: scaleY(1); }
.mode-glyph {
background: linear-gradient(150deg,
color-mix(in srgb, var(--primary) 14%, var(--card)) 0%,
color-mix(in srgb, var(--primary) 6%, var(--card)) 100%);
border: 1px solid color-mix(in srgb, var(--primary) 18%, var(--border));
color: var(--primary);
}
/* CALLOUT cards β€” keep the amber trust card distinct, lift both. */
.callout-card {
border-radius: 18px;
transition: transform .2s ease, box-shadow .2s ease;
}
.callout-card:hover {
transform: translateY(-2px);
box-shadow: 0 18px 40px -28px color-mix(in srgb, var(--foreground) 40%, transparent);
}
/* Orchestrated page-load reveal β€” staggered, calm, runs once. */
@keyframes reveal-up {
from { opacity: 0; transform: translateY(16px); }
to { opacity: 1; transform: translateY(0); }
}
.reveal {
opacity: 0;
animation: reveal-up .6s cubic-bezier(.2,.7,.3,1) forwards;
}
.reveal-1 { animation-delay: .02s; }
.reveal-2 { animation-delay: .12s; }
.reveal-3 { animation-delay: .22s; }
.reveal-4 { animation-delay: .32s; }
/* ────────────────────────────────────────────────────────────────────
* PREMIUM APP SURFACES β€” profile builder Β· chat Β· cited cards Β·
* marketplace. Same editorial-fintech system as the landing: Fraunces
* display serif for section titles, Plus Jakarta body, hairline
* borders, soft long shadows, brand-teal accents, one calm reveal.
* ──────────────────────────────────────────────────────────────────── */
/* Slide-over panel shell (profile / marketplace). Quiet paper, a faint
* top teal wash so it reads as a lifted "sheet", not a flat overlay. */
.app-panel {
position: relative;
font-family: var(--font-sans);
background:
radial-gradient(110% 50% at 50% -8%,
color-mix(in srgb, var(--primary) 7%, transparent) 0%,
transparent 55%),
var(--background);
}
/* Chaptered panel header β€” kicker + serif title, mirrors .section-num. */
.panel-kicker {
display: inline-flex;
align-items: center;
gap: 7px;
font-size: 10.5px;
font-weight: 600;
letter-spacing: 0.14em;
text-transform: uppercase;
color: color-mix(in srgb, var(--primary) 78%, var(--muted-foreground));
}
.panel-kicker .dot {
width: 5px;
height: 5px;
border-radius: 999px;
background: var(--primary);
}
.panel-title {
font-family: var(--font-serif);
font-optical-sizing: auto;
font-variation-settings: "SOFT" 40, "WONK" 0;
letter-spacing: -0.012em;
font-weight: 600;
}
/* A profile "fieldset" β€” one numbered chapter of the form. Hairline
* card, soft long shadow, a serif step index in a tinted medallion so
* the form reads as a guided journey, not a wall of inputs. */
.field-group {
position: relative;
border-radius: 18px;
border: 1px solid var(--border);
background:
linear-gradient(180deg,
color-mix(in srgb, var(--primary) 4%, var(--card)) 0%,
var(--card) 38%);
box-shadow:
0 1px 2px color-mix(in srgb, var(--foreground) 4%, transparent),
0 16px 40px -32px color-mix(in srgb, var(--foreground) 28%, transparent);
transition: border-color .22s ease, box-shadow .22s ease;
}
.field-group:focus-within {
border-color: color-mix(in srgb, var(--primary) 32%, var(--border));
box-shadow:
0 1px 2px color-mix(in srgb, var(--foreground) 4%, transparent),
0 18px 44px -28px color-mix(in srgb, var(--primary) 36%, transparent);
}
.field-medallion {
width: 30px;
height: 30px;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
font-family: var(--font-serif);
font-size: 14px;
font-weight: 600;
color: var(--primary-foreground);
background: linear-gradient(150deg,
color-mix(in srgb, var(--primary) 92%, white) 0%,
var(--primary) 55%,
color-mix(in srgb, var(--primary) 80%, black) 100%);
box-shadow:
0 2px 5px color-mix(in srgb, var(--primary) 36%, transparent),
0 0 0 4px color-mix(in srgb, var(--primary) 9%, transparent);
}
/* Selectable option pill β€” replaces the ad-hoc chip classes. Crisp
* hairline, brand fill on select, a soft press feel. */
.opt-pill {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 7px 13px;
border-radius: 999px;
border: 1px solid var(--border);
background: var(--card);
font-size: 12px;
font-weight: 500;
color: var(--foreground);
cursor: pointer;
transition: transform .15s cubic-bezier(.2,.7,.3,1),
border-color .15s ease, background .15s ease, color .15s ease,
box-shadow .15s ease;
}
.opt-pill:hover {
border-color: color-mix(in srgb, var(--primary) 40%, var(--border));
}
.opt-pill:active { transform: scale(.97); }
.opt-pill[data-on="true"] {
border-color: var(--primary);
background: var(--primary);
color: var(--primary-foreground);
box-shadow: 0 6px 16px -8px color-mix(in srgb, var(--primary) 60%, transparent);
}
.opt-pill:focus-visible {
outline: 2px solid var(--primary);
outline-offset: 2px;
}
/* Text / number field β€” single shared input look. */
.app-input {
width: 100%;
font-size: 14px;
padding: 9px 12px;
border-radius: 11px;
border: 1px solid var(--border);
background: var(--card);
color: var(--foreground);
transition: border-color .18s ease, box-shadow .18s ease;
}
.app-input::placeholder { color: var(--muted-foreground); }
.app-input:focus {
outline: none;
border-color: var(--primary);
box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary) 14%, transparent);
}
/* Brand range slider β€” themed track + thumb so it stops looking like a
* raw OS control next to the editorial type. */
.app-range {
-webkit-appearance: none;
appearance: none;
width: 100%;
background: transparent; /* track is drawn by the pseudo-elements
below β€” relying on the element bg broke
once .app-range-lg added padding +
background-clip:content-box (#58). */
outline: none;
cursor: pointer;
}
.app-range::-webkit-slider-runnable-track {
height: 6px;
border-radius: 999px;
background: color-mix(in srgb, var(--primary) 22%, var(--border));
}
.app-range::-moz-range-track {
height: 6px;
border-radius: 999px;
background: color-mix(in srgb, var(--primary) 22%, var(--border));
}
.app-range::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 18px;
height: 18px;
margin-top: -6px; /* center the 18px thumb on the 6px track */
border-radius: 999px;
background: var(--primary);
border: 3px solid var(--card);
box-shadow: 0 1px 4px color-mix(in srgb, var(--primary) 50%, transparent);
cursor: pointer;
}
.app-range::-moz-range-thumb {
width: 16px;
height: 16px;
border-radius: 999px;
background: var(--primary);
border: 3px solid var(--card);
cursor: pointer;
}
/* Conditional sub-block (parents detail) β€” a tinted inset rail. */
.subfield {
border-radius: 14px;
border: 1px solid color-mix(in srgb, var(--primary) 20%, var(--border));
background: color-mix(in srgb, var(--primary) 5%, var(--card));
}
/* Sticky save bar β€” frosted, lifted off the form. */
.save-bar {
background: color-mix(in srgb, var(--card) 86%, transparent);
-webkit-backdrop-filter: saturate(180%) blur(10px);
backdrop-filter: saturate(180%) blur(10px);
border-top: 1px solid var(--border);
}
.btn-primary {
font-weight: 600;
border-radius: 12px;
color: var(--primary-foreground);
background: linear-gradient(150deg,
color-mix(in srgb, var(--primary) 94%, white) 0%,
var(--primary) 60%);
box-shadow: 0 8px 20px -10px color-mix(in srgb, var(--primary) 60%, transparent);
transition: transform .15s ease, box-shadow .15s ease, opacity .15s ease;
}
.btn-primary:hover:not(:disabled) { transform: translateY(-1px); }
.btn-primary:disabled { opacity: .5; cursor: not-allowed; }
/* CHAT bubbles β€” the assistant reads as a calm "letter" on paper, the
* user as a brand slab. Both lifted, both with a soft tail-less radius. */
.bubble-assistant {
border-radius: 18px 18px 18px 6px;
border: 1px solid var(--border);
background:
linear-gradient(180deg,
color-mix(in srgb, var(--primary) 3.5%, var(--card)) 0%,
var(--card) 36%);
box-shadow:
0 1px 2px color-mix(in srgb, var(--foreground) 4%, transparent),
0 14px 36px -30px color-mix(in srgb, var(--foreground) 26%, transparent);
}
.bubble-user {
border-radius: 18px 18px 6px 18px;
color: var(--primary-foreground);
background: linear-gradient(150deg,
color-mix(in srgb, var(--primary) 92%, white) 0%,
var(--primary) 62%);
box-shadow: 0 10px 26px -14px color-mix(in srgb, var(--primary) 55%, transparent);
}
/* Cited-policy card β€” hairline, lifts to a teal-tinted long shadow. */
.cited-card {
border-radius: 14px;
border: 1px solid var(--border);
background: var(--card);
transition: transform .2s cubic-bezier(.2,.7,.3,1),
border-color .2s ease, box-shadow .2s ease;
}
.cited-card:hover {
transform: translateY(-2px);
border-color: color-mix(in srgb, var(--primary) 32%, var(--border));
box-shadow: 0 16px 34px -24px color-mix(in srgb, var(--primary) 42%, transparent);
}
/* Marketplace policy card β€” same lift language as the step cards. */
.policy-card {
border-radius: 16px;
border: 1px solid var(--border);
background:
linear-gradient(180deg,
color-mix(in srgb, var(--primary) 3.5%, var(--card)) 0%,
var(--card) 40%);
transition: transform .2s cubic-bezier(.2,.7,.3,1),
border-color .2s ease, box-shadow .2s ease;
}
.policy-card:hover {
transform: translateY(-3px);
border-color: color-mix(in srgb, var(--primary) 34%, var(--border));
box-shadow:
0 1px 2px color-mix(in srgb, var(--foreground) 4%, transparent),
0 22px 44px -26px color-mix(in srgb, var(--primary) 44%, transparent);
}
.policy-card[data-selected="true"] {
border-color: var(--primary);
box-shadow: 0 18px 40px -22px color-mix(in srgb, var(--primary) 50%, transparent);
}
/* Filter shell + sticky compare bar share the frosted treatment. */
.filter-shell {
border-radius: 18px;
border: 1px solid var(--border);
background: var(--card);
box-shadow: 0 1px 2px color-mix(in srgb, var(--foreground) 4%, transparent);
}
/* Honour reduced-motion preference: drop the hover-lift transition on the
* landing step / mode / callout cards for vestibular-sensitive users. */
@media (prefers-reduced-motion: reduce) {
.step-card, .mode-row, .callout-card, .chip-tile,
.field-group, .opt-pill, .cited-card, .policy-card, .btn-primary {
transition: none !important;
}
.step-card:hover, .mode-row:hover, .callout-card:hover,
.cited-card:hover, .policy-card:hover, .btn-primary:hover {
transform: none !important;
}
.reveal {
opacity: 1 !important;
animation: none !important;
}
.kicker .dot { animation: none !important; }
}
/* ────────────────────────────────────────────────────────────────────
* #44 β€” assistant markdown prose. Tight, readable defaults that inherit
* the chat bubble's type scale. Lists, bold policy names, paragraphs and
* line breaks all read cleanly instead of as a raw `**`/`1.` wall.
* ──────────────────────────────────────────────────────────────────── */
.md-body { overflow-wrap: anywhere; word-break: break-word; }
.md-body > *:first-child { margin-top: 0; }
.md-body > *:last-child { margin-bottom: 0; }
.md-body a { word-break: break-word; }
.md-body ol, .md-body ul { padding-inline-start: 1.35rem; }
.md-body li::marker { font-variant-numeric: tabular-nums; }
.md-body code { white-space: pre-wrap; word-break: break-word; }
/* #47 β€” larger continuous slider variant for the merged Profile &
* premium money fields. Bigger track + thumb so the touch target clears
* the 44px guideline on phones (the wrapper row + thumb hit-area). */
/* Padding gives the β‰₯44px touch target; the track is a pseudo-element so
* the padding does not hide it. */
.app-range-lg { padding: 13px 0; }
.app-range-lg::-webkit-slider-runnable-track { height: 8px; }
.app-range-lg::-moz-range-track { height: 8px; }
.app-range-lg::-webkit-slider-thumb {
width: 24px; height: 24px; margin-top: -8px; border-width: 4px;
}
.app-range-lg::-moz-range-thumb {
width: 22px; height: 22px; border-width: 4px;
}
.app-range:focus-visible { outline: 2px solid var(--primary); outline-offset: 4px; }
/* ────────────────────────────────────────────────────────────────────
* #49 β€” full mobile optimization. Single-column stacks, β‰₯44px tap
* targets, no horizontal overflow, mobile-safe modals / sliders /
* sticky bars, readable type. Scoped so desktop is untouched.
* ──────────────────────────────────────────────────────────────────── */
/* Hard stop on horizontal overflow anywhere in the app. */
html, body { max-width: 100%; overflow-x: hidden; }
@media (max-width: 640px) {
/* Generous tap targets for every interactive control on phones. */
.opt-pill { min-height: 40px; padding: 9px 15px; font-size: 12.5px; }
.chip-tile { min-height: 48px; }
.btn-primary { min-height: 44px; }
/* The header chip row scrolls horizontally instead of wrapping into a
* tall ragged stack β€” keeps the brand mark + chips on one tidy line a
* thumb can swipe. Hide the scrollbar; momentum scroll on iOS. */
.chip-row-scroll {
flex-wrap: nowrap;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
scrollbar-width: none;
margin-inline: -1rem;
padding-inline: 1rem;
scroll-snap-type: x proximity;
}
.chip-row-scroll::-webkit-scrollbar { display: none; }
.chip-row-scroll > * { scroll-snap-align: start; }
/* Slide-over app panels become a full-height sheet on phones (the chat
* lives above in the column flow; the panel gets the rest of the
* viewport and scrolls internally). Drops the desktop 80vh cap. */
.app-panel-mobile-full {
max-height: none !important;
min-height: 70vh;
}
/* Centered modals dock to the bottom as a full-width sheet β€” easier to
* reach one-handed, respects the home-indicator safe area. */
.modal-shell-mobile {
align-items: flex-end !important;
padding: 0 !important;
}
.modal-card-mobile {
max-width: 100% !important;
width: 100% !important;
max-height: 92dvh !important;
border-bottom-left-radius: 0 !important;
border-bottom-right-radius: 0 !important;
padding-bottom: env(safe-area-inset-bottom) !important;
}
/* Any 2-up grid inside a panel collapses to one column on phones. */
.stack-on-mobile { grid-template-columns: 1fr !important; }
/* Comparison table stays usable: allow horizontal scroll within its
* own container without blowing out the page width. */
.table-scroll-x { overflow-x: auto; -webkit-overflow-scrolling: touch; }
/* Slightly larger base type for chat prose on small screens. */
.md-body { font-size: 14.5px; line-height: 1.6; }
}
/* ─────────────────────────────────────────────────────────────────────
* POLICY SNAPSHOT (#75 + #64) β€” the decision-ordered coverage lens shared
* by the marketplace detail modal and the in-chat compare card. Grounded
* on the landing's editorial system: hairline card, soft long shadow,
* Fraunces group title, a tinted accent rail per decision group, generous
* row rhythm. One look, two surfaces.
* ───────────────────────────────────────────────────────────────────── */
.snap-stack { display: flex; flex-direction: column; gap: 12px; }
.snap-group {
position: relative;
border: 1px solid var(--border);
border-radius: 16px;
padding: 14px 16px 8px 18px;
background:
linear-gradient(180deg,
color-mix(in srgb, var(--snap-accent, var(--primary)) 6%, var(--card)) 0%,
var(--card) 44%);
box-shadow:
0 1px 2px color-mix(in srgb, var(--foreground) 4%, transparent),
0 18px 44px -34px color-mix(in srgb, var(--foreground) 26%, transparent);
}
.snap-group::before {
content: "";
position: absolute;
left: 0; top: 14px; bottom: 14px;
width: 3px;
border-radius: 999px;
background: var(--snap-accent, var(--primary));
opacity: .5;
}
.snap-head {
display: inline-flex;
align-items: center;
gap: 8px;
margin-bottom: 3px;
}
.snap-dot {
width: 6px; height: 6px;
border-radius: 999px;
background: var(--snap-accent, var(--primary));
flex-shrink: 0;
}
.snap-title {
font-family: var(--font-serif);
font-optical-sizing: auto;
font-variation-settings: "SOFT" 40, "WONK" 0;
letter-spacing: -.011em;
font-weight: 600;
font-size: 14.5px;
color: var(--foreground);
}
.snap-sub {
font-size: 11px;
line-height: 1.45;
color: var(--muted-foreground);
margin: 0 0 9px;
}
.snap-rows { display: flex; flex-direction: column; }
.snap-row {
display: flex;
align-items: baseline;
justify-content: space-between;
gap: 16px;
padding: 8px 0;
border-top: 1px solid color-mix(in srgb, var(--border) 65%, transparent);
}
.snap-row:first-child { border-top: 0; }
.snap-row dt {
font-size: 11.5px;
line-height: 1.4;
color: var(--muted-foreground);
flex: 1;
min-width: 0;
}
.snap-row dd {
margin: 0;
font-size: 12.5px;
font-weight: 600;
color: var(--foreground);
text-align: right;
font-variant-numeric: tabular-nums;
max-width: 60%;
overflow-wrap: anywhere;
}
.snap-row[data-rel="true"] dd { color: var(--primary); }
.snap-group--sit {
padding: 13px 16px;
background:
linear-gradient(180deg,
color-mix(in srgb, var(--primary) 4%, var(--card)) 0%,
var(--card) 60%);
}
.snap-group--sit::before { display: none; }
.snap-sit-toggle {
display: flex;
align-items: center;
gap: 9px;
width: 100%;
background: none;
border: 0;
padding: 0;
cursor: pointer;
color: inherit;
text-align: left;
}
.snap-rel-pill {
font-size: 9px;
font-weight: 700;
letter-spacing: .05em;
text-transform: uppercase;
color: var(--primary);
background: color-mix(in srgb, var(--primary) 12%, transparent);
border: 1px solid color-mix(in srgb, var(--primary) 38%, transparent);
border-radius: 999px;
padding: 2px 8px;
white-space: nowrap;
}
.snap-chevron {
margin-left: auto;
font-size: 15px;
line-height: 1;
color: var(--muted-foreground);
transition: transform .2s ease;
}
.snap-chevron[data-open="true"] { transform: rotate(180deg); }
.snap-rel-tag {
font-size: 8.5px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: .05em;
color: var(--primary);
margin-left: 7px;
vertical-align: middle;
}
/* In-chat / marketplace card stat tile (#47/#89) β€” equal-height tiles in a
* 2Γ—2 grid. The label gets a fixed 2-line block so a 1-line label and a
* wrapping one ("Mandatory co-pay") line up, and the value is pinned to the
* bottom so all four value baselines align. overflow:visible so the
* hover "?" tooltip is never clipped by the tile. */
.cs-tile {
display: flex;
flex-direction: column;
min-height: 64px;
background: color-mix(in srgb, var(--primary) 4%, var(--muted));
border: 1px solid color-mix(in srgb, var(--border) 82%, transparent);
border-radius: 10px;
padding: 8px 10px;
overflow: visible;
}
.cs-label {
font-size: 9.5px;
font-weight: 600;
letter-spacing: .045em;
text-transform: uppercase;
color: var(--muted-foreground);
line-height: 1.25;
min-height: 2.4em; /* reserve 2 lines so every tile aligns */
display: flex;
align-items: flex-start;
overflow-wrap: anywhere;
}
.cs-value {
margin-top: auto;
padding-top: 4px;
font-size: 13px;
font-weight: 700;
color: var(--foreground);
font-variant-numeric: tabular-nums;
line-height: 1.2;
overflow-wrap: anywhere;
}
/* ─────────────────────────────────────────────────────────────────────
* REPUTATION β€” one card per independent source (#82). Same editorial
* tokens as the snapshot: tinted card, hairline, soft lift on hover for
* the clickable ones. A lead "overall" synthesis sits above the grid.
* ───────────────────────────────────────────────────────────────────── */
.rev-lead {
display: flex;
align-items: flex-start;
gap: 12px;
border: 1px solid var(--border);
border-radius: 16px;
padding: 13px 15px;
background:
linear-gradient(180deg,
color-mix(in srgb, var(--primary) 6%, var(--card)) 0%,
var(--card) 50%);
box-shadow:
0 1px 2px color-mix(in srgb, var(--foreground) 4%, transparent),
0 18px 44px -34px color-mix(in srgb, var(--foreground) 26%, transparent);
}
.rev-grade {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 46px; height: 46px;
border-radius: 12px;
font-size: 17px;
font-weight: 800;
line-height: 1;
flex-shrink: 0;
}
.rev-grade small { font-size: 9px; font-weight: 700; opacity: .9; margin-top: 2px; }
.rev-lead-head { font-size: 12.5px; line-height: 1.45; color: var(--foreground); }
.rev-lead-sub {
font-size: 10.5px;
line-height: 1.4;
color: var(--muted-foreground);
margin-top: 4px;
}
/* #90 β€” fixed 3Γ—2 even grid (never ragged auto-fit). Equal-height rows so
* the six buckets are perfectly uniform regardless of content length. */
.rev-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: 1fr;
gap: 10px;
}
@media (max-width: 900px) { .rev-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .rev-grid { grid-template-columns: 1fr; } }
.rev-card {
position: relative;
display: flex;
flex-direction: column;
min-height: 116px;
border: 1px solid color-mix(in srgb, var(--border) 82%, transparent);
border-radius: 12px;
padding: 12px 13px;
background: color-mix(in srgb, var(--primary) 4%, var(--card));
text-decoration: none;
color: inherit;
}
.rev-card--link { transition: border-color .18s ease, box-shadow .18s ease, transform .18s ease; }
.rev-card--link:hover {
border-color: color-mix(in srgb, var(--primary) 48%, var(--border));
box-shadow: 0 14px 30px -24px color-mix(in srgb, var(--foreground) 32%, transparent);
transform: translateY(-1px);
}
.rev-src {
font-size: 9.5px;
font-weight: 700;
letter-spacing: .07em;
text-transform: uppercase;
color: var(--muted-foreground);
}
.rev-val {
font-size: 16px;
font-weight: 700;
color: var(--foreground);
margin-top: 4px;
font-variant-numeric: tabular-nums;
}
.rev-verdict {
font-size: 13px;
font-weight: 600;
text-transform: capitalize;
}
.rev-sub {
font-size: 10.5px;
line-height: 1.4;
color: var(--muted-foreground);
margin-top: 3px;
}
.rev-go {
color: var(--primary);
font-weight: 700;
font-size: 10px;
}
.rev-card--sum { padding: 12px 14px; }
.rev-lines { display: flex; flex-direction: column; gap: 2px; margin-top: 7px; }
.rev-line {
display: block;
font-size: 12px;
line-height: 1.5;
text-decoration: none;
color: var(--foreground);
padding: 3px 0;
border-top: 1px solid color-mix(in srgb, var(--border) 55%, transparent);
}
.rev-lines .rev-line:first-child { border-top: 0; }
.rev-line:hover .rev-line-name { color: var(--primary); }
.rev-line-name { font-weight: 600; }
.rev-line-verdict { color: var(--muted-foreground); }
/* ─────────────────────────────────────────────────────────────────────
* GLOSSARY TIP (#64/#65/#98) β€” the ONE explainer used on snapshot rows
* AND card tiles. Hover/focus only (no click, no close). The popup is
* width-constrained and sits ABOVE the badge, centred, pointer-events-
* none, so it never blocks interaction or spills across cards. Editorial
* card chrome to match .snap-* / .rev-* (Fraunces-adjacent title, soft
* shadow, hairline border).
* ───────────────────────────────────────────────────────────────────── */
.gtip { position: relative; display: inline-flex; vertical-align: middle; margin-left: 5px; }
.gtip-badge {
display: inline-flex; align-items: center; justify-content: center;
width: 14px; height: 14px; border-radius: 999px;
border: 1px solid color-mix(in srgb, var(--muted-foreground) 55%, transparent);
color: var(--muted-foreground);
font-size: 9px; font-weight: 700; line-height: 1;
cursor: help; user-select: none; outline: none;
transition: color .15s ease, border-color .15s ease;
}
.gtip:hover .gtip-badge,
.gtip:focus-within .gtip-badge {
color: var(--primary);
border-color: color-mix(in srgb, var(--primary) 60%, transparent);
}
.gtip-pop {
pointer-events: none;
position: absolute;
bottom: calc(100% + 8px);
left: 50%;
transform: translateX(-50%) translateY(3px);
width: min(20rem, 74vw);
background: var(--card);
border: 1px solid var(--border);
border-radius: 12px;
box-shadow:
0 1px 2px color-mix(in srgb, var(--foreground) 5%, transparent),
0 18px 44px -22px color-mix(in srgb, var(--foreground) 32%, transparent);
padding: 11px 13px;
text-align: left;
opacity: 0;
visibility: hidden;
transition: opacity .15s ease, transform .15s ease, visibility .15s;
z-index: 60;
}
.gtip:hover .gtip-pop,
.gtip:focus-within .gtip-pop {
opacity: 1;
visibility: visible;
transform: translateX(-50%) translateY(0);
}
.gtip-pop::after {
content: "";
position: absolute;
top: 100%;
left: 50%;
transform: translateX(-50%);
border: 6px solid transparent;
border-top-color: var(--card);
}
.gtip-title {
display: block;
font-family: var(--font-serif);
font-weight: 600;
font-size: 12.5px;
letter-spacing: -.01em;
color: var(--foreground);
margin-bottom: 4px;
}
.gtip-body {
display: block;
font-size: 11.5px;
line-height: 1.5;
color: var(--muted-foreground);
text-transform: none;
font-weight: 400;
letter-spacing: normal;
}
/* ─────────────────────────────────────────────────────────────────────
* HelpTip β€” the shared "?" affordance for policy-calculation controls.
*
* Visual chrome mirrors `.gtip-*` above (14px badge, var(--card) bg,
* var(--border) hairline, Fraunces title, soft shadow, small arrow). The
* difference is structural: the popover is portalled to <body> and given
* `position:fixed` coords by HelpTip.tsx (the surfaces sit in overflow
* scroll containers that clip an absolute popover), so this block carries
* NO positioning β€” only appearance and the up/down arrow direction.
* ───────────────────────────────────────────────────────────────────── */
.helptip-badge {
display: inline-flex; align-items: center; justify-content: center;
width: 14px; height: 14px; border-radius: 999px;
border: 1px solid color-mix(in srgb, var(--muted-foreground) 55%, transparent);
background: transparent;
color: var(--muted-foreground);
font-size: 9px; font-weight: 700; line-height: 1;
cursor: help; user-select: none; outline: none; padding: 0;
margin-left: 5px;
transition: color .15s ease, border-color .15s ease;
}
.helptip-badge:hover,
.helptip-badge:focus-visible,
.helptip-badge[aria-expanded="true"] {
color: var(--primary);
border-color: color-mix(in srgb, var(--primary) 60%, transparent);
}
.helptip-badge:focus-visible {
box-shadow: 0 0 0 2px color-mix(in srgb, var(--primary) 35%, transparent);
}
.helptip-pop {
width: min(20rem, 74vw);
background: var(--card);
border: 1px solid var(--border);
border-radius: 12px;
box-shadow:
0 1px 2px color-mix(in srgb, var(--foreground) 5%, transparent),
0 18px 44px -22px color-mix(in srgb, var(--foreground) 32%, transparent);
padding: 11px 13px;
text-align: left;
}
.helptip-pop::after {
content: "";
position: absolute;
left: 50%;
transform: translateX(-50%);
border: 6px solid transparent;
}
.helptip-pop--above::after {
top: 100%;
border-top-color: var(--card);
}
.helptip-pop--below::after {
bottom: 100%;
border-bottom-color: var(--card);
}
.helptip-title {
display: block;
font-family: var(--font-serif);
font-weight: 600;
font-size: 12.5px;
letter-spacing: -.01em;
color: var(--foreground);
margin-bottom: 4px;
}
.helptip-body {
display: block;
font-size: 11.5px;
line-height: 1.5;
color: var(--muted-foreground);
text-transform: none;
font-weight: 400;
letter-spacing: normal;
}