AI Answer Citation Row
Decorative chat / answer-UI skeleton graphic. Restyle via --lk-* CSS variables.
Install
npx shadcn@latest add https://visual-blocks.akiho.dev/r/chat-answer-row.jsonnpx skills add akifo/landerkitBlocks work with zero setup thanks to baked defaults. Set --lk-accent(and optionally --lk-bg / --lk-radius /--lk-font / --lk-grid) on :rootor any wrapper to restyle.
Source
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 320" role="img" aria-label="Chat answer mockup graphic — decorative" class="lk-block" data-lk="chat-answer-row" data-lk-contract="1">
<title>Chat answer graphic</title>
<desc>Decorative chat answer graphic. Illustrative shape only; any implied data is fictional.</desc>
<style>
/* lk-contract v1 — synced from blocks/_contract/header.css */
[data-lk="chat-answer-row"] {
--_accent: var(--lk-accent, #4BE0C3);
--_bg: var(--lk-bg, #0A0F14);
--_radius: var(--lk-radius, 12px);
--_i: oklch(from var(--_bg) clamp(0.14, (0.68 - l) * 999, 0.93) min(c, 0.03) h);
--_i2: color-mix(in oklab, var(--_i) 62%, transparent);
--_i3: color-mix(in oklab, var(--_i) 42%, transparent);
--_hair: color-mix(in oklab, var(--_i) 8%, transparent);
--_g: var(--lk-grid, color-mix(in oklab, var(--_i) 9%, transparent));
--_surf: color-mix(in oklab, var(--_accent) 3%, var(--_bg));
--_soft: color-mix(in oklab, var(--_accent) 24%, transparent);
--_faint: color-mix(in oklab, var(--_accent) 12%, transparent);
--_glow: color-mix(in oklab, var(--_accent) 55%, var(--_bg));
color: var(--_accent);
font-family: var(--lk-font, 'Inter','Neue Haas Grotesk','Helvetica Neue',Arial,sans-serif);
}
/* base ink: text flips with the bg via --_i; dim/semantic classes override (see CONVENTIONS.md) */
[data-lk="chat-answer-row"] text,
[data-lk="chat-answer-row"] tspan { fill: var(--_i); }
/* Layer 3: block-specific — every selector MUST start with [data-lk="chat-answer-row"] */
[data-lk="chat-answer-row"] .bubble { fill: var(--_bg); stroke: var(--_hair); stroke-width: 1; rx: calc(var(--_radius) * 1.3); }
[data-lk="chat-answer-row"] .card { fill: var(--_surf); stroke: var(--_hair); stroke-width: 1; rx: var(--_radius); }
[data-lk="chat-answer-row"] .grid { fill: none; stroke: var(--_g); stroke-width: 1; }
[data-lk="chat-answer-row"] .hair { stroke: var(--_hair); stroke-width: 1; }
[data-lk="chat-answer-row"] .glyph { fill: var(--_accent); }
[data-lk="chat-answer-row"] .line { fill: color-mix(in oklab, var(--_i) 20%, transparent); rx: calc(var(--_radius) * .375); }
[data-lk="chat-answer-row"] .linef { fill: color-mix(in oklab, var(--_i) 12%, transparent); rx: calc(var(--_radius) * .375); }
[data-lk="chat-answer-row"] .pill { fill: var(--_soft); stroke: var(--_accent); stroke-width: 1; rx: calc(var(--_radius) * .5); }
[data-lk="chat-answer-row"] .cchip { fill: none; stroke: color-mix(in oklab, var(--_accent) 40%, transparent); stroke-width: 1; rx: calc(var(--_radius) * .5); }
[data-lk="chat-answer-row"] .fav { fill: var(--_i3); }
/* Hover motion (opt-out): 2 stages. (1) the user bubble, then the answer card,
rise + fade in (each riser carries its own skeleton copy so nothing desyncs);
the card follows the bubble by ~.12s. (2) staggered: the answer's skeleton
text-bars fade in top→down at a typing cadence, then the citation chips pop
left→right. Off for reduced-motion visitors; set the motion token to 0 to
force off. */
[data-lk="chat-answer-row"] .rise-bubble,
[data-lk="chat-answer-row"] .rise-card { transform-box: fill-box; }
[data-lk="chat-answer-row"] .chip { transform-box: fill-box; }
@media (prefers-reduced-motion: no-preference) {
[data-lk="chat-answer-row"]:hover .rise-bubble { animation: lk-chat-answer-row-rise calc(var(--lk-motion, 1) * .48s) cubic-bezier(.22,.61,.36,1) both; }
[data-lk="chat-answer-row"]:hover .rise-card { animation: lk-chat-answer-row-rise calc(var(--lk-motion, 1) * .48s) cubic-bezier(.22,.61,.36,1) both; animation-delay: calc(var(--lk-motion, 1) * .12s); }
[data-lk="chat-answer-row"]:hover .typeline { animation: lk-chat-answer-row-type calc(var(--lk-motion, 1) * .24s) ease-out both; animation-delay: calc(var(--lk-motion, 1) * .6s); }
[data-lk="chat-answer-row"]:hover .tl2 { animation-delay: calc(var(--lk-motion, 1) * .68s); }
[data-lk="chat-answer-row"]:hover .tl3 { animation-delay: calc(var(--lk-motion, 1) * .76s); }
[data-lk="chat-answer-row"]:hover .chip { animation: lk-chat-answer-row-pop calc(var(--lk-motion, 1) * .38s) ease-out both; animation-delay: calc(var(--lk-motion, 1) * 1s); }
[data-lk="chat-answer-row"]:hover .chip2 { animation-delay: calc(var(--lk-motion, 1) * 1.06s); }
[data-lk="chat-answer-row"]:hover .chip3 { animation-delay: calc(var(--lk-motion, 1) * 1.12s); }
}
@keyframes lk-chat-answer-row-rise { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }
@keyframes lk-chat-answer-row-type { from { opacity: 0; } to { opacity: 1; } }
@keyframes lk-chat-answer-row-pop { 0% { opacity: 0; transform: scale(1); } 20% { opacity: 1; transform: scale(1); } 55% { transform: scale(1.4); } 100% { opacity: 1; transform: scale(1); } }
</style>
<!-- user turn: right-aligned bubble, hairline border + bg fill (quieter than the AI surface below), holding skeleton copy — one riser, rises + fades in together -->
<g class="rise-bubble">
<rect class="bubble" x="350" y="20" width="270" height="52" rx="15.6" fill="#0A0F14" stroke="#1A2128" stroke-width="1"/>
<rect class="line" x="368" y="34" width="234" height="8" rx="4" fill="#E6EDEE33"/>
<rect class="line" x="452" y="52" width="150" height="8" rx="4" fill="#E6EDEE33"/>
</g>
<!-- réseau cross: sparse calibration mark in the top-left dead zone, on the grid token (silenced when lk-grid is transparent) -->
<path class="grid" d="M37 40h6M40 37v6" fill="none" stroke="#1C262C" stroke-width="1"/>
<!-- AI answer turn: its own card (the block itself carries no outer frame) — rises + fades in as one riser, following the bubble -->
<g class="rise-card">
<rect class="card" x="20" y="92" width="600" height="208" rx="12" fill="#0E141B" stroke="#1A2128" stroke-width="1"/>
<!-- réseau cross: sparse calibration mark in the card's dead zone, on the grid token (silenced when lk-grid is transparent) -->
<path class="grid" d="M596 280h6M599 277v6" fill="none" stroke="#1C262C" stroke-width="1"/>
<!-- header: the one permitted decorative icon, a 4-point sparkle glyph marking the AI answer, beside a skeleton label bar -->
<polygon class="glyph" points="50,120 51.6,124.4 56,126 51.6,127.6 50,132 48.4,127.6 44,126 48.4,124.4" fill="#4BE0C3"/>
<rect class="line" x="64" y="122" width="88" height="8" rx="4" fill="#E6EDEE33"/>
<!-- answer body: skeleton text lines fade in sequentially top→down at a typing cadence; cited term as an accent pill, last line faded to suggest continuation -->
<g class="typeline tl1">
<rect class="line" x="44" y="163.5" width="118" height="9" rx="4.5" fill="#E6EDEE33"/>
<rect class="pill" x="170" y="160" width="66" height="16" rx="6" fill="#4BE0C33D" stroke="#4BE0C3" stroke-width="1"/>
<rect class="line" x="244" y="163.5" width="176" height="9" rx="4.5" fill="#E6EDEE33"/>
</g>
<g class="typeline tl2">
<rect class="line" x="44" y="187.5" width="486" height="9" rx="4.5" fill="#E6EDEE33"/>
</g>
<g class="typeline tl3">
<rect class="linef" x="44" y="211.5" width="300" height="9" rx="4.5" fill="#E6EDEE1F"/>
</g>
<!-- sources divider: hairline separating the answer body from the citation row -->
<line class="hair" x1="44" y1="232" x2="596" y2="232" stroke="#1A2128" stroke-width="1"/>
<!-- citation chips: rounded, accent 40% 1px border, achromatic favicon dot + skeleton label — pop once the answer has typed out, left→right -->
<g class="chip chip1">
<rect class="cchip" x="44" y="244" width="96" height="24" rx="6" fill="none" stroke="#4BE0C366" stroke-width="1"/>
<circle class="fav" cx="59" cy="256" r="3" fill="#E6EDEE6B"/>
<rect class="line" x="68" y="252.5" width="60" height="7" rx="3.5" fill="#E6EDEE33"/>
</g>
<g class="chip chip2">
<rect class="cchip" x="152" y="244" width="132" height="24" rx="6" fill="none" stroke="#4BE0C366" stroke-width="1"/>
<circle class="fav" cx="167" cy="256" r="3" fill="#E6EDEE6B"/>
<rect class="line" x="176" y="252.5" width="96" height="7" rx="3.5" fill="#E6EDEE33"/>
</g>
<g class="chip chip3">
<rect class="cchip" x="296" y="244" width="104" height="24" rx="6" fill="none" stroke="#4BE0C366" stroke-width="1"/>
<circle class="fav" cx="311" cy="256" r="3" fill="#E6EDEE6B"/>
<rect class="line" x="320" y="252.5" width="68" height="7" rx="3.5" fill="#E6EDEE33"/>
</g>
</g>
</svg>
/* GENERATED FROM blocks/ (catalog.json + *.svg + _contract/) — DO NOT EDIT. Run `pnpm generate`. */
import type { HTMLAttributes } from 'react';
const svg = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 640 320\" role=\"img\" aria-label=\"Chat answer mockup graphic — decorative\" class=\"lk-block\" data-lk=\"chat-answer-row\" data-lk-contract=\"1\">\n <title>Chat answer graphic</title>\n <desc>Decorative chat answer graphic. Illustrative shape only; any implied data is fictional.</desc>\n <style>\n /* lk-contract v1 — synced from blocks/_contract/header.css */\n [data-lk=\"chat-answer-row\"] {\n --_accent: var(--lk-accent, #4BE0C3);\n --_bg: var(--lk-bg, #0A0F14);\n --_radius: var(--lk-radius, 12px);\n --_i: oklch(from var(--_bg) clamp(0.14, (0.68 - l) * 999, 0.93) min(c, 0.03) h);\n --_i2: color-mix(in oklab, var(--_i) 62%, transparent);\n --_i3: color-mix(in oklab, var(--_i) 42%, transparent);\n --_hair: color-mix(in oklab, var(--_i) 8%, transparent);\n --_g: var(--lk-grid, color-mix(in oklab, var(--_i) 9%, transparent));\n --_surf: color-mix(in oklab, var(--_accent) 3%, var(--_bg));\n --_soft: color-mix(in oklab, var(--_accent) 24%, transparent);\n --_faint: color-mix(in oklab, var(--_accent) 12%, transparent);\n --_glow: color-mix(in oklab, var(--_accent) 55%, var(--_bg));\n color: var(--_accent);\n font-family: var(--lk-font, 'Inter','Neue Haas Grotesk','Helvetica Neue',Arial,sans-serif);\n }\n /* base ink: text flips with the bg via --_i; dim/semantic classes override (see CONVENTIONS.md) */\n [data-lk=\"chat-answer-row\"] text,\n [data-lk=\"chat-answer-row\"] tspan { fill: var(--_i); }\n\n\n /* Layer 3: block-specific — every selector MUST start with [data-lk=\"chat-answer-row\"] */\n [data-lk=\"chat-answer-row\"] .bubble { fill: var(--_bg); stroke: var(--_hair); stroke-width: 1; rx: calc(var(--_radius) * 1.3); }\n [data-lk=\"chat-answer-row\"] .card { fill: var(--_surf); stroke: var(--_hair); stroke-width: 1; rx: var(--_radius); }\n [data-lk=\"chat-answer-row\"] .grid { fill: none; stroke: var(--_g); stroke-width: 1; }\n [data-lk=\"chat-answer-row\"] .hair { stroke: var(--_hair); stroke-width: 1; }\n [data-lk=\"chat-answer-row\"] .glyph { fill: var(--_accent); }\n [data-lk=\"chat-answer-row\"] .line { fill: color-mix(in oklab, var(--_i) 20%, transparent); rx: calc(var(--_radius) * .375); }\n [data-lk=\"chat-answer-row\"] .linef { fill: color-mix(in oklab, var(--_i) 12%, transparent); rx: calc(var(--_radius) * .375); }\n [data-lk=\"chat-answer-row\"] .pill { fill: var(--_soft); stroke: var(--_accent); stroke-width: 1; rx: calc(var(--_radius) * .5); }\n [data-lk=\"chat-answer-row\"] .cchip { fill: none; stroke: color-mix(in oklab, var(--_accent) 40%, transparent); stroke-width: 1; rx: calc(var(--_radius) * .5); }\n [data-lk=\"chat-answer-row\"] .fav { fill: var(--_i3); }\n\n /* Hover motion (opt-out): 2 stages. (1) the user bubble, then the answer card,\n rise + fade in (each riser carries its own skeleton copy so nothing desyncs);\n the card follows the bubble by ~.12s. (2) staggered: the answer's skeleton\n text-bars fade in top→down at a typing cadence, then the citation chips pop\n left→right. Off for reduced-motion visitors; set the motion token to 0 to\n force off. */\n [data-lk=\"chat-answer-row\"] .rise-bubble,\n [data-lk=\"chat-answer-row\"] .rise-card { transform-box: fill-box; }\n [data-lk=\"chat-answer-row\"] .chip { transform-box: fill-box; }\n @media (prefers-reduced-motion: no-preference) {\n [data-lk=\"chat-answer-row\"]:hover .rise-bubble { animation: lk-chat-answer-row-rise calc(var(--lk-motion, 1) * .48s) cubic-bezier(.22,.61,.36,1) both; }\n [data-lk=\"chat-answer-row\"]:hover .rise-card { animation: lk-chat-answer-row-rise calc(var(--lk-motion, 1) * .48s) cubic-bezier(.22,.61,.36,1) both; animation-delay: calc(var(--lk-motion, 1) * .12s); }\n [data-lk=\"chat-answer-row\"]:hover .typeline { animation: lk-chat-answer-row-type calc(var(--lk-motion, 1) * .24s) ease-out both; animation-delay: calc(var(--lk-motion, 1) * .6s); }\n [data-lk=\"chat-answer-row\"]:hover .tl2 { animation-delay: calc(var(--lk-motion, 1) * .68s); }\n [data-lk=\"chat-answer-row\"]:hover .tl3 { animation-delay: calc(var(--lk-motion, 1) * .76s); }\n [data-lk=\"chat-answer-row\"]:hover .chip { animation: lk-chat-answer-row-pop calc(var(--lk-motion, 1) * .38s) ease-out both; animation-delay: calc(var(--lk-motion, 1) * 1s); }\n [data-lk=\"chat-answer-row\"]:hover .chip2 { animation-delay: calc(var(--lk-motion, 1) * 1.06s); }\n [data-lk=\"chat-answer-row\"]:hover .chip3 { animation-delay: calc(var(--lk-motion, 1) * 1.12s); }\n }\n @keyframes lk-chat-answer-row-rise { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }\n @keyframes lk-chat-answer-row-type { from { opacity: 0; } to { opacity: 1; } }\n @keyframes lk-chat-answer-row-pop { 0% { opacity: 0; transform: scale(1); } 20% { opacity: 1; transform: scale(1); } 55% { transform: scale(1.4); } 100% { opacity: 1; transform: scale(1); } }\n </style>\n\n <!-- user turn: right-aligned bubble, hairline border + bg fill (quieter than the AI surface below), holding skeleton copy — one riser, rises + fades in together -->\n <g class=\"rise-bubble\">\n <rect class=\"bubble\" x=\"350\" y=\"20\" width=\"270\" height=\"52\" rx=\"15.6\" fill=\"#0A0F14\" stroke=\"#1A2128\" stroke-width=\"1\"/>\n <rect class=\"line\" x=\"368\" y=\"34\" width=\"234\" height=\"8\" rx=\"4\" fill=\"#E6EDEE33\"/>\n <rect class=\"line\" x=\"452\" y=\"52\" width=\"150\" height=\"8\" rx=\"4\" fill=\"#E6EDEE33\"/>\n </g>\n\n <!-- réseau cross: sparse calibration mark in the top-left dead zone, on the grid token (silenced when lk-grid is transparent) -->\n <path class=\"grid\" d=\"M37 40h6M40 37v6\" fill=\"none\" stroke=\"#1C262C\" stroke-width=\"1\"/>\n\n <!-- AI answer turn: its own card (the block itself carries no outer frame) — rises + fades in as one riser, following the bubble -->\n <g class=\"rise-card\">\n <rect class=\"card\" x=\"20\" y=\"92\" width=\"600\" height=\"208\" rx=\"12\" fill=\"#0E141B\" stroke=\"#1A2128\" stroke-width=\"1\"/>\n\n <!-- réseau cross: sparse calibration mark in the card's dead zone, on the grid token (silenced when lk-grid is transparent) -->\n <path class=\"grid\" d=\"M596 280h6M599 277v6\" fill=\"none\" stroke=\"#1C262C\" stroke-width=\"1\"/>\n\n <!-- header: the one permitted decorative icon, a 4-point sparkle glyph marking the AI answer, beside a skeleton label bar -->\n <polygon class=\"glyph\" points=\"50,120 51.6,124.4 56,126 51.6,127.6 50,132 48.4,127.6 44,126 48.4,124.4\" fill=\"#4BE0C3\"/>\n <rect class=\"line\" x=\"64\" y=\"122\" width=\"88\" height=\"8\" rx=\"4\" fill=\"#E6EDEE33\"/>\n\n <!-- answer body: skeleton text lines fade in sequentially top→down at a typing cadence; cited term as an accent pill, last line faded to suggest continuation -->\n <g class=\"typeline tl1\">\n <rect class=\"line\" x=\"44\" y=\"163.5\" width=\"118\" height=\"9\" rx=\"4.5\" fill=\"#E6EDEE33\"/>\n <rect class=\"pill\" x=\"170\" y=\"160\" width=\"66\" height=\"16\" rx=\"6\" fill=\"#4BE0C33D\" stroke=\"#4BE0C3\" stroke-width=\"1\"/>\n <rect class=\"line\" x=\"244\" y=\"163.5\" width=\"176\" height=\"9\" rx=\"4.5\" fill=\"#E6EDEE33\"/>\n </g>\n <g class=\"typeline tl2\">\n <rect class=\"line\" x=\"44\" y=\"187.5\" width=\"486\" height=\"9\" rx=\"4.5\" fill=\"#E6EDEE33\"/>\n </g>\n <g class=\"typeline tl3\">\n <rect class=\"linef\" x=\"44\" y=\"211.5\" width=\"300\" height=\"9\" rx=\"4.5\" fill=\"#E6EDEE1F\"/>\n </g>\n\n <!-- sources divider: hairline separating the answer body from the citation row -->\n <line class=\"hair\" x1=\"44\" y1=\"232\" x2=\"596\" y2=\"232\" stroke=\"#1A2128\" stroke-width=\"1\"/>\n\n <!-- citation chips: rounded, accent 40% 1px border, achromatic favicon dot + skeleton label — pop once the answer has typed out, left→right -->\n <g class=\"chip chip1\">\n <rect class=\"cchip\" x=\"44\" y=\"244\" width=\"96\" height=\"24\" rx=\"6\" fill=\"none\" stroke=\"#4BE0C366\" stroke-width=\"1\"/>\n <circle class=\"fav\" cx=\"59\" cy=\"256\" r=\"3\" fill=\"#E6EDEE6B\"/>\n <rect class=\"line\" x=\"68\" y=\"252.5\" width=\"60\" height=\"7\" rx=\"3.5\" fill=\"#E6EDEE33\"/>\n </g>\n <g class=\"chip chip2\">\n <rect class=\"cchip\" x=\"152\" y=\"244\" width=\"132\" height=\"24\" rx=\"6\" fill=\"none\" stroke=\"#4BE0C366\" stroke-width=\"1\"/>\n <circle class=\"fav\" cx=\"167\" cy=\"256\" r=\"3\" fill=\"#E6EDEE6B\"/>\n <rect class=\"line\" x=\"176\" y=\"252.5\" width=\"96\" height=\"7\" rx=\"3.5\" fill=\"#E6EDEE33\"/>\n </g>\n <g class=\"chip chip3\">\n <rect class=\"cchip\" x=\"296\" y=\"244\" width=\"104\" height=\"24\" rx=\"6\" fill=\"none\" stroke=\"#4BE0C366\" stroke-width=\"1\"/>\n <circle class=\"fav\" cx=\"311\" cy=\"256\" r=\"3\" fill=\"#E6EDEE6B\"/>\n <rect class=\"line\" x=\"320\" y=\"252.5\" width=\"68\" height=\"7\" rx=\"3.5\" fill=\"#E6EDEE33\"/>\n </g>\n </g>\n</svg>\n";
export function AIAnswerCitationRow(props: HTMLAttributes<HTMLDivElement>) {
return <div {...props} dangerouslySetInnerHTML={{ __html: svg }} />;
}
export default AIAnswerCitationRow;
<!-- GENERATED FROM blocks/ (catalog.json + *.svg + _contract/) — DO NOT EDIT. Run `pnpm generate`. -->
<template>
<div v-html="svg" />
</template>
<script setup lang="ts">
const svg = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 640 320\" role=\"img\" aria-label=\"Chat answer mockup graphic — decorative\" class=\"lk-block\" data-lk=\"chat-answer-row\" data-lk-contract=\"1\">\n <title>Chat answer graphic</title>\n <desc>Decorative chat answer graphic. Illustrative shape only; any implied data is fictional.</desc>\n <style>\n /* lk-contract v1 — synced from blocks/_contract/header.css */\n [data-lk=\"chat-answer-row\"] {\n --_accent: var(--lk-accent, #4BE0C3);\n --_bg: var(--lk-bg, #0A0F14);\n --_radius: var(--lk-radius, 12px);\n --_i: oklch(from var(--_bg) clamp(0.14, (0.68 - l) * 999, 0.93) min(c, 0.03) h);\n --_i2: color-mix(in oklab, var(--_i) 62%, transparent);\n --_i3: color-mix(in oklab, var(--_i) 42%, transparent);\n --_hair: color-mix(in oklab, var(--_i) 8%, transparent);\n --_g: var(--lk-grid, color-mix(in oklab, var(--_i) 9%, transparent));\n --_surf: color-mix(in oklab, var(--_accent) 3%, var(--_bg));\n --_soft: color-mix(in oklab, var(--_accent) 24%, transparent);\n --_faint: color-mix(in oklab, var(--_accent) 12%, transparent);\n --_glow: color-mix(in oklab, var(--_accent) 55%, var(--_bg));\n color: var(--_accent);\n font-family: var(--lk-font, 'Inter','Neue Haas Grotesk','Helvetica Neue',Arial,sans-serif);\n }\n /* base ink: text flips with the bg via --_i; dim/semantic classes override (see CONVENTIONS.md) */\n [data-lk=\"chat-answer-row\"] text,\n [data-lk=\"chat-answer-row\"] tspan { fill: var(--_i); }\n\n\n /* Layer 3: block-specific — every selector MUST start with [data-lk=\"chat-answer-row\"] */\n [data-lk=\"chat-answer-row\"] .bubble { fill: var(--_bg); stroke: var(--_hair); stroke-width: 1; rx: calc(var(--_radius) * 1.3); }\n [data-lk=\"chat-answer-row\"] .card { fill: var(--_surf); stroke: var(--_hair); stroke-width: 1; rx: var(--_radius); }\n [data-lk=\"chat-answer-row\"] .grid { fill: none; stroke: var(--_g); stroke-width: 1; }\n [data-lk=\"chat-answer-row\"] .hair { stroke: var(--_hair); stroke-width: 1; }\n [data-lk=\"chat-answer-row\"] .glyph { fill: var(--_accent); }\n [data-lk=\"chat-answer-row\"] .line { fill: color-mix(in oklab, var(--_i) 20%, transparent); rx: calc(var(--_radius) * .375); }\n [data-lk=\"chat-answer-row\"] .linef { fill: color-mix(in oklab, var(--_i) 12%, transparent); rx: calc(var(--_radius) * .375); }\n [data-lk=\"chat-answer-row\"] .pill { fill: var(--_soft); stroke: var(--_accent); stroke-width: 1; rx: calc(var(--_radius) * .5); }\n [data-lk=\"chat-answer-row\"] .cchip { fill: none; stroke: color-mix(in oklab, var(--_accent) 40%, transparent); stroke-width: 1; rx: calc(var(--_radius) * .5); }\n [data-lk=\"chat-answer-row\"] .fav { fill: var(--_i3); }\n\n /* Hover motion (opt-out): 2 stages. (1) the user bubble, then the answer card,\n rise + fade in (each riser carries its own skeleton copy so nothing desyncs);\n the card follows the bubble by ~.12s. (2) staggered: the answer's skeleton\n text-bars fade in top→down at a typing cadence, then the citation chips pop\n left→right. Off for reduced-motion visitors; set the motion token to 0 to\n force off. */\n [data-lk=\"chat-answer-row\"] .rise-bubble,\n [data-lk=\"chat-answer-row\"] .rise-card { transform-box: fill-box; }\n [data-lk=\"chat-answer-row\"] .chip { transform-box: fill-box; }\n @media (prefers-reduced-motion: no-preference) {\n [data-lk=\"chat-answer-row\"]:hover .rise-bubble { animation: lk-chat-answer-row-rise calc(var(--lk-motion, 1) * .48s) cubic-bezier(.22,.61,.36,1) both; }\n [data-lk=\"chat-answer-row\"]:hover .rise-card { animation: lk-chat-answer-row-rise calc(var(--lk-motion, 1) * .48s) cubic-bezier(.22,.61,.36,1) both; animation-delay: calc(var(--lk-motion, 1) * .12s); }\n [data-lk=\"chat-answer-row\"]:hover .typeline { animation: lk-chat-answer-row-type calc(var(--lk-motion, 1) * .24s) ease-out both; animation-delay: calc(var(--lk-motion, 1) * .6s); }\n [data-lk=\"chat-answer-row\"]:hover .tl2 { animation-delay: calc(var(--lk-motion, 1) * .68s); }\n [data-lk=\"chat-answer-row\"]:hover .tl3 { animation-delay: calc(var(--lk-motion, 1) * .76s); }\n [data-lk=\"chat-answer-row\"]:hover .chip { animation: lk-chat-answer-row-pop calc(var(--lk-motion, 1) * .38s) ease-out both; animation-delay: calc(var(--lk-motion, 1) * 1s); }\n [data-lk=\"chat-answer-row\"]:hover .chip2 { animation-delay: calc(var(--lk-motion, 1) * 1.06s); }\n [data-lk=\"chat-answer-row\"]:hover .chip3 { animation-delay: calc(var(--lk-motion, 1) * 1.12s); }\n }\n @keyframes lk-chat-answer-row-rise { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }\n @keyframes lk-chat-answer-row-type { from { opacity: 0; } to { opacity: 1; } }\n @keyframes lk-chat-answer-row-pop { 0% { opacity: 0; transform: scale(1); } 20% { opacity: 1; transform: scale(1); } 55% { transform: scale(1.4); } 100% { opacity: 1; transform: scale(1); } }\n </style>\n\n <!-- user turn: right-aligned bubble, hairline border + bg fill (quieter than the AI surface below), holding skeleton copy — one riser, rises + fades in together -->\n <g class=\"rise-bubble\">\n <rect class=\"bubble\" x=\"350\" y=\"20\" width=\"270\" height=\"52\" rx=\"15.6\" fill=\"#0A0F14\" stroke=\"#1A2128\" stroke-width=\"1\"/>\n <rect class=\"line\" x=\"368\" y=\"34\" width=\"234\" height=\"8\" rx=\"4\" fill=\"#E6EDEE33\"/>\n <rect class=\"line\" x=\"452\" y=\"52\" width=\"150\" height=\"8\" rx=\"4\" fill=\"#E6EDEE33\"/>\n </g>\n\n <!-- réseau cross: sparse calibration mark in the top-left dead zone, on the grid token (silenced when lk-grid is transparent) -->\n <path class=\"grid\" d=\"M37 40h6M40 37v6\" fill=\"none\" stroke=\"#1C262C\" stroke-width=\"1\"/>\n\n <!-- AI answer turn: its own card (the block itself carries no outer frame) — rises + fades in as one riser, following the bubble -->\n <g class=\"rise-card\">\n <rect class=\"card\" x=\"20\" y=\"92\" width=\"600\" height=\"208\" rx=\"12\" fill=\"#0E141B\" stroke=\"#1A2128\" stroke-width=\"1\"/>\n\n <!-- réseau cross: sparse calibration mark in the card's dead zone, on the grid token (silenced when lk-grid is transparent) -->\n <path class=\"grid\" d=\"M596 280h6M599 277v6\" fill=\"none\" stroke=\"#1C262C\" stroke-width=\"1\"/>\n\n <!-- header: the one permitted decorative icon, a 4-point sparkle glyph marking the AI answer, beside a skeleton label bar -->\n <polygon class=\"glyph\" points=\"50,120 51.6,124.4 56,126 51.6,127.6 50,132 48.4,127.6 44,126 48.4,124.4\" fill=\"#4BE0C3\"/>\n <rect class=\"line\" x=\"64\" y=\"122\" width=\"88\" height=\"8\" rx=\"4\" fill=\"#E6EDEE33\"/>\n\n <!-- answer body: skeleton text lines fade in sequentially top→down at a typing cadence; cited term as an accent pill, last line faded to suggest continuation -->\n <g class=\"typeline tl1\">\n <rect class=\"line\" x=\"44\" y=\"163.5\" width=\"118\" height=\"9\" rx=\"4.5\" fill=\"#E6EDEE33\"/>\n <rect class=\"pill\" x=\"170\" y=\"160\" width=\"66\" height=\"16\" rx=\"6\" fill=\"#4BE0C33D\" stroke=\"#4BE0C3\" stroke-width=\"1\"/>\n <rect class=\"line\" x=\"244\" y=\"163.5\" width=\"176\" height=\"9\" rx=\"4.5\" fill=\"#E6EDEE33\"/>\n </g>\n <g class=\"typeline tl2\">\n <rect class=\"line\" x=\"44\" y=\"187.5\" width=\"486\" height=\"9\" rx=\"4.5\" fill=\"#E6EDEE33\"/>\n </g>\n <g class=\"typeline tl3\">\n <rect class=\"linef\" x=\"44\" y=\"211.5\" width=\"300\" height=\"9\" rx=\"4.5\" fill=\"#E6EDEE1F\"/>\n </g>\n\n <!-- sources divider: hairline separating the answer body from the citation row -->\n <line class=\"hair\" x1=\"44\" y1=\"232\" x2=\"596\" y2=\"232\" stroke=\"#1A2128\" stroke-width=\"1\"/>\n\n <!-- citation chips: rounded, accent 40% 1px border, achromatic favicon dot + skeleton label — pop once the answer has typed out, left→right -->\n <g class=\"chip chip1\">\n <rect class=\"cchip\" x=\"44\" y=\"244\" width=\"96\" height=\"24\" rx=\"6\" fill=\"none\" stroke=\"#4BE0C366\" stroke-width=\"1\"/>\n <circle class=\"fav\" cx=\"59\" cy=\"256\" r=\"3\" fill=\"#E6EDEE6B\"/>\n <rect class=\"line\" x=\"68\" y=\"252.5\" width=\"60\" height=\"7\" rx=\"3.5\" fill=\"#E6EDEE33\"/>\n </g>\n <g class=\"chip chip2\">\n <rect class=\"cchip\" x=\"152\" y=\"244\" width=\"132\" height=\"24\" rx=\"6\" fill=\"none\" stroke=\"#4BE0C366\" stroke-width=\"1\"/>\n <circle class=\"fav\" cx=\"167\" cy=\"256\" r=\"3\" fill=\"#E6EDEE6B\"/>\n <rect class=\"line\" x=\"176\" y=\"252.5\" width=\"96\" height=\"7\" rx=\"3.5\" fill=\"#E6EDEE33\"/>\n </g>\n <g class=\"chip chip3\">\n <rect class=\"cchip\" x=\"296\" y=\"244\" width=\"104\" height=\"24\" rx=\"6\" fill=\"none\" stroke=\"#4BE0C366\" stroke-width=\"1\"/>\n <circle class=\"fav\" cx=\"311\" cy=\"256\" r=\"3\" fill=\"#E6EDEE6B\"/>\n <rect class=\"line\" x=\"320\" y=\"252.5\" width=\"68\" height=\"7\" rx=\"3.5\" fill=\"#E6EDEE33\"/>\n </g>\n </g>\n</svg>\n";
</script>
<div style="--lk-accent: #4BE0C3; --lk-bg: #0A0F14;">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 320" role="img" aria-label="Chat answer mockup graphic — decorative" class="lk-block" data-lk="chat-answer-row" data-lk-contract="1">
<title>Chat answer graphic</title>
<desc>Decorative chat answer graphic. Illustrative shape only; any implied data is fictional.</desc>
<style>
/* lk-contract v1 — synced from blocks/_contract/header.css */
[data-lk="chat-answer-row"] {
--_accent: var(--lk-accent, #4BE0C3);
--_bg: var(--lk-bg, #0A0F14);
--_radius: var(--lk-radius, 12px);
--_i: oklch(from var(--_bg) clamp(0.14, (0.68 - l) * 999, 0.93) min(c, 0.03) h);
--_i2: color-mix(in oklab, var(--_i) 62%, transparent);
--_i3: color-mix(in oklab, var(--_i) 42%, transparent);
--_hair: color-mix(in oklab, var(--_i) 8%, transparent);
--_g: var(--lk-grid, color-mix(in oklab, var(--_i) 9%, transparent));
--_surf: color-mix(in oklab, var(--_accent) 3%, var(--_bg));
--_soft: color-mix(in oklab, var(--_accent) 24%, transparent);
--_faint: color-mix(in oklab, var(--_accent) 12%, transparent);
--_glow: color-mix(in oklab, var(--_accent) 55%, var(--_bg));
color: var(--_accent);
font-family: var(--lk-font, 'Inter','Neue Haas Grotesk','Helvetica Neue',Arial,sans-serif);
}
/* base ink: text flips with the bg via --_i; dim/semantic classes override (see CONVENTIONS.md) */
[data-lk="chat-answer-row"] text,
[data-lk="chat-answer-row"] tspan { fill: var(--_i); }
/* Layer 3: block-specific — every selector MUST start with [data-lk="chat-answer-row"] */
[data-lk="chat-answer-row"] .bubble { fill: var(--_bg); stroke: var(--_hair); stroke-width: 1; rx: calc(var(--_radius) * 1.3); }
[data-lk="chat-answer-row"] .card { fill: var(--_surf); stroke: var(--_hair); stroke-width: 1; rx: var(--_radius); }
[data-lk="chat-answer-row"] .grid { fill: none; stroke: var(--_g); stroke-width: 1; }
[data-lk="chat-answer-row"] .hair { stroke: var(--_hair); stroke-width: 1; }
[data-lk="chat-answer-row"] .glyph { fill: var(--_accent); }
[data-lk="chat-answer-row"] .line { fill: color-mix(in oklab, var(--_i) 20%, transparent); rx: calc(var(--_radius) * .375); }
[data-lk="chat-answer-row"] .linef { fill: color-mix(in oklab, var(--_i) 12%, transparent); rx: calc(var(--_radius) * .375); }
[data-lk="chat-answer-row"] .pill { fill: var(--_soft); stroke: var(--_accent); stroke-width: 1; rx: calc(var(--_radius) * .5); }
[data-lk="chat-answer-row"] .cchip { fill: none; stroke: color-mix(in oklab, var(--_accent) 40%, transparent); stroke-width: 1; rx: calc(var(--_radius) * .5); }
[data-lk="chat-answer-row"] .fav { fill: var(--_i3); }
/* Hover motion (opt-out): 2 stages. (1) the user bubble, then the answer card,
rise + fade in (each riser carries its own skeleton copy so nothing desyncs);
the card follows the bubble by ~.12s. (2) staggered: the answer's skeleton
text-bars fade in top→down at a typing cadence, then the citation chips pop
left→right. Off for reduced-motion visitors; set the motion token to 0 to
force off. */
[data-lk="chat-answer-row"] .rise-bubble,
[data-lk="chat-answer-row"] .rise-card { transform-box: fill-box; }
[data-lk="chat-answer-row"] .chip { transform-box: fill-box; }
@media (prefers-reduced-motion: no-preference) {
[data-lk="chat-answer-row"]:hover .rise-bubble { animation: lk-chat-answer-row-rise calc(var(--lk-motion, 1) * .48s) cubic-bezier(.22,.61,.36,1) both; }
[data-lk="chat-answer-row"]:hover .rise-card { animation: lk-chat-answer-row-rise calc(var(--lk-motion, 1) * .48s) cubic-bezier(.22,.61,.36,1) both; animation-delay: calc(var(--lk-motion, 1) * .12s); }
[data-lk="chat-answer-row"]:hover .typeline { animation: lk-chat-answer-row-type calc(var(--lk-motion, 1) * .24s) ease-out both; animation-delay: calc(var(--lk-motion, 1) * .6s); }
[data-lk="chat-answer-row"]:hover .tl2 { animation-delay: calc(var(--lk-motion, 1) * .68s); }
[data-lk="chat-answer-row"]:hover .tl3 { animation-delay: calc(var(--lk-motion, 1) * .76s); }
[data-lk="chat-answer-row"]:hover .chip { animation: lk-chat-answer-row-pop calc(var(--lk-motion, 1) * .38s) ease-out both; animation-delay: calc(var(--lk-motion, 1) * 1s); }
[data-lk="chat-answer-row"]:hover .chip2 { animation-delay: calc(var(--lk-motion, 1) * 1.06s); }
[data-lk="chat-answer-row"]:hover .chip3 { animation-delay: calc(var(--lk-motion, 1) * 1.12s); }
}
@keyframes lk-chat-answer-row-rise { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }
@keyframes lk-chat-answer-row-type { from { opacity: 0; } to { opacity: 1; } }
@keyframes lk-chat-answer-row-pop { 0% { opacity: 0; transform: scale(1); } 20% { opacity: 1; transform: scale(1); } 55% { transform: scale(1.4); } 100% { opacity: 1; transform: scale(1); } }
</style>
<!-- user turn: right-aligned bubble, hairline border + bg fill (quieter than the AI surface below), holding skeleton copy — one riser, rises + fades in together -->
<g class="rise-bubble">
<rect class="bubble" x="350" y="20" width="270" height="52" rx="15.6" fill="#0A0F14" stroke="#1A2128" stroke-width="1"/>
<rect class="line" x="368" y="34" width="234" height="8" rx="4" fill="#E6EDEE33"/>
<rect class="line" x="452" y="52" width="150" height="8" rx="4" fill="#E6EDEE33"/>
</g>
<!-- réseau cross: sparse calibration mark in the top-left dead zone, on the grid token (silenced when lk-grid is transparent) -->
<path class="grid" d="M37 40h6M40 37v6" fill="none" stroke="#1C262C" stroke-width="1"/>
<!-- AI answer turn: its own card (the block itself carries no outer frame) — rises + fades in as one riser, following the bubble -->
<g class="rise-card">
<rect class="card" x="20" y="92" width="600" height="208" rx="12" fill="#0E141B" stroke="#1A2128" stroke-width="1"/>
<!-- réseau cross: sparse calibration mark in the card's dead zone, on the grid token (silenced when lk-grid is transparent) -->
<path class="grid" d="M596 280h6M599 277v6" fill="none" stroke="#1C262C" stroke-width="1"/>
<!-- header: the one permitted decorative icon, a 4-point sparkle glyph marking the AI answer, beside a skeleton label bar -->
<polygon class="glyph" points="50,120 51.6,124.4 56,126 51.6,127.6 50,132 48.4,127.6 44,126 48.4,124.4" fill="#4BE0C3"/>
<rect class="line" x="64" y="122" width="88" height="8" rx="4" fill="#E6EDEE33"/>
<!-- answer body: skeleton text lines fade in sequentially top→down at a typing cadence; cited term as an accent pill, last line faded to suggest continuation -->
<g class="typeline tl1">
<rect class="line" x="44" y="163.5" width="118" height="9" rx="4.5" fill="#E6EDEE33"/>
<rect class="pill" x="170" y="160" width="66" height="16" rx="6" fill="#4BE0C33D" stroke="#4BE0C3" stroke-width="1"/>
<rect class="line" x="244" y="163.5" width="176" height="9" rx="4.5" fill="#E6EDEE33"/>
</g>
<g class="typeline tl2">
<rect class="line" x="44" y="187.5" width="486" height="9" rx="4.5" fill="#E6EDEE33"/>
</g>
<g class="typeline tl3">
<rect class="linef" x="44" y="211.5" width="300" height="9" rx="4.5" fill="#E6EDEE1F"/>
</g>
<!-- sources divider: hairline separating the answer body from the citation row -->
<line class="hair" x1="44" y1="232" x2="596" y2="232" stroke="#1A2128" stroke-width="1"/>
<!-- citation chips: rounded, accent 40% 1px border, achromatic favicon dot + skeleton label — pop once the answer has typed out, left→right -->
<g class="chip chip1">
<rect class="cchip" x="44" y="244" width="96" height="24" rx="6" fill="none" stroke="#4BE0C366" stroke-width="1"/>
<circle class="fav" cx="59" cy="256" r="3" fill="#E6EDEE6B"/>
<rect class="line" x="68" y="252.5" width="60" height="7" rx="3.5" fill="#E6EDEE33"/>
</g>
<g class="chip chip2">
<rect class="cchip" x="152" y="244" width="132" height="24" rx="6" fill="none" stroke="#4BE0C366" stroke-width="1"/>
<circle class="fav" cx="167" cy="256" r="3" fill="#E6EDEE6B"/>
<rect class="line" x="176" y="252.5" width="96" height="7" rx="3.5" fill="#E6EDEE33"/>
</g>
<g class="chip chip3">
<rect class="cchip" x="296" y="244" width="104" height="24" rx="6" fill="none" stroke="#4BE0C366" stroke-width="1"/>
<circle class="fav" cx="311" cy="256" r="3" fill="#E6EDEE6B"/>
<rect class="line" x="320" y="252.5" width="68" height="7" rx="3.5" fill="#E6EDEE33"/>
</g>
</g>
</svg>
</div>