Surface every outstanding suggestion as a card in the right-hand
whitespace, vertically aligned to the text it flags — so the writer sees
the whole queue at once instead of hovering each highlight. Cards stack
with collision avoidance, link both ways with their highlight (hover/click
↔ soft text wash, driven through the decoration plugin so it survives
edit repaints), and carry the same Accept / Dismiss / Ask Petal actions.
The rail is a progressive enhancement: it mounts only when there's room
beside the editor, otherwise the existing inline hover card is unchanged.
Stacked cards that reach the bottom-right corner tuck behind the
companion mascot (z-order).
When a card is expanded, the Ask Petal bubble now opens with the
Simplified-Chinese translation of the explanation (the English stays in
the card body) instead of repeating the same text twice — a new
POST /api/suggestions/{id}/translate one-shot LLM endpoint, loaded
lazily on open with an English fallback.
Verified live against the local LLM via the uitest harness: rail
stacking, hover↔text wash, expand/Ask Petal, accept-from-rail, narrow
fallback, and the Mandarin bubble.
Claude-Session: https://claude.ai/code/session_016Yr6jELuRc7hyzYLccQKZd
606 lines
19 KiB
CSS
606 lines
19 KiB
CSS
@import "tailwindcss";
|
||
|
||
/* Petal design tokens — soft, warm, bubbly stationery aesthetic.
|
||
Defined in @theme so they generate Tailwind utilities (bg-bg, text-plum,
|
||
rounded-card, font-ui, etc.). See petal-spec.md → Design System. */
|
||
@theme {
|
||
/* Palette */
|
||
--color-bg: #FDF6F0; /* warm cream canvas */
|
||
--color-surface: #FFFFFF; /* card/panel surfaces */
|
||
--color-surface-alt: #FFF0F5; /* rose-tinted alt surface */
|
||
--color-border: #F0E0EB; /* soft pink-grey border */
|
||
--color-plum: #3D2E39; /* warm dark plum text (not harsh black) */
|
||
--color-muted: #9B8CA3; /* muted lavender-grey */
|
||
--color-accent: #E8A0BF; /* soft rose — primary interactive */
|
||
--color-accent-hover: #D98AAF;/* deeper rose on hover */
|
||
|
||
/* Suggestion type colors */
|
||
--color-mint: #A8D8C8; /* grammar */
|
||
--color-peach: #F4B8A0; /* phrasing */
|
||
--color-lavender: #C5B4E8; /* idiom */
|
||
--color-sky: #A8CCE8; /* clarity */
|
||
--color-honey: #CE9B4F; /* voice */
|
||
--color-success: #8FCFA8; /* saved / accepted */
|
||
|
||
/* Typography */
|
||
--font-ui: "Nunito", "PingFang SC", "Microsoft YaHei", "Noto Sans CJK SC", sans-serif;
|
||
--font-body: "Lora", Georgia, serif;
|
||
--font-mono: "JetBrains Mono", ui-monospace, monospace;
|
||
|
||
/* Shape language */
|
||
--radius-card: 16px;
|
||
--radius-modal: 24px;
|
||
--radius-pill: 999px;
|
||
--radius-input: 12px;
|
||
|
||
/* Soft, warm, lifted shadow */
|
||
--shadow-soft: 0 4px 20px rgba(180, 130, 160, 0.12);
|
||
}
|
||
|
||
html, body, #root {
|
||
height: 100%;
|
||
}
|
||
|
||
body {
|
||
margin: 0;
|
||
background: var(--color-bg);
|
||
color: var(--color-plum);
|
||
font-family: var(--font-ui);
|
||
-webkit-font-smoothing: antialiased;
|
||
}
|
||
|
||
/* Gentle, consistent motion across interactive elements */
|
||
button, a, input {
|
||
transition: all 200ms ease;
|
||
}
|
||
|
||
/* Editor body — serif Lora for prose, warm plum ink, roomy line height. The
|
||
title and headings use the Nunito UI face for contrast. */
|
||
.petal-prose {
|
||
font-family: var(--font-body);
|
||
font-size: 1.125rem;
|
||
line-height: 1.75;
|
||
color: var(--color-plum);
|
||
}
|
||
.petal-prose > * + * {
|
||
margin-top: 0.9em;
|
||
}
|
||
.petal-prose h1,
|
||
.petal-prose h2,
|
||
.petal-prose h3 {
|
||
font-family: var(--font-ui);
|
||
font-weight: 800;
|
||
line-height: 1.3;
|
||
}
|
||
.petal-prose h1 { font-size: 1.6em; }
|
||
.petal-prose h2 { font-size: 1.3em; }
|
||
.petal-prose h3 { font-size: 1.1em; }
|
||
.petal-prose ul,
|
||
.petal-prose ol {
|
||
padding-left: 1.4em;
|
||
}
|
||
.petal-prose ul { list-style: disc; }
|
||
.petal-prose ol { list-style: decimal; }
|
||
.petal-prose a {
|
||
color: var(--color-accent-hover);
|
||
text-decoration: underline;
|
||
}
|
||
.petal-prose blockquote {
|
||
border-left: 3px solid var(--color-border);
|
||
padding-left: 1em;
|
||
color: var(--color-muted);
|
||
font-style: italic;
|
||
}
|
||
.petal-prose code {
|
||
font-family: var(--font-mono);
|
||
font-size: 0.9em;
|
||
background: var(--color-surface-alt);
|
||
padding: 0.1em 0.35em;
|
||
border-radius: 6px;
|
||
}
|
||
/* Top formatting bar: a single line at rest so it stays slim, expanding to
|
||
reveal every control on hover (or while a control inside it has focus, e.g.
|
||
the link input or an open popover). The clipped right edge fades out as a hint
|
||
that more is available. */
|
||
.petal-toolbar {
|
||
flex-wrap: nowrap;
|
||
overflow: hidden;
|
||
max-width: 100%;
|
||
-webkit-mask-image: linear-gradient(to right, #000 90%, transparent 100%);
|
||
mask-image: linear-gradient(to right, #000 90%, transparent 100%);
|
||
}
|
||
.petal-toolbar:hover,
|
||
.petal-toolbar:focus-within {
|
||
flex-wrap: wrap;
|
||
overflow: visible;
|
||
-webkit-mask-image: none;
|
||
mask-image: none;
|
||
}
|
||
|
||
/* Highlighter mark — inline background swatch behind the text. */
|
||
.petal-prose mark {
|
||
border-radius: 4px;
|
||
padding: 0.05em 0.15em;
|
||
/* color comes from the inline style the Highlight extension writes */
|
||
}
|
||
/* Inserted images: rounded, soft-shadowed, never wider than the column. The
|
||
selected-node ring matches the rest of the rose theme. Scoped to the editor's
|
||
own <img> (not a class) since Tiptap doesn't always carry the configured
|
||
class through to the rendered node. */
|
||
.petal-prose img {
|
||
max-width: 100%;
|
||
height: auto;
|
||
border-radius: var(--radius-card);
|
||
box-shadow: var(--shadow-soft);
|
||
}
|
||
.petal-prose img.ProseMirror-selectednode {
|
||
outline: 2px solid var(--color-accent);
|
||
outline-offset: 2px;
|
||
}
|
||
/* Tables: soft pink grid, rounded outer corners, a tinted header row. Targeted
|
||
by element within the editor — Tiptap renders the <table> without our
|
||
configured class, so a `.petal-table` selector would never match. The wrapper
|
||
Tiptap adds (.tableWrapper) handles horizontal overflow scroll. */
|
||
.petal-prose .tableWrapper {
|
||
overflow-x: auto;
|
||
}
|
||
.petal-prose table {
|
||
border-collapse: collapse;
|
||
width: 100%;
|
||
margin: 0.4em 0;
|
||
overflow: hidden;
|
||
border-radius: var(--radius-input);
|
||
border: 1px solid var(--color-border);
|
||
table-layout: fixed;
|
||
}
|
||
.petal-prose td,
|
||
.petal-prose th {
|
||
border: 1px solid var(--color-border);
|
||
padding: 0.4em 0.6em;
|
||
vertical-align: top;
|
||
position: relative;
|
||
min-width: 3em;
|
||
}
|
||
.petal-prose th {
|
||
background: var(--color-surface-alt);
|
||
font-weight: 700;
|
||
text-align: left;
|
||
}
|
||
/* The cell being edited / the active selection inside a table. */
|
||
.petal-prose .selectedCell::after {
|
||
content: '';
|
||
position: absolute;
|
||
inset: 0;
|
||
background: var(--color-surface-alt);
|
||
opacity: 0.5;
|
||
pointer-events: none;
|
||
}
|
||
/* The column-resize handle Tiptap draws between columns. */
|
||
.petal-prose .column-resize-handle {
|
||
position: absolute;
|
||
right: -2px;
|
||
top: 0;
|
||
bottom: -2px;
|
||
width: 4px;
|
||
background: var(--color-accent);
|
||
pointer-events: none;
|
||
}
|
||
/* Placeholder shown on the empty first paragraph (Tiptap Placeholder ext). */
|
||
.petal-prose p.is-editor-empty:first-child::before {
|
||
content: attr(data-placeholder);
|
||
color: var(--color-muted);
|
||
float: left;
|
||
height: 0;
|
||
pointer-events: none;
|
||
}
|
||
|
||
/* --- Suggestion decorations -------------------------------------------------
|
||
Inline highlights anchored by string at render time (not stored marks). Each
|
||
type gets a soft underline in its palette color; hovering opens its card. */
|
||
.petal-suggestion {
|
||
border-bottom: 2px solid transparent;
|
||
border-radius: 2px;
|
||
cursor: pointer;
|
||
transition: background 200ms ease;
|
||
/* gentle fade + slight upward float as decorations appear */
|
||
animation: petal-suggestion-in 260ms ease both;
|
||
}
|
||
.petal-suggestion:hover {
|
||
background: var(--color-surface-alt);
|
||
}
|
||
.petal-suggestion-grammar { border-bottom-color: var(--color-mint); }
|
||
.petal-suggestion-phrasing { border-bottom-color: var(--color-peach); }
|
||
.petal-suggestion-idiom { border-bottom-color: var(--color-lavender); }
|
||
.petal-suggestion-clarity { border-bottom-color: var(--color-sky); }
|
||
.petal-suggestion-voice { border-bottom-color: var(--color-honey); }
|
||
|
||
@keyframes petal-suggestion-in {
|
||
from { opacity: 0; transform: translateY(4px); }
|
||
to { opacity: 1; transform: translateY(0); }
|
||
}
|
||
|
||
.petal-suggestion-card {
|
||
animation: petal-suggestion-in 200ms ease both;
|
||
}
|
||
|
||
/* Text emphasized from its margin card (or a hover) — a soft wash so the
|
||
card↔text link reads at a glance, both directions. */
|
||
.petal-suggestion-active {
|
||
background: var(--color-surface-alt);
|
||
box-shadow: 0 0 0 3px var(--color-surface-alt);
|
||
border-radius: 3px;
|
||
}
|
||
|
||
/* --- Suggestion margin rail -------------------------------------------------
|
||
The right-hand "comment column": every outstanding suggestion as a card,
|
||
vertically aligned to the text it flags, so the whole queue is visible at a
|
||
glance instead of one-highlight-at-a-time on hover. It floats in the whitespace
|
||
just right of the editor column and is only mounted when there's room for it
|
||
(EditorCore measures the gap). Cards are absolutely positioned by a resolved
|
||
top (anchor + collision avoidance), so the container only anchors the column. */
|
||
.petal-rail {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 100%;
|
||
margin-left: 32px;
|
||
width: 300px;
|
||
/* Below the companion mascot (z-40): where a stacked card reaches the
|
||
bottom-right corner it simply tucks behind the sleeping cat. */
|
||
z-index: 10;
|
||
}
|
||
.petal-rail-card {
|
||
position: absolute;
|
||
left: 0;
|
||
right: 0;
|
||
background: var(--color-surface);
|
||
border: 1px solid var(--color-border);
|
||
border-left: 3px solid var(--color-border); /* type color set inline */
|
||
border-radius: var(--radius-card);
|
||
box-shadow: var(--shadow-soft);
|
||
padding: 0.7rem 0.85rem;
|
||
/* `top` eases so re-stacking (accept/dismiss/edit) glides instead of jumping.
|
||
The entrance uses fill `backwards` so its translateY doesn't linger and fight
|
||
the active-state transform once it's done. */
|
||
transition: top 240ms cubic-bezier(0.2, 0.7, 0.3, 1), box-shadow 200ms ease,
|
||
transform 200ms ease, border-color 200ms ease;
|
||
animation: petal-suggestion-in 220ms ease backwards;
|
||
}
|
||
.petal-rail-card-active {
|
||
transform: translateX(-5px);
|
||
box-shadow: 0 8px 26px rgba(180, 130, 160, 0.24);
|
||
border-top-color: var(--color-accent);
|
||
border-right-color: var(--color-accent);
|
||
border-bottom-color: var(--color-accent);
|
||
}
|
||
.petal-rail-x {
|
||
color: var(--color-muted);
|
||
font-size: 0.72rem;
|
||
line-height: 1;
|
||
padding: 2px 5px;
|
||
border-radius: var(--radius-pill);
|
||
}
|
||
.petal-rail-x:hover {
|
||
background: var(--color-surface-alt);
|
||
color: var(--color-plum);
|
||
}
|
||
|
||
/* --- Find & Replace ---------------------------------------------------------
|
||
In-document search (Ctrl/Cmd+F). Every match gets a soft honey wash; the
|
||
current match is brighter with a rose ring so it stands out as you step
|
||
through. Decorations, like every other highlight layer here. */
|
||
.petal-find-match {
|
||
background: var(--color-highlight, #fff1a8);
|
||
border-radius: 3px;
|
||
box-shadow: 0 0 0 1px var(--color-border);
|
||
}
|
||
.petal-find-match-active {
|
||
background: var(--color-peach);
|
||
box-shadow: 0 0 0 2px var(--color-accent);
|
||
}
|
||
|
||
/* --- Spell check ------------------------------------------------------------
|
||
Browser-side nspell flags misspellings with a soft rose wavy underline (a
|
||
gentler take on the classic red squiggle, to fit the pastel palette). Like the
|
||
suggestion layer these are ProseMirror decorations, never stored marks.
|
||
Clicking a flagged word opens its MisspellCard with corrections. */
|
||
.petal-misspelling {
|
||
cursor: pointer;
|
||
text-decoration: underline wavy var(--color-accent);
|
||
text-decoration-skip-ink: none;
|
||
text-underline-offset: 2px;
|
||
}
|
||
.petal-misspelling:hover {
|
||
background: var(--color-surface-alt);
|
||
border-radius: 2px;
|
||
}
|
||
|
||
.petal-misspell-card {
|
||
animation: petal-suggestion-in 200ms ease both;
|
||
}
|
||
|
||
/* --- Word lookup popover ----------------------------------------------------
|
||
Right-click a word for its dictionary definition and synonyms. Same soft card
|
||
treatment as the spelling popover; synonym pills swap the word on click. */
|
||
.petal-word-card {
|
||
animation: petal-suggestion-in 200ms ease both;
|
||
}
|
||
|
||
/* --- ESL superpowers (Phase 9) ----------------------------------------------
|
||
Inline Chinese gloss on hover (a small dark tooltip under the word), and the
|
||
selection rewrite bubble + its preview card. All share the soft pop-in. The
|
||
gloss tip fades in a touch faster — it's a fleeting reading aid, not a panel. */
|
||
.petal-gloss-tip {
|
||
animation: petal-suggestion-in 140ms ease both;
|
||
}
|
||
.petal-selection-bubble,
|
||
.petal-rewrite-card {
|
||
animation: petal-suggestion-in 200ms ease both;
|
||
}
|
||
|
||
/* --- Accept confetti --------------------------------------------------------
|
||
A tiny CSS-only burst played where a suggestion is accepted: four colored
|
||
dots spray up-and-out, then fade. No JS animation — each dot reads its
|
||
direction from --dx/--dy custom properties set inline. (Spec → Signature.) */
|
||
.petal-confetti {
|
||
width: 0;
|
||
height: 0;
|
||
}
|
||
.petal-confetti-dot {
|
||
position: absolute;
|
||
left: 0;
|
||
top: 0;
|
||
width: 7px;
|
||
height: 7px;
|
||
border-radius: var(--radius-pill);
|
||
animation: petal-confetti 680ms cubic-bezier(0.2, 0.7, 0.3, 1) forwards;
|
||
}
|
||
@keyframes petal-confetti {
|
||
0% { transform: translate(0, 0) scale(0.3); opacity: 0; }
|
||
18% { opacity: 1; }
|
||
100% { transform: translate(var(--dx), var(--dy)) scale(1); opacity: 0; }
|
||
}
|
||
|
||
/* --- Distraction-free mode ---------------------------------------------------
|
||
The doc-list sidebar slides left and collapses to zero width; the editor
|
||
canvas (centered, max-width) re-centers into the full pane. Width + transform
|
||
animate together for a smooth slide. (Spec → Distraction-free mode.) */
|
||
.petal-sidebar {
|
||
width: 260px;
|
||
overflow: hidden;
|
||
transition: width 280ms ease, transform 280ms ease, opacity 200ms ease;
|
||
}
|
||
.petal-sidebar-hidden {
|
||
width: 0;
|
||
transform: translateX(-24px);
|
||
opacity: 0;
|
||
pointer-events: none;
|
||
}
|
||
|
||
/* --- Companion kitten -------------------------------------------------------
|
||
The cozy corner mascot. Gently bobs while awake, settles and sways slowly
|
||
while napping; its speech bubble pops in; little zzz drift up when asleep. */
|
||
.petal-companion {
|
||
/* Mascot size scales with the viewport width: ~original on a laptop, up to
|
||
~2× on a large desktop. Tune the middle (vw) term to taste. */
|
||
--petal-companion-size: clamp(10rem, 17vw, 20rem);
|
||
animation: petal-bob 3.2s ease-in-out infinite;
|
||
transition: transform 200ms ease;
|
||
}
|
||
/* The Lottie art sits inside the round badge with a little breathing room. */
|
||
.petal-companion-art {
|
||
width: 88%;
|
||
height: 88%;
|
||
}
|
||
.petal-companion:hover {
|
||
transform: translateY(-2px) scale(1.04);
|
||
}
|
||
.petal-companion-sleep {
|
||
animation: petal-bob-slow 5s ease-in-out infinite;
|
||
}
|
||
@keyframes petal-bob {
|
||
0%, 100% { transform: translateY(0); }
|
||
50% { transform: translateY(-4px); }
|
||
}
|
||
@keyframes petal-bob-slow {
|
||
0%, 100% { transform: translateY(0) rotate(-1deg); }
|
||
50% { transform: translateY(-2px) rotate(1deg); }
|
||
}
|
||
|
||
.petal-bubble {
|
||
animation: petal-bubble-in 240ms cubic-bezier(0.2, 0.8, 0.3, 1.2) both;
|
||
transform-origin: bottom right;
|
||
}
|
||
@keyframes petal-bubble-in {
|
||
from { opacity: 0; transform: translateY(6px) scale(0.92); }
|
||
to { opacity: 1; transform: translateY(0) scale(1); }
|
||
}
|
||
|
||
.petal-zzz {
|
||
top: calc(var(--petal-companion-size) * 0.04);
|
||
right: calc(var(--petal-companion-size) * 0.1);
|
||
font-weight: 800;
|
||
font-size: calc(var(--petal-companion-size) * 0.12);
|
||
animation: petal-zzz 2.4s ease-in-out infinite;
|
||
}
|
||
@keyframes petal-zzz {
|
||
0% { opacity: 0; transform: translateY(0) scale(0.8); }
|
||
30% { opacity: 0.9; }
|
||
100% { opacity: 0; transform: translateY(-14px) scale(1.1); }
|
||
}
|
||
|
||
/* "New version available" banner — drifts down from the top like a petal. */
|
||
.petal-update {
|
||
animation: petal-drop 360ms cubic-bezier(0.2, 0.8, 0.3, 1.2) both;
|
||
}
|
||
@keyframes petal-drop {
|
||
from { opacity: 0; transform: translateY(-14px) scale(0.96); }
|
||
to { opacity: 1; transform: translateY(0) scale(1); }
|
||
}
|
||
|
||
/* Blinking caret in the Ask Petal bubble while awaiting the first token. */
|
||
.petal-chat-caret {
|
||
animation: petal-breathe 1s ease-in-out infinite;
|
||
color: var(--color-accent);
|
||
}
|
||
|
||
/* Breathing rose dot shown in the StatusBar while a checkpoint runs. */
|
||
.petal-checkpoint-dot {
|
||
animation: petal-breathe 2s ease-in-out infinite;
|
||
}
|
||
@keyframes petal-breathe {
|
||
0%, 100% { opacity: 0.4; }
|
||
50% { opacity: 1; }
|
||
}
|
||
|
||
/* --- Organization & search (Phase 10) --------------------------------------
|
||
Tag chips, the search results list, and per-row affordances. The row actions
|
||
(tag / delete) fade in on hover for pointer users but are always visible on
|
||
touch (no hover) — see the coarse-pointer block below. */
|
||
.petal-tag-chip {
|
||
transition: background 160ms ease, color 160ms ease, transform 160ms ease;
|
||
}
|
||
.petal-search-results {
|
||
animation: petal-suggestion-in 160ms ease both;
|
||
}
|
||
.petal-tag-picker {
|
||
animation: petal-suggestion-in 160ms ease both;
|
||
}
|
||
.petal-row-action {
|
||
opacity: 0;
|
||
transition: opacity 160ms ease, background 160ms ease;
|
||
}
|
||
.group:hover .petal-row-action,
|
||
.petal-row-action:focus-visible {
|
||
opacity: 1;
|
||
}
|
||
.petal-row-action:hover {
|
||
background: var(--color-surface-alt);
|
||
}
|
||
/* Clamp a search snippet to two lines. */
|
||
.line-clamp-2 {
|
||
display: -webkit-box;
|
||
-webkit-line-clamp: 2;
|
||
line-clamp: 2;
|
||
-webkit-box-orient: vertical;
|
||
overflow: hidden;
|
||
}
|
||
|
||
/* --- Touch & tablet polish --------------------------------------------------
|
||
On coarse pointers (tablets, phones) there's no hover, so make tap targets
|
||
comfortable and reveal affordances that would otherwise be hover-only. */
|
||
@media (pointer: coarse) {
|
||
.petal-tap {
|
||
min-height: 44px;
|
||
}
|
||
.petal-tap-sm {
|
||
min-height: 36px;
|
||
}
|
||
/* Row actions can't rely on hover — keep them visible and roomy. */
|
||
.petal-row-action {
|
||
opacity: 1;
|
||
height: 36px;
|
||
width: 36px;
|
||
}
|
||
/* Bigger, easier-to-hit suggestion/word/tag pills. */
|
||
.petal-tag-chip {
|
||
padding-top: 0.25rem;
|
||
padding-bottom: 0.25rem;
|
||
}
|
||
}
|
||
|
||
/* --- Responsive sidebar (narrow screens) ------------------------------------
|
||
Below the tablet breakpoint the sidebar becomes an overlay drawer toggled by a
|
||
hamburger in the header, instead of a permanent column. A scrim sits behind it.
|
||
On wide screens the toggle + scrim are hidden and the sidebar is in-flow. */
|
||
.petal-sidebar-toggle {
|
||
display: none;
|
||
}
|
||
.petal-scrim {
|
||
display: none;
|
||
}
|
||
@media (max-width: 768px) {
|
||
.petal-sidebar-toggle {
|
||
display: inline-flex;
|
||
}
|
||
.petal-sidebar {
|
||
position: fixed;
|
||
top: 48px; /* below the 12-height header */
|
||
bottom: 0;
|
||
left: 0;
|
||
z-index: 30;
|
||
background: var(--color-bg);
|
||
box-shadow: var(--shadow-soft);
|
||
}
|
||
/* On mobile the sidebar is hidden by default; the drawer-open class slides it
|
||
in. (Distraction-free's petal-sidebar-hidden still wins to keep it closed.) */
|
||
.petal-sidebar:not(.petal-drawer-open) {
|
||
width: 0;
|
||
transform: translateX(-24px);
|
||
opacity: 0;
|
||
pointer-events: none;
|
||
}
|
||
.petal-scrim.petal-scrim-show {
|
||
display: block;
|
||
position: fixed;
|
||
inset: 48px 0 0 0;
|
||
z-index: 20;
|
||
background: rgba(61, 46, 57, 0.18);
|
||
}
|
||
}
|
||
|
||
/* Print / Save-as-PDF: strip every bit of app chrome and editing decoration so
|
||
only the title and the writing itself reach the page. This is Petal's PDF
|
||
path — it uses the browser's own fonts, so CJK renders correctly with no
|
||
server-side font embedding. */
|
||
/* --- Ambient falling petals -------------------------------------------------
|
||
The WebGL petal layer is a fixed, non-interactive overlay that drifts soft
|
||
blossoms over the page. Kept gentle (low opacity) so it never competes with
|
||
the writing. It hides itself in print and is skipped entirely for users who
|
||
prefer reduced motion (the component renders nothing in that case). */
|
||
.petal-fall {
|
||
opacity: 1;
|
||
}
|
||
|
||
/* Honor reduced-motion globally: still the looping ambient animations and drop
|
||
the petal layer. One-shot entrance/feedback animations are left intact. */
|
||
@media (prefers-reduced-motion: reduce) {
|
||
.petal-fall {
|
||
display: none !important;
|
||
}
|
||
.petal-bob,
|
||
.petal-bob-slow,
|
||
.petal-zzz,
|
||
.petal-checkpoint-dot {
|
||
animation: none !important;
|
||
}
|
||
}
|
||
|
||
@media print {
|
||
.petal-fall,
|
||
.petal-no-print,
|
||
.petal-sidebar,
|
||
.petal-suggestion-card,
|
||
.petal-misspell-card,
|
||
.petal-gloss-tip,
|
||
.petal-selection-bubble,
|
||
.petal-rewrite-card,
|
||
.petal-confetti,
|
||
.petal-companion {
|
||
display: none !important;
|
||
}
|
||
html, body, #root {
|
||
height: auto !important;
|
||
overflow: visible !important;
|
||
background: #fff !important;
|
||
}
|
||
/* Drop the in-editor highlight underlines/tints — they're guidance, not ink. */
|
||
.petal-suggestion,
|
||
.petal-misspelling {
|
||
background: none !important;
|
||
text-decoration: none !important;
|
||
border-bottom: none !important;
|
||
}
|
||
/* Let the writing use the full page width. */
|
||
.max-w-\[720px\] { max-width: none !important; }
|
||
}
|