diff --git a/README.md b/README.md index 22e31e0..81e2d36 100644 --- a/README.md +++ b/README.md @@ -1411,6 +1411,26 @@ Things I chose while building, with the reasoning: pre-blurred wallpaper — the scene is clearly visible through the glass, and the pixel-contrast scan still passes. +70. **Chat answers are bubbles in Aero too.** The assistant answers are deliberately bubble-less + (full-width text on the flat themes) and the user bubble's thin tint washed out over the bright + parts of the wallpaper, so the longest text in the app ended up sitting straight on the photo. + In Aero both get a real pane: `.chat-answer` wraps the markdown in a bubble (plus a + `chat-bubble` class on the user turn), with a stronger veil than the shared glass so a wall of + text still reads comfortably over the same blurred scene, and the bright rim. Light and dark + keep the bubble-less assistant design — these classes are styled only under `.aero`. + +69. **The glass got thinner and reaches the whole app.** Two asks in one pass: "slightly more + transparent" and "some buttons aren't themed" while doing decks/homework. The veils drop + another notch (recipe 0.15 -> 0.12, the tokens ~0.03 less, the tab bar / wizard bar / gloss + likewise), and the recipe now catches the flows' hand-rolled frost: the study activities' + `bg-white/xx` chips (multiple-choice options, matching terms, ordering cards, fill-in-blank + chips), the exam deck rows and pickers that used `bg-[var(--surface)]` — an *opaque* white in + Aero — and everything using the surface tokens (chat action chips, homework chips, inputs, + dropzones); attribute selectors match them, so no component needed a new class. The same shapes + inside sheets stay flat (the exclusion list covers the new selectors — there the sheet itself is + the glass), and the dropzones lost their press-scale (a transform on a fixed backdrop + re-anchors it) and shade inward instead. `tests/contrast.mjs`: 0 findings. + 68. **The Ask pill joins the glass, and Aero's hovers light the pane instead of moving it.** Two leftovers from the previous pass. The Ask button (and the two phone icon pills that share its styling) was a hand-styled `bg-[var(--surface-strong)]` pill that never picked up the frosted diff --git a/app/globals.css b/app/globals.css index 4565aa3..d9730a1 100644 --- a/app/globals.css +++ b/app/globals.css @@ -295,10 +295,10 @@ .aero .glass { background-image: linear-gradient( 180deg, - rgb(255 255 255 / 0.32) 0%, - rgb(255 255 255 / 0.1) 46%, + rgb(255 255 255 / 0.28) 0%, + rgb(255 255 255 / 0.08) 46%, rgb(255 255 255 / 0.03) 47%, - rgb(255 255 255 / 0.1) 100% + rgb(255 255 255 / 0.08) 100% ); } @@ -386,12 +386,12 @@ stay thin too. Contrast is pixel-scanned in all three themes, so the tints cannot drop below what the text needs. */ .aero { - --glass-bg: rgb(228 246 255 / 0.26); - --glass-solid-bg: rgb(232 248 255 / 0.34); - --glass-sheet-bg: rgb(232 248 255 / 0.68); - --surface-strong: rgb(255 255 255 / 0.26); - --surface-sunken: rgb(255 255 255 / 0.2); - --nav-active-bg: rgb(255 255 255 / 0.3); + --glass-bg: rgb(228 246 255 / 0.22); + --glass-solid-bg: rgb(232 248 255 / 0.3); + --glass-sheet-bg: rgb(232 248 255 / 0.64); + --surface-strong: rgb(255 255 255 / 0.23); + --surface-sunken: rgb(255 255 255 / 0.17); + --nav-active-bg: rgb(255 255 255 / 0.27); } /* Liquid glass — one recipe for every surface, so the rail, the cards, the @@ -418,16 +418,29 @@ .aero .grad-ice, .aero .segmented, .aero .segmented > button[aria-pressed="true"], -.aero .segmented > a[aria-current="page"] { +.aero .segmented > a[aria-current="page"], +/* Hand-rolled frost fills in the study, exam, chat and homework flows: + white/xx utilities and the surface tokens — without this they render as + flat white chips next to the glass. */ +.aero [class*="bg-white/35"], +.aero [class*="bg-white/40"], +.aero [class*="bg-white/45"], +.aero [class*="bg-white/50"], +.aero [class*="bg-white/55"], +.aero [class*="bg-white/60"], +.aero [class*="bg-white/70"], +.aero [class*="bg-[var(--surface)]"], +.aero [class*="bg-[var(--surface-strong)]"], +.aero [class*="bg-frost-50"] { background-image: linear-gradient( 180deg, - rgb(255 255 255 / 0.16) 0%, - rgb(255 255 255 / 0.05) 46%, - rgb(255 255 255 / 0.04) 53%, - rgb(255 255 255 / 0.09) 100% + rgb(255 255 255 / 0.13) 0%, + rgb(255 255 255 / 0.04) 46%, + rgb(255 255 255 / 0.03) 53%, + rgb(255 255 255 / 0.07) 100% ), - linear-gradient(rgb(255 255 255 / 0.15), rgb(255 255 255 / 0.15)), + linear-gradient(rgb(255 255 255 / 0.12), rgb(255 255 255 / 0.12)), url("/aero/background-blur.webp?v=3"); background-size: 100% 100%, 100% 100%, cover; background-position: 0 0, 0 0, center 42%; @@ -439,7 +452,7 @@ blue, which read as a heavy slab over the photo — give it the same thin glass as everything else (it already has a real backdrop blur). */ .aero [data-wizard-bar] { - background: rgb(255 255 255 / 0.24); + background: rgb(255 255 255 / 0.2); border-top-color: rgb(255 255 255 / 0.6); box-shadow: 0 -14px 34px -22px rgb(2 62 110 / 0.5); } @@ -484,6 +497,7 @@ } .aero .card-hover:active, .aero .card-hover:hover, +.aero .press:active, .aero .btn-primary:active, .aero .segmented > button:active, .aero .segmented > a:active, @@ -494,6 +508,7 @@ filter: none; } .aero .card-hover:active, +.aero .press:active, .aero .btn-primary:active, .aero .nav-action:active, .aero .glass-pill:active, @@ -501,16 +516,46 @@ box-shadow: inset 0 2px 8px rgb(2 62 110 / 0.2), inset 0 1px 0 rgb(255 255 255 / 0.8); } +/* 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 .chat-bubble, +.aero .chat-answer { + border-color: rgb(255 255 255 / 0.7); + 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"); + background-size: 100% 100%, cover; + background-position: 0 0, center 42%; + background-attachment: scroll, fixed; + background-repeat: no-repeat, no-repeat; + 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; + padding: 0.7rem 0.95rem; +} + /* The phone tab bar carries its labels right at the bottom of the water, so it keeps a little more veil than the cards. */ .aero .tabbar { background-image: linear-gradient( 180deg, - rgb(255 255 255 / 0.26) 0%, - rgb(255 255 255 / 0.12) 46%, - rgb(255 255 255 / 0.1) 53%, - rgb(255 255 255 / 0.16) 100% + rgb(255 255 255 / 0.22) 0%, + rgb(255 255 255 / 0.1) 46%, + rgb(255 255 255 / 0.08) 53%, + rgb(255 255 255 / 0.13) 100% ), url("/aero/background-blur.webp?v=3"); background-size: 100% 100%, cover; @@ -533,7 +578,17 @@ .aero .glass-sheet .segmented > a[aria-current="page"], .aero .glass-sheet .btn-secondary, .aero .glass-sheet .btn-primary, -.aero .glass-sheet .grad-ice { +.aero .glass-sheet .grad-ice, +.aero .glass-sheet [class*="bg-white/35"], +.aero .glass-sheet [class*="bg-white/40"], +.aero .glass-sheet [class*="bg-white/45"], +.aero .glass-sheet [class*="bg-white/50"], +.aero .glass-sheet [class*="bg-white/55"], +.aero .glass-sheet [class*="bg-white/60"], +.aero .glass-sheet [class*="bg-white/70"], +.aero .glass-sheet [class*="bg-[var(--surface)]"], +.aero .glass-sheet [class*="bg-[var(--surface-strong)]"], +.aero .glass-sheet [class*="bg-frost-50"] { background-image: none; } diff --git a/components/chat/MessageRow.tsx b/components/chat/MessageRow.tsx index c466060..80ac578 100644 --- a/components/chat/MessageRow.tsx +++ b/components/chat/MessageRow.tsx @@ -43,7 +43,7 @@ export function MessageRow({ if (message.role === "user") { return (
{message.content}
{message.attachments && message.attachments.length > 0 ? (@@ -69,7 +69,9 @@ export function MessageRow({