Chat chrome: one gutter, one radius scale, one even glass recipe
The header and composer were full-bleed bands (flush to the top/right/bottom viewport edges, composer corners off-screen) next to a rail that floats with a 12px margin. The new --layout-gutter (12px) spaces the rail, header, empty-state card and composer identically on every side; --radius-panel/-control/-chip (-pill) replace the ad-hoc radii across the shared classes, so every panel is rounded on all four corners and shared controls match in every theme. The desktop-only ::after hairlines and the left-corner-only radius are gone. Aero: the rail and the chat chrome (answers included) share one even recipe - the wallpaper extra-blurred into a hue-free wash (background-glass.webp) under a uniform ~50% white veil and a whisper of gloss. Measured within ~10 RGB units across the rail top->bottom and the card/composer left->right; the blue->green smear and the teal composer are gone. The composer's field is a clean even tile with no wallpaper gradient inside it. Chat fixes: send is a filled primary tile shaped exactly like attach (dimmed while the input is empty), suggestion/context chips use the shared .chip token (40/44px target, visible rim, full-contrast text, raw model id in the tooltip), the AI note reads at 12px --text-muted (.ai-disclaimer), the selected sidebar row carries the accent border + accent icon, the theme toggle is back in Aero (the moon flips to Dark; Settings brings Aero back), and the empty state is centered exactly between header and composer. Outside CSS: the wallpaper's top-left HUD-circle decoration (it peeked through the 12px gutters on wide windows) was healed out of background.webp and background-blur.webp; the orbs/bubbles ride one masked .ice-floats layer that fades them under the chrome bands and the rail strip, so none is sliced by a panel edge (still parked under reduced motion). Version 0.6.0, SW -> freezmo-v82. Tests: chat suite pins the new geometry (12px gutter, 24px corners, even wash on all four panels, send-vs-attach shape, chips/input radii); mobile pins the phone chrome and the Aero toggle; bubbles pins the floats layer + its reduced-motion opt-out.
This commit is contained in:
parent
8153fc8dae
commit
786d6cf1ae
21 changed files with 562 additions and 290 deletions
364
app/globals.css
364
app/globals.css
|
|
@ -100,6 +100,15 @@
|
|||
--hover: rgb(12 32 62 / 0.05);
|
||||
--focus: #0ea5e9;
|
||||
|
||||
/* Shared layout scale: one gutter for every floating panel and one radius
|
||||
per role, so the rail, the header, the composer and the cards line up in
|
||||
every theme — only the surface treatment differs. */
|
||||
--layout-gutter: 0.75rem; /* 12px — the same inset the rail floats with */
|
||||
--radius-panel: 1.5rem; /* 24px — floating panels and cards */
|
||||
--radius-control: 0.875rem; /* 14px — buttons, inputs, tiles */
|
||||
--radius-chip: 0.75rem; /* 12px — chips, nav rows, small controls */
|
||||
--radius-pill: 999px; /* fully rounded */
|
||||
|
||||
/* Frosted ice glass — one shared recipe for every large surface. */
|
||||
--glass-bg: rgb(255 255 255 / 0.55);
|
||||
/* A cool rim instead of near-white: white-on-white made light-mode card
|
||||
|
|
@ -112,8 +121,8 @@
|
|||
than the cards: at 0.55 the muted text under it measured ~2.8:1. */
|
||||
--glass-sheet-bg: rgb(255 255 255 / 0.93);
|
||||
--glass-fallback: rgb(247 251 255 / 0.97); /* no backdrop-filter */
|
||||
--nav-active-bg: rgb(255 255 255 / 0.75);
|
||||
--nav-active-border: rgb(56 189 248 / 0.5);
|
||||
--nav-active-bg: rgb(219 238 254 / 0.95);
|
||||
--nav-active-border: rgb(56 189 248 / 0.65);
|
||||
/* API-key gate: cool near-white stage with soft blue glows, tinted input. */
|
||||
--gate-card: rgb(255 255 255 / 0.62);
|
||||
--gate-callout-bg: rgb(255 255 255 / 0.55);
|
||||
|
|
@ -160,8 +169,8 @@
|
|||
--glass-solid-bg: rgb(255 255 255 / 0.1);
|
||||
--glass-sheet-bg: rgb(17 27 46 / 0.94);
|
||||
--glass-fallback: rgb(16 26 45 / 0.97);
|
||||
--nav-active-bg: rgb(56 189 248 / 0.14);
|
||||
--nav-active-border: rgb(56 189 248 / 0.4);
|
||||
--nav-active-bg: rgb(56 189 248 / 0.18);
|
||||
--nav-active-border: rgb(56 189 248 / 0.55);
|
||||
/* API-key gate: navy stage with the icon's blue glows, raised input. */
|
||||
--gate-card: rgb(255 255 255 / 0.06);
|
||||
--gate-callout-bg: rgb(255 255 255 / 0.06);
|
||||
|
|
@ -235,8 +244,8 @@
|
|||
--glass-solid-bg: rgb(232 248 255 / 0.9);
|
||||
--glass-sheet-bg: rgb(232 246 255 / 0.94);
|
||||
--glass-fallback: rgb(226 242 253 / 0.97);
|
||||
--nav-active-bg: rgb(255 255 255 / 0.85);
|
||||
--nav-active-border: rgb(14 165 233 / 0.7);
|
||||
--nav-active-bg: rgb(255 255 255 / 0.5);
|
||||
--nav-active-border: rgb(14 165 233 / 0.75);
|
||||
--gate-card: rgb(226 244 255 / 0.7);
|
||||
--gate-callout-bg: rgb(255 255 255 / 0.6);
|
||||
--gate-callout-border: rgb(56 189 248 / 0.45);
|
||||
|
|
@ -263,7 +272,7 @@
|
|||
in public/aero/). Only the moving bubbles are drawn on top; the image
|
||||
already has grass, sun, water and clouds. */
|
||||
.aero .ice-scene {
|
||||
background-image: url("/aero/background.webp?v=3");
|
||||
background-image: url("/aero/background.webp?v=4");
|
||||
background-size: cover;
|
||||
background-position: center 42%;
|
||||
background-repeat: no-repeat;
|
||||
|
|
@ -417,7 +426,7 @@
|
|||
--surface-strong: rgb(255 255 255 / 0.23);
|
||||
--surface-sunken: rgb(255 255 255 / 0.17);
|
||||
--track: rgb(255 255 255 / 0.38);
|
||||
--nav-active-bg: rgb(255 255 255 / 0.27);
|
||||
--nav-active-bg: rgb(255 255 255 / 0.5);
|
||||
}
|
||||
|
||||
/* Liquid glass — one recipe for every surface, so the rail, the cards, the
|
||||
|
|
@ -467,7 +476,7 @@
|
|||
rgb(255 255 255 / 0.09) 100%
|
||||
),
|
||||
linear-gradient(rgb(255 255 255 / 0.16), rgb(255 255 255 / 0.16)),
|
||||
url("/aero/background-blur.webp?v=3");
|
||||
url("/aero/background-blur.webp?v=4");
|
||||
background-size: 100% 100%, 100% 100%, cover;
|
||||
background-position: 0 0, 0 0, center 42%;
|
||||
background-attachment: scroll, scroll, fixed;
|
||||
|
|
@ -555,20 +564,15 @@
|
|||
/* Chat: the longest text in the app sits straight on the wallpaper. The
|
||||
assistant answers are deliberately bubble-less in the flat themes, and the
|
||||
user bubble's thin tint washes out over the bright parts of the scene — in
|
||||
Aero both get a real pane (a stronger veil than the shared glass, so an
|
||||
answer reads as its own bubble). */
|
||||
Aero both get a real pane: the same even wash as the chrome, a touch more
|
||||
opaque (this is where the reading happens), so an answer reads as its own
|
||||
bubble and its colour does not drift with the photo behind it. */
|
||||
.aero .chat-bubble,
|
||||
.aero .chat-answer {
|
||||
border-color: rgb(255 255 255 / 0.7);
|
||||
border-color: rgb(255 255 255 / 0.85);
|
||||
background-image:
|
||||
linear-gradient(
|
||||
180deg,
|
||||
rgb(255 255 255 / 0.6) 0%,
|
||||
rgb(255 255 255 / 0.44) 46%,
|
||||
rgb(255 255 255 / 0.4) 53%,
|
||||
rgb(255 255 255 / 0.52) 100%
|
||||
),
|
||||
url("/aero/background-blur.webp?v=3");
|
||||
linear-gradient(rgb(255 255 255 / 0.6), rgb(255 255 255 / 0.6)),
|
||||
url("/aero/background-glass.webp?v=4");
|
||||
background-size: 100% 100%, cover;
|
||||
background-position: 0 0, center 42%;
|
||||
background-attachment: scroll, fixed;
|
||||
|
|
@ -576,9 +580,9 @@
|
|||
box-shadow: 0 16px 34px -22px rgb(2 62 110 / 0.45), inset 0 1px 0 rgb(255 255 255 / 0.9);
|
||||
}
|
||||
.aero .chat-answer {
|
||||
border: 1px solid rgb(255 255 255 / 0.7);
|
||||
border-radius: 1.25rem;
|
||||
border-bottom-left-radius: 0.6rem;
|
||||
border: 1px solid rgb(255 255 255 / 0.85);
|
||||
border-radius: var(--radius-panel);
|
||||
border-bottom-left-radius: var(--radius-chip);
|
||||
padding: 0.7rem 0.95rem;
|
||||
}
|
||||
|
||||
|
|
@ -593,7 +597,7 @@
|
|||
rgb(255 255 255 / 0.08) 53%,
|
||||
rgb(255 255 255 / 0.13) 100%
|
||||
),
|
||||
url("/aero/background-blur.webp?v=3");
|
||||
url("/aero/background-blur.webp?v=4");
|
||||
background-size: 100% 100%, cover;
|
||||
background-position: 0 0, center 42%;
|
||||
background-attachment: scroll, fixed;
|
||||
|
|
@ -633,6 +637,15 @@
|
|||
background-image: none;
|
||||
background-color: rgb(255 255 255 / 0.55);
|
||||
}
|
||||
/* The chat chrome and the rail keep one even, a little stronger tint on
|
||||
touch: without the baked blur the flat fill has to carry the surface on
|
||||
its own, or the photo underneath tints it unevenly again. */
|
||||
.aero .chat-header,
|
||||
.aero .chat-empty,
|
||||
.aero .chat-composer-band {
|
||||
background-image: none;
|
||||
background-color: rgb(255 255 255 / 0.55);
|
||||
}
|
||||
.aero .tabbar {
|
||||
background-image: none;
|
||||
}
|
||||
|
|
@ -665,7 +678,7 @@
|
|||
rgb(255 255 255 / 0.32) 53%,
|
||||
rgb(255 255 255 / 0.44) 100%
|
||||
),
|
||||
url("/aero/background-blur.webp?v=3");
|
||||
url("/aero/background-blur.webp?v=4");
|
||||
background-size: 100% 100%, cover;
|
||||
background-position: 0 0, center 42%;
|
||||
background-attachment: scroll, fixed;
|
||||
|
|
@ -680,7 +693,7 @@
|
|||
rgb(255 255 255 / 0.32) 53%,
|
||||
rgb(255 255 255 / 0.44) 100%
|
||||
),
|
||||
url("/aero/background-blur.webp?v=3");
|
||||
url("/aero/background-blur.webp?v=4");
|
||||
background-size: 100% 100%, cover;
|
||||
background-position: 0 0, center 42%;
|
||||
background-attachment: scroll, fixed;
|
||||
|
|
@ -689,85 +702,41 @@
|
|||
color: var(--text);
|
||||
}
|
||||
|
||||
/* Chat header: the same glass as the cards, a touch more fill — its title and
|
||||
scope line sit directly over the sky. At lg its divider is the inset hairline
|
||||
the desktop block below draws (::after), so it never hits the seam. */
|
||||
.aero .chat-header {
|
||||
background-color: rgb(232 248 255 / 0.4);
|
||||
border-bottom: 1px solid rgb(255 255 255 / 0.6);
|
||||
}
|
||||
.aero .chat-header::after {
|
||||
background: rgb(255 255 255 / 0.6);
|
||||
/* Chat chrome and the rail: one even frosted recipe. The pre-blurred,
|
||||
extra-soft wash of the wallpaper (background-glass) sits under a uniform
|
||||
white veil, so the surface colour cannot drift with the photo behind it —
|
||||
the rail used to run from clear blue into a muddy green smear, the composer
|
||||
picked up the river's teal and the header a saturated stripe of sky. */
|
||||
.aero .sidebar-surface,
|
||||
.aero .chat-header,
|
||||
.aero .chat-empty,
|
||||
.aero .chat-composer-band {
|
||||
background-image:
|
||||
linear-gradient(
|
||||
180deg,
|
||||
rgb(255 255 255 / 0.3) 0%,
|
||||
rgb(255 255 255 / 0.1) 46%,
|
||||
rgb(255 255 255 / 0.05) 53%,
|
||||
rgb(255 255 255 / 0.12) 100%
|
||||
),
|
||||
linear-gradient(rgb(255 255 255 / 0.46), rgb(255 255 255 / 0.46)),
|
||||
url("/aero/background-glass.webp?v=4");
|
||||
background-size: 100% 100%, 100% 100%, cover;
|
||||
background-position: 0 0, 0 0, center 42%;
|
||||
background-attachment: scroll, scroll, fixed;
|
||||
background-repeat: no-repeat, no-repeat, no-repeat;
|
||||
}
|
||||
|
||||
/* The chat composer: one flat frosted panel for the input, the chips and the
|
||||
note — instead of each of them floating on the wallpaper. */
|
||||
.aero .chat-composer {
|
||||
background-color: rgb(232 248 255 / 0.55);
|
||||
border-top: 1px solid rgb(255 255 255 / 0.65);
|
||||
box-shadow: 0 -16px 36px -26px rgb(2 62 110 / 0.5);
|
||||
}
|
||||
.aero .chat-composer::after {
|
||||
background: rgb(255 255 255 / 0.65);
|
||||
}
|
||||
|
||||
/* Desktop: the chat chrome ends at the rail with a rounded corner. The header
|
||||
and the composer are full-bleed bands inside the main pane, which starts
|
||||
right at the sidebar; a straight vertical edge there read as a hard cut (the
|
||||
12px gutter showed the raw scene and the bands' fill/blur made it a color
|
||||
step at the seam). Both bands now stop at the seam with the rail card's own
|
||||
1.5rem radius on their left end, so the ending reads as deliberate, and their
|
||||
hairlines span the content box instead of touching the seam. Phones keep the
|
||||
plain full-width borders. */
|
||||
@media (min-width: 1024px) {
|
||||
.chat-header {
|
||||
border-bottom: 0;
|
||||
border-start-start-radius: 1.5rem;
|
||||
border-end-start-radius: 1.5rem;
|
||||
}
|
||||
.aero .chat-header {
|
||||
border-bottom: 0;
|
||||
}
|
||||
.chat-header::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 1.5rem;
|
||||
right: 1rem;
|
||||
bottom: 0;
|
||||
height: 1px;
|
||||
background: var(--glass-border);
|
||||
}
|
||||
.chat-composer,
|
||||
.chat-composer-band {
|
||||
border-start-start-radius: 1.5rem;
|
||||
border-end-start-radius: 1.5rem;
|
||||
}
|
||||
.chat-composer-band {
|
||||
border-top: 0;
|
||||
}
|
||||
.aero .chat-composer {
|
||||
border-top: 0;
|
||||
}
|
||||
.chat-composer::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 2.5rem;
|
||||
right: 2.5rem;
|
||||
top: 0;
|
||||
height: 1px;
|
||||
background: var(--glass-border);
|
||||
}
|
||||
}
|
||||
|
||||
/* The chat welcome (subtitle + suggestions): the same frosted glass as the
|
||||
cards (the shared recipe above), stretched flush with the header and the
|
||||
composer — a panel floating 40px inside the scene looked cut off. */
|
||||
/* The chat welcome (title, subtitle, suggestion chips): a card like the
|
||||
library's, stretched across the conversation column so it lines up with the
|
||||
floating header above and composer below it. */
|
||||
.aero .chat-empty {
|
||||
margin-inline: -1rem;
|
||||
border-radius: 1.5rem;
|
||||
border: 1px solid rgb(255 255 255 / 0.5);
|
||||
background-color: rgb(255 255 255 / 0.32);
|
||||
padding: 1.35rem 1rem 1.1rem;
|
||||
border-radius: var(--radius-panel);
|
||||
border: 1px solid var(--glass-border);
|
||||
background-color: var(--glass-bg);
|
||||
box-shadow: var(--glass-shadow), inset 0 1px 0 var(--glass-highlight);
|
||||
}
|
||||
@media (min-width: 1024px) {
|
||||
.aero .chat-empty {
|
||||
|
|
@ -776,6 +745,24 @@
|
|||
}
|
||||
}
|
||||
|
||||
/* The column floats inside the main pane with the shared gutter; on desktop
|
||||
the rail already carries its own 12px right-hand gutter, so the column
|
||||
drops its left padding — every gap between the panels is then the same
|
||||
--layout-gutter. (Unlayered on purpose: it must beat the Tailwind
|
||||
`p-[var(--layout-gutter)]` utility.) */
|
||||
@media (min-width: 1024px) {
|
||||
.chat-column { padding-left: 0; }
|
||||
}
|
||||
|
||||
/* The composer's field: a clean, even glass tile — no wallpaper gradient
|
||||
inside it, just a lighter veil than the panel around it. */
|
||||
.aero .chat-composer-band textarea,
|
||||
.aero .chat-composer-band input[type="search"] {
|
||||
background-image: none;
|
||||
background-color: rgb(255 255 255 / 0.6);
|
||||
border-color: rgb(255 255 255 / 0.9);
|
||||
}
|
||||
|
||||
/* Page headings that sit straight on the wallpaper. */
|
||||
.aero .page-heading {
|
||||
display: inline-block;
|
||||
|
|
@ -785,25 +772,10 @@
|
|||
background-color: rgb(255 255 255 / 0.32);
|
||||
}
|
||||
|
||||
/* The rail's lower half sits over the grass; weight the glass a little below
|
||||
the middle so the bottom rows keep the same contrast as the top. */
|
||||
.aero .sidebar-surface {
|
||||
background-image:
|
||||
linear-gradient(180deg, rgb(255 255 255 / 0) 42%, rgb(255 255 255 / 0.22) 100%),
|
||||
linear-gradient(
|
||||
180deg,
|
||||
rgb(255 255 255 / 0.15) 0%,
|
||||
rgb(255 255 255 / 0.06) 46%,
|
||||
rgb(255 255 255 / 0.05) 53%,
|
||||
rgb(255 255 255 / 0.09) 100%
|
||||
),
|
||||
linear-gradient(rgb(255 255 255 / 0.16), rgb(255 255 255 / 0.16)),
|
||||
url("/aero/background-blur.webp?v=3");
|
||||
background-size: 100% 100%, 100% 100%, 100% 100%, cover;
|
||||
background-position: 0 0, 0 0, 0 0, center 42%;
|
||||
background-attachment: scroll, scroll, scroll, fixed;
|
||||
background-repeat: no-repeat, no-repeat, no-repeat, no-repeat;
|
||||
}
|
||||
/* The rail used to weight its lower half (the grass read darker through the
|
||||
glass) with a gradient that left a visible blue → green smear. It now uses
|
||||
the same even veil as the chat chrome — see the shared recipe above — so
|
||||
every row keeps the same contrast from top to bottom. */
|
||||
|
||||
/* Inside a sheet or dialog the backdrop is not the raw scene — a scrim and a
|
||||
more opaque sheet glass sit in between — so the viewport-aligned frosted
|
||||
|
|
@ -976,6 +948,90 @@ body:has(.overlay-open) :is(.app-header, .segmented, .tabbar, .cookie-notice) {
|
|||
100% { transform: translate3d(0, calc(-100vh - 100%), 0) scale(1.06); opacity: 0; }
|
||||
}
|
||||
|
||||
/* The rising orbs and bubbles are clipped to the scene, but the floating
|
||||
glass panels (the rail, the chat header/composer, the tab bar) sit on top of
|
||||
it — a bubble reaching one of those edges looked sliced by a straight line.
|
||||
This layer keeps them inside the open middle band: they fade in below the
|
||||
top chrome, out above the bottom chrome (the values come from where the
|
||||
header and the composer actually end) and, on desktop, stay out of the rail
|
||||
strip. Static under reduced motion: nothing moves there, and the parked
|
||||
orbs keep their spots. */
|
||||
.ice-floats {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
overflow: hidden;
|
||||
-webkit-mask-image: linear-gradient(
|
||||
to bottom,
|
||||
transparent 0,
|
||||
transparent 68px,
|
||||
black 150px,
|
||||
black calc(100% - 330px),
|
||||
transparent calc(100% - 172px)
|
||||
);
|
||||
mask-image: linear-gradient(
|
||||
to bottom,
|
||||
transparent 0,
|
||||
transparent 68px,
|
||||
black 150px,
|
||||
black calc(100% - 330px),
|
||||
transparent calc(100% - 172px)
|
||||
);
|
||||
}
|
||||
@media (min-width: 640px) {
|
||||
.ice-floats {
|
||||
-webkit-mask-image: linear-gradient(
|
||||
to bottom,
|
||||
transparent 0,
|
||||
transparent 68px,
|
||||
black 150px,
|
||||
black calc(100% - 300px),
|
||||
transparent calc(100% - 151px)
|
||||
);
|
||||
mask-image: linear-gradient(
|
||||
to bottom,
|
||||
transparent 0,
|
||||
transparent 68px,
|
||||
black 150px,
|
||||
black calc(100% - 300px),
|
||||
transparent calc(100% - 151px)
|
||||
);
|
||||
}
|
||||
}
|
||||
@media (min-width: 1024px) {
|
||||
/* …and the rail's strip (plus its gutter) stays clear too. */
|
||||
.ice-floats {
|
||||
-webkit-mask-image:
|
||||
linear-gradient(
|
||||
to bottom,
|
||||
transparent 0,
|
||||
transparent 68px,
|
||||
black 150px,
|
||||
black calc(100% - 300px),
|
||||
transparent calc(100% - 151px)
|
||||
),
|
||||
linear-gradient(to right, transparent 0, transparent 260px, black 360px);
|
||||
mask-image:
|
||||
linear-gradient(
|
||||
to bottom,
|
||||
transparent 0,
|
||||
transparent 68px,
|
||||
black 150px,
|
||||
black calc(100% - 300px),
|
||||
transparent calc(100% - 151px)
|
||||
),
|
||||
linear-gradient(to right, transparent 0, transparent 260px, black 360px);
|
||||
-webkit-mask-composite: destination-in;
|
||||
mask-composite: intersect;
|
||||
}
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.ice-floats { -webkit-mask-image: none !important; mask-image: none !important; }
|
||||
}
|
||||
html.reduce-motion .ice-floats {
|
||||
-webkit-mask-image: none !important;
|
||||
mask-image: none !important;
|
||||
}
|
||||
|
||||
/* Frosted grain over the whole scene. */
|
||||
.ice-grain {
|
||||
position: absolute;
|
||||
|
|
@ -1104,7 +1160,7 @@ body:has(.overlay-open) :is(.app-header, .segmented, .tabbar, .cookie-notice) {
|
|||
|
||||
.glass-panel {
|
||||
border: 1px solid var(--glass-border);
|
||||
border-radius: 1.5rem;
|
||||
border-radius: var(--radius-panel);
|
||||
}
|
||||
|
||||
/* Nested glass: slightly more opaque than its parent, no extra blur. */
|
||||
|
|
@ -1139,13 +1195,13 @@ body:has(.overlay-open) :is(.app-header, .segmented, .tabbar, .cookie-notice) {
|
|||
}
|
||||
|
||||
.card {
|
||||
border-radius: 1.5rem; /* 24px */
|
||||
border-radius: var(--radius-panel); /* 24px */
|
||||
border: 1px solid var(--glass-border);
|
||||
}
|
||||
|
||||
.gate-card {
|
||||
border: 1px solid var(--glass-border);
|
||||
border-radius: 1.75rem; /* 28px */
|
||||
border-radius: var(--radius-panel);
|
||||
}
|
||||
|
||||
/* Blur is expensive: halve it on phones (floating glass only). */
|
||||
|
|
@ -1188,7 +1244,7 @@ body:has(.overlay-open) :is(.app-header, .segmented, .tabbar, .cookie-notice) {
|
|||
|
||||
/* Inset grouped list ---------------------------------------------------- */
|
||||
.list-group {
|
||||
border-radius: 1rem;
|
||||
border-radius: var(--radius-control);
|
||||
@apply backdrop-blur-lg backdrop-saturate-150;
|
||||
background: color-mix(in oklab, var(--surface) 82%, transparent);
|
||||
border: 1px solid var(--hairline);
|
||||
|
|
@ -1198,19 +1254,53 @@ body:has(.overlay-open) :is(.app-header, .segmented, .tabbar, .cookie-notice) {
|
|||
border-top: 1px solid var(--hairline-soft);
|
||||
}
|
||||
|
||||
/* Shared chip ------------------------------------------------------------
|
||||
One control language for the chat's suggestion chips, the composer's
|
||||
context/model chips and the small chips inside a message: a light glass
|
||||
fill, a visible rim, full-contrast text and a real tap target (44px on
|
||||
phones, like every other control). */
|
||||
.chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
min-height: 2.5rem;
|
||||
border-radius: var(--radius-chip);
|
||||
border: 1px solid var(--glass-border);
|
||||
background: var(--surface-strong);
|
||||
color: var(--text);
|
||||
font-weight: 600;
|
||||
box-shadow: inset 0 1px 0 var(--glass-highlight);
|
||||
transition: background-color 160ms ease, border-color 160ms ease, color 160ms ease;
|
||||
}
|
||||
.chip:hover {
|
||||
background: var(--hover);
|
||||
border-color: var(--nav-active-border);
|
||||
}
|
||||
@media (max-width: 639px) {
|
||||
.chip { min-height: 44px; }
|
||||
}
|
||||
|
||||
/* The AI note under a surface that shows model output -------------------- */
|
||||
.ai-disclaimer {
|
||||
font-size: 12px;
|
||||
line-height: 1.4;
|
||||
color: var(--text-muted);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* iOS segmented control ------------------------------------------------- */
|
||||
.segmented {
|
||||
display: flex;
|
||||
gap: 2px;
|
||||
padding: 3px;
|
||||
border-radius: 0.95rem;
|
||||
border-radius: var(--radius-control);
|
||||
@apply backdrop-blur-sm;
|
||||
background: var(--surface-sunken);
|
||||
border: 1px solid var(--hairline);
|
||||
}
|
||||
.segmented > button {
|
||||
flex: 1;
|
||||
border-radius: 0.75rem;
|
||||
border-radius: var(--radius-chip);
|
||||
padding: 0.42rem 0.5rem;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
|
|
@ -1239,7 +1329,7 @@ body:has(.overlay-open) :is(.app-header, .segmented, .tabbar, .cookie-notice) {
|
|||
justify-content: center;
|
||||
gap: 0.375rem;
|
||||
min-height: 2.75rem;
|
||||
border-radius: 0.75rem;
|
||||
border-radius: var(--radius-chip);
|
||||
padding: 0.42rem 0.5rem;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
|
|
@ -1301,7 +1391,7 @@ body:has(.overlay-open) :is(.app-header, .segmented, .tabbar, .cookie-notice) {
|
|||
/* Sidebar surface: one tall inset glass panel. */
|
||||
.sidebar-surface {
|
||||
border: 1px solid var(--glass-border);
|
||||
border-radius: 1.5rem;
|
||||
border-radius: var(--radius-panel);
|
||||
}
|
||||
|
||||
/* Sidebar nav rows */
|
||||
|
|
@ -1310,7 +1400,7 @@ body:has(.overlay-open) :is(.app-header, .segmented, .tabbar, .cookie-notice) {
|
|||
align-items: center;
|
||||
gap: 0.625rem;
|
||||
width: 100%;
|
||||
border-radius: 0.625rem;
|
||||
border-radius: var(--radius-chip);
|
||||
padding: 0.5rem 0.625rem;
|
||||
font-size: 13.5px;
|
||||
font-weight: 500;
|
||||
|
|
@ -1330,7 +1420,7 @@ body:has(.overlay-open) :is(.app-header, .segmented, .tabbar, .cookie-notice) {
|
|||
align-items: center;
|
||||
gap: 0.625rem;
|
||||
width: 100%;
|
||||
border-radius: 0.75rem;
|
||||
border-radius: var(--radius-chip);
|
||||
padding: 0.5rem 0.625rem;
|
||||
font-size: 13.5px;
|
||||
font-weight: 600;
|
||||
|
|
@ -1347,7 +1437,15 @@ body:has(.overlay-open) :is(.app-header, .segmented, .tabbar, .cookie-notice) {
|
|||
.nav-row[aria-pressed="true"] {
|
||||
background: var(--nav-active-bg);
|
||||
color: var(--text);
|
||||
box-shadow: inset 0 0 0 1px var(--nav-active-border), inset 0 1px 0 var(--glass-highlight);
|
||||
font-weight: 600;
|
||||
box-shadow: inset 0 0 0 1.5px var(--nav-active-border), inset 0 1px 0 var(--glass-highlight);
|
||||
}
|
||||
/* …and the icon carries the accent, so the selected row can never be mistaken
|
||||
for one more tinted action button ("New deck", "New homework"). */
|
||||
.nav-row[aria-current="page"] svg,
|
||||
.nav-row[aria-pressed="true"] svg {
|
||||
color: var(--focus);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Shared CTA language: one ice gradient in *both* themes (it mirrors the
|
||||
|
|
@ -1358,7 +1456,7 @@ body:has(.overlay-open) :is(.app-header, .segmented, .tabbar, .cookie-notice) {
|
|||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.5rem;
|
||||
border-radius: 14px;
|
||||
border-radius: var(--radius-control);
|
||||
background-image: linear-gradient(135deg, #38bdf8 0%, #60a5fa 100%);
|
||||
color: #06111f;
|
||||
font-weight: 600;
|
||||
|
|
@ -1389,7 +1487,7 @@ body:has(.overlay-open) :is(.app-header, .segmented, .tabbar, .cookie-notice) {
|
|||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.5rem;
|
||||
border-radius: 14px;
|
||||
border-radius: var(--radius-control);
|
||||
background: var(--surface-strong);
|
||||
color: var(--text);
|
||||
border: 1px solid var(--glass-border);
|
||||
|
|
@ -1407,7 +1505,7 @@ body:has(.overlay-open) :is(.app-header, .segmented, .tabbar, .cookie-notice) {
|
|||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.5rem;
|
||||
border-radius: 14px;
|
||||
border-radius: var(--radius-control);
|
||||
background: transparent;
|
||||
color: var(--text-muted);
|
||||
font-weight: 500;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue