initial commit
This commit is contained in:
@@ -45,24 +45,32 @@
|
||||
}
|
||||
|
||||
.dai-root {
|
||||
--dai-accent: #C8102E;
|
||||
/* Brand accent — resolves to the app's accent token, which is black
|
||||
(root CLAUDE.md §6.2: "the brand is black", one accent only). Send
|
||||
button, active states and the trigger all read from this single
|
||||
variable, so switching the assistant to Doormile red is a one-line
|
||||
change here rather than a hunt through the components. */
|
||||
--dai-accent: var(--color-accent, #0f172a);
|
||||
--dai-accent-contrast: #ffffff;
|
||||
--dai-accent-ring: rgba(200, 16, 46, 0.16);
|
||||
/* Focus ring, tinted with the accent rather than a flat grey wash. */
|
||||
--dai-accent-ring: color-mix(in srgb, var(--dai-accent) 14%, transparent);
|
||||
|
||||
--dai-ai-from: #C8102E;
|
||||
--dai-ai-to: #E11D48;
|
||||
--dai-ai-glow: rgba(200, 16, 46, 0.15);
|
||||
/* AI identity accent — used ONLY on the spark/orb marks so the assistant
|
||||
reads as an AI surface without turning the panel into a purple product. */
|
||||
--dai-ai-from: #6366f1;
|
||||
--dai-ai-to: #8b5cf6;
|
||||
--dai-ai-glow: rgba(99, 102, 241, 0.18);
|
||||
|
||||
--dai-text: #0f172a;
|
||||
--dai-text-secondary: #475569;
|
||||
--dai-text-secondary: #64748b;
|
||||
--dai-text-muted: #94a3b8;
|
||||
--dai-surface: #ffffff;
|
||||
--dai-surface-alt: #f8fafc;
|
||||
--dai-surface-hover: #f1f5f9;
|
||||
--dai-border: #e2e8f0;
|
||||
--dai-border-strong: #cbd5e1;
|
||||
--dai-border: rgba(15, 23, 42, 0.08);
|
||||
--dai-border-strong: rgba(15, 23, 42, 0.14);
|
||||
--dai-scrim: rgba(15, 23, 42, 0.08);
|
||||
--dai-shadow: -6px 0 24px rgba(15, 23, 42, 0.06);
|
||||
--dai-shadow: 0 8px 30px rgba(15, 23, 42, 0.1);
|
||||
--dai-live: #10b981;
|
||||
|
||||
--dai-panel-width: 428px;
|
||||
@@ -109,22 +117,16 @@
|
||||
No radius and no drop shadow: both are what make a surface read as floating
|
||||
ABOVE the page. A soft shadow is kept only as a left-edge falloff so the
|
||||
seam has depth without the panel detaching. */
|
||||
/* Two classes, not one: the element is a shadcn SheetContent, which carries
|
||||
`inset-y-0 h-full` from Tailwind. Those utilities are emitted after this
|
||||
stylesheet, so a single `.dai-panel` ties on specificity and loses — the
|
||||
dock then starts at y=0 and covers the top nav it is supposed to sit under.
|
||||
`.dai-root.dai-panel` out-specifies them; `height: auto` hands the box back
|
||||
to top/bottom so it cannot run past the bottom of the window. */
|
||||
.dai-root.dai-panel {
|
||||
.dai-panel {
|
||||
position: fixed;
|
||||
/* Measured from the app header by AIPanel — see the [data-app-header] hook. */
|
||||
/* Set from JS by AIPanel — Astryx does not publish a header-height token,
|
||||
despite --appshell-header-height looking like one. */
|
||||
top: var(--dai-dock-top, 57px);
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
height: auto;
|
||||
z-index: 1200;
|
||||
width: var(--dai-dock-width);
|
||||
display: none;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
@@ -138,20 +140,13 @@
|
||||
transform var(--dai-duration) var(--dai-ease),
|
||||
visibility 0s linear var(--dai-duration);
|
||||
}
|
||||
|
||||
.dai-panel[data-state='open'],
|
||||
.dai-panel[data-open='true'] {
|
||||
display: flex !important;
|
||||
transform: translateX(0);
|
||||
visibility: visible;
|
||||
transition:
|
||||
transform var(--dai-duration) var(--dai-ease),
|
||||
visibility 0s;
|
||||
}
|
||||
.dai-panel[data-state='closed'],
|
||||
.dai-panel[data-open='false'] {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* ---- The page makes room -------------------------------------------------
|
||||
`.dai-docked` is set on <body> while the panel is open. Padding rather than
|
||||
@@ -162,10 +157,10 @@
|
||||
The transition sits on the container unconditionally so the page slides back
|
||||
when the panel closes too — a rule that only exists while `.dai-docked` is
|
||||
applied cannot animate its own removal. */
|
||||
.dai-page {
|
||||
.astryx-layout-content {
|
||||
transition: padding-right var(--dai-duration) var(--dai-ease);
|
||||
}
|
||||
body.dai-docked .dai-page {
|
||||
body.dai-docked .astryx-layout-content {
|
||||
padding-right: var(--dai-dock-width);
|
||||
}
|
||||
|
||||
@@ -174,7 +169,7 @@ body.dai-docked .dai-page {
|
||||
used to be everywhere — a full-width overlay with a scrim — and the page
|
||||
stops reserving a strip it cannot afford. */
|
||||
@media (max-width: 900px) {
|
||||
.dai-root.dai-panel {
|
||||
.dai-panel {
|
||||
top: 0;
|
||||
width: 100%;
|
||||
z-index: 1301;
|
||||
@@ -187,7 +182,7 @@ body.dai-docked .dai-page {
|
||||
.dai-scrim[data-open='true'] {
|
||||
opacity: 1;
|
||||
}
|
||||
body.dai-docked .dai-page {
|
||||
body.dai-docked .astryx-layout-content {
|
||||
padding-right: 0;
|
||||
}
|
||||
}
|
||||
@@ -199,59 +194,67 @@ body.dai-docked .dai-page {
|
||||
-------------------------------------------------------------------------- */
|
||||
.dai-root .dai-header {
|
||||
flex: 0 0 auto;
|
||||
padding: 14px 16px 12px;
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
backdrop-filter: blur(12px);
|
||||
padding: 14px 12px 12px 14px;
|
||||
border-bottom: 1px solid var(--dai-border);
|
||||
}
|
||||
.dai-root .dai-title {
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
font-weight: 650;
|
||||
line-height: 1.2;
|
||||
letter-spacing: -0.01em;
|
||||
color: var(--dai-text);
|
||||
}
|
||||
.dai-root .dai-subtitle {
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
line-height: 1.3;
|
||||
color: var(--dai-text-muted);
|
||||
}
|
||||
/* The AI mark — sleek rounded tinted container */
|
||||
/* The AI mark. A soft gradient orb — not a robot face. */
|
||||
.dai-root .dai-spark {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex: 0 0 auto;
|
||||
border-radius: 9px;
|
||||
background: #fff1f2;
|
||||
border: 1px solid #fecdd3;
|
||||
border-radius: 999px;
|
||||
background: var(--dai-surface);
|
||||
overflow: hidden;
|
||||
}
|
||||
/* The mark's own canvas is only 66.8% content — a third of every edge is
|
||||
transparent padding, measured off the PNG's alpha bounding box (x and y both
|
||||
170..853 of 1024, i.e. perfectly centred). Drawing it at 100% therefore
|
||||
rendered a D two-thirds the size the box implied, which is exactly why it
|
||||
read as too small. 150% cancels that padding so the D fills its box edge to
|
||||
edge; the overflow:hidden above clips only transparent pixels. */
|
||||
.dai-root .dai-spark img {
|
||||
width: 150%;
|
||||
height: 150%;
|
||||
max-width: none;
|
||||
object-fit: contain;
|
||||
display: block;
|
||||
}
|
||||
.dai-root .dai-spark[data-size='sm'] {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
.dai-root .dai-spark[data-size='md'] {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
.dai-root .dai-spark[data-size='lg'] {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
}
|
||||
/* Live indicator — crisp pill */
|
||||
/* Live indicator — subtle, not a large pill. */
|
||||
.dai-root .dai-live {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
padding: 3px 9px;
|
||||
padding: 3px 8px;
|
||||
border-radius: 999px;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
font-weight: 550;
|
||||
color: #047857;
|
||||
background: #ecfdf5;
|
||||
border: 1px solid #a7f3d0;
|
||||
background: rgba(16, 185, 129, 0.08);
|
||||
white-space: nowrap;
|
||||
}
|
||||
.dai-root .dai-live-dot {
|
||||
@@ -275,10 +278,9 @@ body.dai-docked .dai-page {
|
||||
/* Page-context strip — "Orders · Today · All locations" */
|
||||
.dai-root .dai-context {
|
||||
flex: 0 0 auto;
|
||||
padding: 8px 16px;
|
||||
padding: 7px 14px;
|
||||
font-size: 11.5px;
|
||||
font-weight: 500;
|
||||
color: var(--dai-text-secondary);
|
||||
color: var(--dai-text-muted);
|
||||
background: var(--dai-surface-alt);
|
||||
border-bottom: 1px solid var(--dai-border);
|
||||
white-space: nowrap;
|
||||
@@ -367,31 +369,34 @@ body.dai-docked .dai-page {
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
max-width: 100%;
|
||||
padding: 6px 14px;
|
||||
padding: 5px 10px;
|
||||
text-align: left;
|
||||
font: inherit;
|
||||
font-size: 12px;
|
||||
line-height: 1.35;
|
||||
font-weight: 550;
|
||||
font-weight: 500;
|
||||
color: var(--dai-text);
|
||||
background: var(--dai-surface);
|
||||
border: 1px solid var(--dai-border);
|
||||
border-radius: 999px;
|
||||
box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
|
||||
/* 14px, pinned — NOT 999px.
|
||||
|
||||
On a one-line chip a fully round radius already resolves to about 14px, so
|
||||
these look identical. The difference shows on a chip whose question wraps
|
||||
to two lines: 999px would resolve to half of ~46px and the chip stops
|
||||
reading as a chip and starts reading as a card, so one long suggestion
|
||||
would look like a different component from the nineteen beside it. */
|
||||
border-radius: 14px;
|
||||
cursor: pointer;
|
||||
transition:
|
||||
background-color 140ms ease,
|
||||
border-color 140ms ease,
|
||||
color 140ms ease,
|
||||
transform 140ms ease,
|
||||
box-shadow 140ms ease;
|
||||
transform 140ms ease;
|
||||
}
|
||||
.dai-suggestion:hover {
|
||||
background: #fff1f2;
|
||||
border-color: #fecdd3;
|
||||
color: #C8102E;
|
||||
background: var(--dai-surface-alt);
|
||||
border-color: var(--dai-border-strong);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 2px 6px rgba(200, 16, 46, 0.1);
|
||||
}
|
||||
.dai-suggestion:active {
|
||||
transform: translateY(0);
|
||||
@@ -406,7 +411,7 @@ body.dai-docked .dai-page {
|
||||
transition: color 140ms ease;
|
||||
}
|
||||
.dai-suggestion:hover .dai-suggestion-icon {
|
||||
color: #C8102E;
|
||||
color: var(--dai-text-secondary);
|
||||
}
|
||||
.dai-root .dai-suggestion-text {
|
||||
min-width: 0;
|
||||
@@ -497,32 +502,22 @@ body.dai-docked .dai-page {
|
||||
}
|
||||
|
||||
.dai-root .dai-msg-user {
|
||||
max-width: 84%;
|
||||
max-width: 82%;
|
||||
margin-left: auto;
|
||||
padding: 10px 15px;
|
||||
border-radius: 18px 18px 4px 18px;
|
||||
padding: 8px 12px;
|
||||
border-radius: 5px;
|
||||
border-bottom-right-radius: 5px;
|
||||
font-size: 13.5px;
|
||||
font-weight: 500;
|
||||
line-height: 1.45;
|
||||
color: #ffffff;
|
||||
background: linear-gradient(135deg, #C8102E 0%, #A00C24 100%);
|
||||
box-shadow: 0 2px 8px rgba(200, 16, 46, 0.16);
|
||||
color: var(--dai-accent-contrast);
|
||||
background: var(--dai-accent);
|
||||
white-space: pre-wrap;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
/* Assistant — sleek rounded response card */
|
||||
.dai-root .dai-msg-row {
|
||||
background: #f8fafc;
|
||||
border: 1px solid var(--dai-border);
|
||||
border-radius: 18px 18px 18px 4px;
|
||||
padding: 12px 14px;
|
||||
box-shadow: 0 1px 3px rgba(15, 23, 42, 0.03);
|
||||
max-width: 95%;
|
||||
width: fit-content;
|
||||
}
|
||||
/* Assistant — no bubble. Text sits on the panel surface. */
|
||||
.dai-root .dai-msg-ai {
|
||||
font-size: 13.5px;
|
||||
line-height: 1.55;
|
||||
line-height: 1.5;
|
||||
color: var(--dai-text);
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
@@ -534,8 +529,8 @@ body.dai-docked .dai-page {
|
||||
}
|
||||
.dai-root .dai-msg-name {
|
||||
font-size: 11.5px;
|
||||
font-weight: 700;
|
||||
color: #334155;
|
||||
font-weight: 600;
|
||||
color: var(--dai-text-secondary);
|
||||
}
|
||||
.dai-root .dai-msg-footer {
|
||||
font-size: 11px;
|
||||
@@ -700,23 +695,24 @@ body.dai-docked .dai-page {
|
||||
-------------------------------------------------------------------------- */
|
||||
.dai-root .dai-composer-wrap {
|
||||
flex: 0 0 auto;
|
||||
padding: 12px 14px calc(12px + env(safe-area-inset-bottom, 0px));
|
||||
padding: 10px 12px calc(10px + env(safe-area-inset-bottom, 0px));
|
||||
border-top: 1px solid var(--dai-border);
|
||||
background: var(--dai-surface);
|
||||
}
|
||||
.dai-root .dai-composer {
|
||||
border: 1.5px solid var(--dai-border);
|
||||
border-radius: 16px;
|
||||
background: var(--dai-surface-alt);
|
||||
border: 1px solid var(--dai-border-strong);
|
||||
/* 14px, the same corner the suggestion chips use. At 5px the input was the
|
||||
one sharp-cornered thing in a panel of rounded surfaces, and it sat
|
||||
directly beneath the chips where the mismatch was most visible. */
|
||||
border-radius: 14px;
|
||||
background: var(--dai-surface);
|
||||
box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
|
||||
padding: 10px 12px 8px 14px;
|
||||
padding: 10px 10px 8px 14px;
|
||||
transition:
|
||||
border-color 140ms ease,
|
||||
background-color 140ms ease,
|
||||
box-shadow 140ms ease;
|
||||
}
|
||||
.dai-root .dai-composer[data-focused='true'] {
|
||||
background: var(--dai-surface);
|
||||
border-color: var(--dai-accent);
|
||||
box-shadow: 0 0 0 3px var(--dai-accent-ring);
|
||||
}
|
||||
@@ -815,27 +811,24 @@ body.dai-docked .dai-page {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex: 0 0 auto;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
padding: 0;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
background: var(--dai-accent);
|
||||
color: var(--dai-accent-contrast);
|
||||
cursor: pointer;
|
||||
box-shadow: 0 2px 6px rgba(200, 16, 46, 0.25);
|
||||
transition:
|
||||
background-color 140ms ease,
|
||||
opacity 140ms ease,
|
||||
transform 140ms ease,
|
||||
box-shadow 140ms ease;
|
||||
transform 140ms ease;
|
||||
}
|
||||
.dai-root .dai-send:hover:not(:disabled) {
|
||||
opacity: 0.92;
|
||||
transform: scale(1.05);
|
||||
opacity: 0.86;
|
||||
}
|
||||
.dai-root .dai-send:active:not(:disabled) {
|
||||
transform: scale(0.95);
|
||||
transform: scale(0.94);
|
||||
}
|
||||
.dai-root .dai-send:focus-visible {
|
||||
outline: 2px solid var(--dai-accent);
|
||||
@@ -846,7 +839,6 @@ body.dai-docked .dai-page {
|
||||
.dai-root .dai-send:disabled {
|
||||
background: var(--dai-surface-hover);
|
||||
color: var(--dai-text-muted);
|
||||
box-shadow: none;
|
||||
cursor: default;
|
||||
}
|
||||
.dai-root .dai-composer textarea {
|
||||
|
||||
Reference in New Issue
Block a user