ez-reads 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +100 -0
- package/bin/paper-site.mjs +6 -0
- package/bin/rebuild-all.mjs +25 -0
- package/package.json +47 -0
- package/src/cli.mjs +243 -0
- package/src/distiller.mjs +356 -0
- package/src/fetcher.mjs +327 -0
- package/src/generator.mjs +656 -0
- package/template/index.html +15 -0
- package/template/package-lock.json +2659 -0
- package/template/package.json +22 -0
- package/template/postcss.config.js +6 -0
- package/template/src/App.jsx +62 -0
- package/template/src/components/Abstract.jsx +18 -0
- package/template/src/components/Analogy.jsx +20 -0
- package/template/src/components/ChatAssistant.jsx +155 -0
- package/template/src/components/Figures.jsx +63 -0
- package/template/src/components/Footer.jsx +22 -0
- package/template/src/components/Glossary.jsx +36 -0
- package/template/src/components/Hero.jsx +56 -0
- package/template/src/components/KeyContributions.jsx +35 -0
- package/template/src/components/Limitations.jsx +22 -0
- package/template/src/components/Methodology.jsx +42 -0
- package/template/src/components/Results.jsx +34 -0
- package/template/src/components/Significance.jsx +20 -0
- package/template/src/components/Stats.jsx +34 -0
- package/template/src/data/paper.json +53 -0
- package/template/src/index.css +327 -0
- package/template/src/main.jsx +10 -0
- package/template/tailwind.config.js +12 -0
- package/template/vite.config.js +7 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"title": "Attention Is All You Need",
|
|
3
|
+
"authors": ["Ashish Vaswani", "Noam Shazeer", "Niki Parmar", "Jakob Uszkoreit", "Llion Jones", "Aidan N. Gomez", "Lukasz Kaiser", "Illia Polosukhin"],
|
|
4
|
+
"tldr": "This paper introduces the Transformer, a novel architecture that replaces recurrence and convolution entirely with self-attention mechanisms, achieving state-of-the-art results in machine translation while being significantly more parallelizable.",
|
|
5
|
+
"analogy": "Imagine translating a book: traditional approaches read word-by-word sequentially (like reading aloud), which is slow and makes it hard to connect a word on page 50 to a key term on page 2. The Transformer instead spreads the entire book on a table and lets every word simultaneously look at every other word, picking out the relevant connections in parallel β like having a team of readers each tracking different threads across the whole text at once.",
|
|
6
|
+
"abstract_simplified": "Sequential models like RNNs process language one word at a time, creating a bottleneck that limits both training speed and the ability to capture long-range dependencies. This paper proposes the Transformer, a model architecture that dispenses with recurrence entirely, relying instead on a mechanism called self-attention that lets every position in a sequence attend to every other position simultaneously. On English-to-German translation, the Transformer achieves a BLEU score of 28.4, surpassing all prior models including ensembles. Beyond raw performance, the architecture trains in a fraction of the time β 3.5 days on 8 GPUs versus weeks for competing approaches. The Transformer's design has since become the foundation of modern NLP.",
|
|
7
|
+
"key_contributions": [
|
|
8
|
+
{ "emoji": "π", "title": "Pure Attention Architecture", "description": "The Transformer is the first sequence transduction model based entirely on attention, eliminating recurrent and convolutional layers. This is a fundamental departure from the prevailing wisdom that sequential processing was necessary for language. By removing the sequential bottleneck, the architecture can process all positions in parallel, enabling dramatically faster training while maintaining or improving quality." },
|
|
9
|
+
{ "emoji": "π", "title": "Multi-Head Attention", "description": "Rather than computing a single attention function, the model projects queries, keys, and values into multiple parallel 'heads' that each attend to different representation subspaces. This allows the model to jointly attend to information at different positions from different perspectives β for example, one head might track syntactic structure while another tracks semantic similarity. The multi-head design consistently outperforms single-head attention of equivalent dimension." },
|
|
10
|
+
{ "emoji": "π", "title": "Positional Encoding", "description": "Since the model contains no recurrence or convolution, it has no inherent notion of word order. The authors introduce sinusoidal positional encodings β fixed functions of position that are added to the input embeddings. The sinusoidal design was chosen because it allows the model to generalize to sequence lengths not seen during training, since relative positions can be expressed as linear functions of the encodings." }
|
|
11
|
+
],
|
|
12
|
+
"methodology": {
|
|
13
|
+
"summary": "The Transformer uses an encoder-decoder structure where both halves are built entirely from stacked self-attention and feed-forward layers. The encoder maps an input sequence to continuous representations, and the decoder generates the output sequence one token at a time, attending to both the encoder output and its own previously generated tokens. The key innovation is that every layer uses attention rather than recurrence, enabling full parallelization during training.",
|
|
14
|
+
"steps": [
|
|
15
|
+
{ "emoji": "π’", "label": "Input Embedding & Positional Encoding", "detail": "Input tokens are mapped to 512-dimensional vectors via learned embeddings, then summed with sinusoidal positional encodings. The positional signals use sine and cosine functions at geometrically increasing frequencies, creating unique position signatures. This approach was chosen over learned positional embeddings because it can extrapolate to sequence lengths beyond those seen in training β the geometric frequency spacing means relative position information is preserved regardless of absolute position." },
|
|
16
|
+
{ "emoji": "ποΈ", "label": "Encoder Stack (6 Layers)", "detail": "Each of the 6 encoder layers applies two sub-operations: multi-head self-attention followed by a position-wise feed-forward network. Both sub-layers use residual connections and layer normalization. The self-attention lets each word build a representation that incorporates context from the entire input sentence, while the feed-forward network (two linear transformations with ReLU) adds non-linear processing capacity. Stacking 6 layers creates increasingly abstract representations." },
|
|
17
|
+
{ "emoji": "π―", "label": "Scaled Dot-Product Attention", "detail": "The core attention mechanism computes compatibility scores between queries and keys using dot products, scaled by the square root of the key dimension. Scaling prevents the dot products from growing too large in magnitude, which would push the softmax into regions with extremely small gradients. The resulting attention weights are applied to values to produce the output. This mechanism runs in O(nΒ²Β·d) time, which is faster than recurrent layers for typical sequence lengths." },
|
|
18
|
+
{ "emoji": "π", "label": "Multi-Head Projection", "detail": "Instead of one attention pass over 512 dimensions, the model runs 8 parallel attention heads, each operating on a 64-dimensional projection. Each head learns to attend to different aspects of the input β empirically, heads specialize in syntactic roles, coreference, and other linguistic phenomena. The outputs are concatenated and linearly projected back to the model dimension. This is both computationally equivalent to single-head attention and strictly more expressive." },
|
|
19
|
+
{ "emoji": "π", "label": "Decoder Stack with Masking", "detail": "The decoder mirrors the encoder but adds a third sub-layer: cross-attention over the encoder output. Crucially, self-attention in the decoder is masked so each position can only attend to earlier positions, preserving the autoregressive property needed for generation. This masking is implemented by setting future positions to negative infinity before softmax, effectively zeroing out those attention weights. The cross-attention layer is what allows the decoder to condition on the full source sequence." }
|
|
20
|
+
]
|
|
21
|
+
},
|
|
22
|
+
"results": [
|
|
23
|
+
{ "emoji": "π", "finding": "State-of-the-art English-to-German translation", "detail": "The big Transformer achieves 28.4 BLEU on WMT 2014 English-to-German, exceeding the previous best models (including ensembles) by over 2 BLEU points. This is notable because the model is a single system, not an ensemble, yet it surpasses ensemble approaches that combine multiple independently trained models. The improvement demonstrates that architectural innovation, not just scaling, can drive meaningful quality gains." },
|
|
24
|
+
{ "emoji": "β‘", "finding": "Dramatically faster training", "detail": "The base model requires only 12 hours of training on 8 P100 GPUs (0.5 days), while the big model takes 3.5 days. By comparison, competitive recurrent models required weeks of training. The parallelization advantage comes from eliminating sequential dependencies β all positions in a layer can be computed simultaneously. This 10-100x training speed improvement makes it practical to iterate on model design and hyperparameters far more rapidly." },
|
|
25
|
+
{ "emoji": "π¬", "finding": "Attention heads learn interpretable patterns", "detail": "Visualization of attention weights reveals that different heads specialize in distinct linguistic functions. Some heads track long-range syntactic dependencies (like subject-verb agreement across clauses), while others focus on local morphological patterns. This emergent specialization occurs without explicit supervision, suggesting that multi-head attention is an effective inductive bias for learning hierarchical language structure." }
|
|
26
|
+
],
|
|
27
|
+
"stats": [
|
|
28
|
+
{ "value": "28.4", "label": "BLEU (ENβDE)", "context": "Surpasses the previous best single model by over 2 BLEU points and outperforms ensemble approaches, setting a new state of the art on WMT 2014." },
|
|
29
|
+
{ "value": "3.5 days", "label": "Training time (big model)", "context": "Trained on 8 GPUs in 3.5 days β roughly 10-100x faster than competing recurrent architectures that required weeks of training." },
|
|
30
|
+
{ "value": "8", "label": "Attention heads", "context": "8 parallel attention heads per layer, each learning different linguistic patterns. Ablations show this outperforms both fewer and more heads." }
|
|
31
|
+
],
|
|
32
|
+
"significance": "The Transformer fundamentally changed the trajectory of natural language processing and, eventually, all of deep learning. By proving that attention alone β without recurrence β could achieve superior results, it removed the sequential bottleneck that had limited both the scale and speed of language models. This architecture directly enabled the development of BERT, GPT, and every major large language model that followed. Beyond NLP, the Transformer's design has been adopted in computer vision (Vision Transformer), protein structure prediction (AlphaFold), and audio generation, establishing it as perhaps the most influential neural architecture of the decade.",
|
|
33
|
+
"limitations": [
|
|
34
|
+
"Self-attention has O(nΒ²) memory and compute complexity in sequence length, making it expensive for very long sequences (e.g., full documents or genomic data). This has spawned an entire subfield of efficient attention variants.",
|
|
35
|
+
"The model was evaluated primarily on machine translation; its effectiveness on other tasks required subsequent work (BERT, GPT) to demonstrate.",
|
|
36
|
+
"Positional encodings are added rather than integrated into the architecture, and the sinusoidal scheme captures only absolute position. Later work showed that relative positional encodings (like RoPE) can be more effective.",
|
|
37
|
+
"The autoregressive decoder generates tokens one at a time during inference, creating a sequential bottleneck at generation time even though training is fully parallel."
|
|
38
|
+
],
|
|
39
|
+
"glossary": [
|
|
40
|
+
{ "term": "Self-Attention", "definition": "A mechanism where each element in a sequence computes attention weights over all other elements in the same sequence, building context-aware representations. Unlike recurrence (which propagates information step-by-step), self-attention provides direct connections between any two positions, making it particularly effective for capturing long-range dependencies." },
|
|
41
|
+
{ "term": "Multi-Head Attention", "definition": "An extension of attention that runs multiple attention functions in parallel on different learned projections of the input. Each 'head' can specialize in different types of relationships (syntactic, semantic, positional), and their outputs are concatenated to form a richer representation than any single attention pass." },
|
|
42
|
+
{ "term": "BLEU Score", "definition": "Bilingual Evaluation Understudy β a metric for evaluating machine translation quality by measuring n-gram overlap between the model's output and reference translations. Scores range from 0 to 100; differences of 1-2 points are generally considered significant in competitive benchmarks." },
|
|
43
|
+
{ "term": "Positional Encoding", "definition": "A signal added to input embeddings to provide sequence order information to models that have no inherent notion of position (like the Transformer). Sinusoidal encodings use trigonometric functions at different frequencies, creating unique signatures for each position that also encode relative distance information." },
|
|
44
|
+
{ "term": "Residual Connection", "definition": "A shortcut connection that adds a layer's input directly to its output (x + sublayer(x)). This helps gradients flow through deep networks during training and allows each layer to learn a refinement of its input rather than a complete transformation, making optimization easier." },
|
|
45
|
+
{ "term": "Layer Normalization", "definition": "A normalization technique that standardizes activations across the feature dimension within each training example. Applied after residual connections in the Transformer, it stabilizes training by reducing sensitivity to the scale of inputs and gradients." }
|
|
46
|
+
],
|
|
47
|
+
"color_theme": {
|
|
48
|
+
"primary": "#2563eb",
|
|
49
|
+
"accent": "#f59e0b"
|
|
50
|
+
},
|
|
51
|
+
"publishedDate": "2017-06-12",
|
|
52
|
+
"url": "https://arxiv.org/abs/1706.03762"
|
|
53
|
+
}
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
@tailwind base;
|
|
2
|
+
@tailwind components;
|
|
3
|
+
@tailwind utilities;
|
|
4
|
+
|
|
5
|
+
:root {
|
|
6
|
+
--color-primary: #2563eb;
|
|
7
|
+
--color-accent: #f59e0b;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
body {
|
|
11
|
+
font-family: 'Inter', system-ui, sans-serif;
|
|
12
|
+
-webkit-font-smoothing: antialiased;
|
|
13
|
+
-moz-osx-font-smoothing: grayscale;
|
|
14
|
+
background: #f8fafc;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/* Scroll animations */
|
|
18
|
+
.fade-in {
|
|
19
|
+
opacity: 0;
|
|
20
|
+
transform: translateY(30px);
|
|
21
|
+
transition: opacity 0.7s ease-out, transform 0.7s ease-out;
|
|
22
|
+
}
|
|
23
|
+
.fade-in.visible {
|
|
24
|
+
opacity: 1;
|
|
25
|
+
transform: translateY(0);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.slide-left {
|
|
29
|
+
opacity: 0;
|
|
30
|
+
transform: translateX(-40px);
|
|
31
|
+
transition: opacity 0.6s ease-out, transform 0.6s ease-out;
|
|
32
|
+
}
|
|
33
|
+
.slide-left.visible {
|
|
34
|
+
opacity: 1;
|
|
35
|
+
transform: translateX(0);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.slide-right {
|
|
39
|
+
opacity: 0;
|
|
40
|
+
transform: translateX(40px);
|
|
41
|
+
transition: opacity 0.6s ease-out, transform 0.6s ease-out;
|
|
42
|
+
}
|
|
43
|
+
.slide-right.visible {
|
|
44
|
+
opacity: 1;
|
|
45
|
+
transform: translateX(0);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.scale-in {
|
|
49
|
+
opacity: 0;
|
|
50
|
+
transform: scale(0.85);
|
|
51
|
+
transition: opacity 0.5s ease-out, transform 0.5s ease-out;
|
|
52
|
+
}
|
|
53
|
+
.scale-in.visible {
|
|
54
|
+
opacity: 1;
|
|
55
|
+
transform: scale(1);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/* Stagger children animations */
|
|
59
|
+
.stagger-children.visible > * {
|
|
60
|
+
opacity: 1;
|
|
61
|
+
transform: translateY(0);
|
|
62
|
+
}
|
|
63
|
+
.stagger-children > * {
|
|
64
|
+
opacity: 0;
|
|
65
|
+
transform: translateY(20px);
|
|
66
|
+
transition: opacity 0.5s ease-out, transform 0.5s ease-out;
|
|
67
|
+
}
|
|
68
|
+
.stagger-children > *:nth-child(1) { transition-delay: 0.05s; }
|
|
69
|
+
.stagger-children > *:nth-child(2) { transition-delay: 0.1s; }
|
|
70
|
+
.stagger-children > *:nth-child(3) { transition-delay: 0.15s; }
|
|
71
|
+
.stagger-children > *:nth-child(4) { transition-delay: 0.2s; }
|
|
72
|
+
.stagger-children > *:nth-child(5) { transition-delay: 0.25s; }
|
|
73
|
+
.stagger-children > *:nth-child(6) { transition-delay: 0.3s; }
|
|
74
|
+
.stagger-children > *:nth-child(7) { transition-delay: 0.35s; }
|
|
75
|
+
.stagger-children > *:nth-child(8) { transition-delay: 0.4s; }
|
|
76
|
+
|
|
77
|
+
/* Hero gradient */
|
|
78
|
+
.gradient-hero {
|
|
79
|
+
background: linear-gradient(135deg, var(--color-primary) 0%, color-mix(in srgb, var(--color-primary) 50%, #1e1b4b) 100%);
|
|
80
|
+
position: relative;
|
|
81
|
+
overflow: hidden;
|
|
82
|
+
}
|
|
83
|
+
.gradient-hero::before {
|
|
84
|
+
content: '';
|
|
85
|
+
position: absolute;
|
|
86
|
+
inset: 0;
|
|
87
|
+
background: radial-gradient(circle at 20% 80%, color-mix(in srgb, var(--color-accent) 20%, transparent) 0%, transparent 50%),
|
|
88
|
+
radial-gradient(circle at 80% 20%, color-mix(in srgb, var(--color-primary) 30%, transparent) 0%, transparent 50%);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/* Accent surfaces */
|
|
92
|
+
.accent-bar {
|
|
93
|
+
background: linear-gradient(135deg, var(--color-accent) 0%, color-mix(in srgb, var(--color-accent) 70%, var(--color-primary)) 100%);
|
|
94
|
+
}
|
|
95
|
+
.primary-glow {
|
|
96
|
+
box-shadow: 0 0 40px color-mix(in srgb, var(--color-primary) 20%, transparent);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/* Animated counter */
|
|
100
|
+
@keyframes countPulse {
|
|
101
|
+
0%, 100% { transform: scale(1); }
|
|
102
|
+
50% { transform: scale(1.05); }
|
|
103
|
+
}
|
|
104
|
+
.stat-value {
|
|
105
|
+
animation: countPulse 2s ease-in-out infinite;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/* Timeline connector */
|
|
109
|
+
.timeline-dot::before {
|
|
110
|
+
content: '';
|
|
111
|
+
position: absolute;
|
|
112
|
+
left: 50%;
|
|
113
|
+
top: 100%;
|
|
114
|
+
width: 2px;
|
|
115
|
+
height: calc(100% + 1.5rem);
|
|
116
|
+
transform: translateX(-50%);
|
|
117
|
+
background: linear-gradient(to bottom, var(--color-primary), color-mix(in srgb, var(--color-primary) 20%, transparent));
|
|
118
|
+
}
|
|
119
|
+
.timeline-dot:last-child::before {
|
|
120
|
+
display: none;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/* Floating blob animation */
|
|
124
|
+
@keyframes float {
|
|
125
|
+
0%, 100% { transform: translateY(0) rotate(0deg); }
|
|
126
|
+
33% { transform: translateY(-8px) rotate(2deg); }
|
|
127
|
+
66% { transform: translateY(4px) rotate(-1deg); }
|
|
128
|
+
}
|
|
129
|
+
.float {
|
|
130
|
+
animation: float 6s ease-in-out infinite;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/* Glossary tooltip hover */
|
|
134
|
+
.glossary-card {
|
|
135
|
+
transition: transform 0.2s, box-shadow 0.2s;
|
|
136
|
+
}
|
|
137
|
+
.glossary-card:hover {
|
|
138
|
+
transform: translateY(-4px);
|
|
139
|
+
box-shadow: 0 12px 24px -8px rgba(0,0,0,0.12);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/* ββ Chat Assistant ββ */
|
|
143
|
+
.chat-fab {
|
|
144
|
+
position: fixed;
|
|
145
|
+
bottom: 1.5rem;
|
|
146
|
+
right: 1.5rem;
|
|
147
|
+
z-index: 1000;
|
|
148
|
+
width: 56px;
|
|
149
|
+
height: 56px;
|
|
150
|
+
border-radius: 50%;
|
|
151
|
+
border: none;
|
|
152
|
+
background: var(--color-accent);
|
|
153
|
+
color: #fff;
|
|
154
|
+
cursor: pointer;
|
|
155
|
+
display: flex;
|
|
156
|
+
align-items: center;
|
|
157
|
+
justify-content: center;
|
|
158
|
+
box-shadow: 0 4px 20px rgba(0,0,0,0.2);
|
|
159
|
+
transition: transform 0.2s, box-shadow 0.2s;
|
|
160
|
+
animation: fabPulse 3s ease-in-out infinite;
|
|
161
|
+
}
|
|
162
|
+
.chat-fab:hover {
|
|
163
|
+
transform: scale(1.08);
|
|
164
|
+
box-shadow: 0 6px 28px rgba(0,0,0,0.3);
|
|
165
|
+
animation: none;
|
|
166
|
+
}
|
|
167
|
+
@keyframes fabPulse {
|
|
168
|
+
0%, 100% { box-shadow: 0 4px 20px rgba(0,0,0,0.2); }
|
|
169
|
+
50% { box-shadow: 0 4px 20px rgba(0,0,0,0.2), 0 0 0 8px color-mix(in srgb, var(--color-accent) 20%, transparent); }
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.chat-panel {
|
|
173
|
+
position: fixed;
|
|
174
|
+
bottom: 5.5rem;
|
|
175
|
+
right: 1.5rem;
|
|
176
|
+
z-index: 1000;
|
|
177
|
+
width: 380px;
|
|
178
|
+
max-height: 520px;
|
|
179
|
+
background: #fff;
|
|
180
|
+
border-radius: 1rem;
|
|
181
|
+
box-shadow: 0 20px 60px -12px rgba(0,0,0,0.25);
|
|
182
|
+
border: 1px solid #e2e8f0;
|
|
183
|
+
display: flex;
|
|
184
|
+
flex-direction: column;
|
|
185
|
+
animation: chatSlideUp 0.25s ease-out;
|
|
186
|
+
overflow: hidden;
|
|
187
|
+
}
|
|
188
|
+
@keyframes chatSlideUp {
|
|
189
|
+
from { opacity: 0; transform: translateY(16px); }
|
|
190
|
+
to { opacity: 1; transform: translateY(0); }
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
.chat-header {
|
|
194
|
+
display: flex;
|
|
195
|
+
align-items: center;
|
|
196
|
+
justify-content: space-between;
|
|
197
|
+
padding: 0.85rem 1rem;
|
|
198
|
+
border-bottom: 1px solid #f1f5f9;
|
|
199
|
+
background: #f8fafc;
|
|
200
|
+
}
|
|
201
|
+
.chat-header-title {
|
|
202
|
+
display: flex;
|
|
203
|
+
align-items: center;
|
|
204
|
+
gap: 0.5rem;
|
|
205
|
+
font-size: 0.88rem;
|
|
206
|
+
font-weight: 600;
|
|
207
|
+
color: #334155;
|
|
208
|
+
}
|
|
209
|
+
.chat-close-btn {
|
|
210
|
+
background: none;
|
|
211
|
+
border: none;
|
|
212
|
+
cursor: pointer;
|
|
213
|
+
color: #94a3b8;
|
|
214
|
+
padding: 2px;
|
|
215
|
+
border-radius: 4px;
|
|
216
|
+
display: flex;
|
|
217
|
+
transition: color 0.15s;
|
|
218
|
+
}
|
|
219
|
+
.chat-close-btn:hover { color: #475569; }
|
|
220
|
+
|
|
221
|
+
.chat-messages {
|
|
222
|
+
flex: 1;
|
|
223
|
+
overflow-y: auto;
|
|
224
|
+
padding: 1rem;
|
|
225
|
+
display: flex;
|
|
226
|
+
flex-direction: column;
|
|
227
|
+
gap: 0.6rem;
|
|
228
|
+
min-height: 200px;
|
|
229
|
+
max-height: 340px;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
.chat-empty {
|
|
233
|
+
display: flex;
|
|
234
|
+
align-items: center;
|
|
235
|
+
justify-content: center;
|
|
236
|
+
height: 100%;
|
|
237
|
+
min-height: 120px;
|
|
238
|
+
color: #94a3b8;
|
|
239
|
+
font-size: 0.88rem;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
.chat-bubble {
|
|
243
|
+
max-width: 85%;
|
|
244
|
+
padding: 0.6rem 0.85rem;
|
|
245
|
+
border-radius: 1rem;
|
|
246
|
+
font-size: 0.85rem;
|
|
247
|
+
line-height: 1.55;
|
|
248
|
+
word-wrap: break-word;
|
|
249
|
+
white-space: pre-wrap;
|
|
250
|
+
}
|
|
251
|
+
.chat-bubble.user {
|
|
252
|
+
align-self: flex-end;
|
|
253
|
+
background: var(--color-accent);
|
|
254
|
+
color: #fff;
|
|
255
|
+
border-bottom-right-radius: 4px;
|
|
256
|
+
}
|
|
257
|
+
.chat-bubble.assistant {
|
|
258
|
+
align-self: flex-start;
|
|
259
|
+
background: #f1f5f9;
|
|
260
|
+
color: #334155;
|
|
261
|
+
border-bottom-left-radius: 4px;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
.chat-input-area {
|
|
265
|
+
display: flex;
|
|
266
|
+
align-items: center;
|
|
267
|
+
gap: 0.5rem;
|
|
268
|
+
padding: 0.75rem 1rem;
|
|
269
|
+
border-top: 1px solid #f1f5f9;
|
|
270
|
+
}
|
|
271
|
+
.chat-input {
|
|
272
|
+
flex: 1;
|
|
273
|
+
border: 1px solid #e2e8f0;
|
|
274
|
+
border-radius: 0.5rem;
|
|
275
|
+
padding: 0.5rem 0.75rem;
|
|
276
|
+
font-size: 0.85rem;
|
|
277
|
+
font-family: inherit;
|
|
278
|
+
outline: none;
|
|
279
|
+
transition: border-color 0.15s;
|
|
280
|
+
color: #1e293b;
|
|
281
|
+
}
|
|
282
|
+
.chat-input::placeholder { color: #94a3b8; }
|
|
283
|
+
.chat-input:focus { border-color: var(--color-accent); }
|
|
284
|
+
.chat-send-btn {
|
|
285
|
+
background: var(--color-accent);
|
|
286
|
+
border: none;
|
|
287
|
+
border-radius: 0.5rem;
|
|
288
|
+
padding: 0.45rem 0.6rem;
|
|
289
|
+
cursor: pointer;
|
|
290
|
+
color: #fff;
|
|
291
|
+
display: flex;
|
|
292
|
+
align-items: center;
|
|
293
|
+
justify-content: center;
|
|
294
|
+
transition: opacity 0.15s;
|
|
295
|
+
}
|
|
296
|
+
.chat-send-btn:disabled { opacity: 0.4; cursor: not-allowed; }
|
|
297
|
+
.chat-send-btn:not(:disabled):hover { opacity: 0.85; }
|
|
298
|
+
|
|
299
|
+
/* Typing indicator */
|
|
300
|
+
.typing-indicator {
|
|
301
|
+
display: inline-flex;
|
|
302
|
+
gap: 4px;
|
|
303
|
+
align-items: center;
|
|
304
|
+
padding: 2px 0;
|
|
305
|
+
}
|
|
306
|
+
.typing-indicator span {
|
|
307
|
+
width: 6px;
|
|
308
|
+
height: 6px;
|
|
309
|
+
border-radius: 50%;
|
|
310
|
+
background: #94a3b8;
|
|
311
|
+
animation: typingBounce 1.2s infinite;
|
|
312
|
+
}
|
|
313
|
+
.typing-indicator span:nth-child(2) { animation-delay: 0.15s; }
|
|
314
|
+
.typing-indicator span:nth-child(3) { animation-delay: 0.3s; }
|
|
315
|
+
@keyframes typingBounce {
|
|
316
|
+
0%, 60%, 100% { transform: translateY(0); }
|
|
317
|
+
30% { transform: translateY(-4px); }
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
@media (max-width: 480px) {
|
|
321
|
+
.chat-panel {
|
|
322
|
+
width: calc(100vw - 2rem);
|
|
323
|
+
right: 1rem;
|
|
324
|
+
bottom: 5rem;
|
|
325
|
+
max-height: 70vh;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** @type {import('tailwindcss').Config} */
|
|
2
|
+
export default {
|
|
3
|
+
content: ['./index.html', './src/**/*.{js,jsx}'],
|
|
4
|
+
theme: {
|
|
5
|
+
extend: {
|
|
6
|
+
fontFamily: {
|
|
7
|
+
sans: ['Inter', 'system-ui', 'sans-serif'],
|
|
8
|
+
},
|
|
9
|
+
},
|
|
10
|
+
},
|
|
11
|
+
plugins: [require('@tailwindcss/typography')],
|
|
12
|
+
};
|