cookiecraft 1.0.7 → 1.0.8
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 +171 -304
- package/dist/cookiecraft.css +1 -1
- package/dist/cookiecraft.esm.js +221 -116
- package/dist/cookiecraft.esm.js.map +1 -1
- package/dist/cookiecraft.js +221 -116
- package/dist/cookiecraft.js.map +1 -1
- package/dist/cookiecraft.min.js +1 -1
- package/dist/cookiecraft.min.js.map +1 -1
- package/dist/stats.html +1 -1
- package/dist/types/blocking/CategoryManager.d.ts +1 -0
- package/dist/types/core/ConsentManager.d.ts +1 -1
- package/dist/types/core/CookieConsent.d.ts +5 -4
- package/dist/types/core/EventEmitter.d.ts +3 -2
- package/dist/types/integrations/GTMConsentMode.d.ts +0 -6
- package/dist/types/types/index.d.ts +3 -7
- package/dist/types/ui/Banner.d.ts +6 -0
- package/dist/types/ui/PreferenceCenter.d.ts +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,86 +1,73 @@
|
|
|
1
1
|
# CookieCraft
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/cookiecraft)
|
|
4
|
+
[](https://bundlephobia.com/package/cookiecraft)
|
|
5
|
+
[](https://github.com/Fz3dev/cookiecraft/blob/main/LICENSE)
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
**Lightweight GDPR-compliant cookie consent library for any website.**
|
|
8
|
+
|
|
9
|
+
Zero dependencies. Modern UI. Google Consent Mode v2 built-in. Works on Webflow, WordPress, Shopify, or any site.
|
|
10
|
+
|
|
11
|
+
[Live Configurator](https://fz3dev.github.io/cookiecraft/settings.html) | [Demo](https://fz3dev.github.io/cookiecraft/)
|
|
6
12
|
|
|
7
13
|
## Features
|
|
8
14
|
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
15
|
+
- **GDPR Compliant** — Full opt-in mode, script blocking before consent, cookie purge on rejection
|
|
16
|
+
- **Lightweight** — < 15KB total (JS + CSS), zero runtime dependencies
|
|
17
|
+
- **Modern UI** — Clean design, dark/light/auto themes, smooth animations
|
|
18
|
+
- **GTM Ready** — Google Consent Mode v2 built-in (ad_storage, analytics_storage, etc.)
|
|
19
|
+
- **Accessible** — WCAG 2.2 AA, focus trapping, keyboard navigation, ARIA attributes
|
|
20
|
+
- **Customizable** — Primary color, layouts, positions, translations, CSS variables
|
|
21
|
+
- **Universal** — Works on any website via CDN (Webflow, WordPress, Shopify, custom)
|
|
22
|
+
- **Script Blocking** — Prevents tracking scripts from firing before consent
|
|
23
|
+
- **Floating Widget** — Persistent button for users to update preferences anytime
|
|
24
|
+
- **Visual Configurator** — No-code setup tool that generates ready-to-paste code
|
|
19
25
|
|
|
20
26
|
## Quick Start
|
|
21
27
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
Add this code in **Site Settings > Custom Code > Footer**:
|
|
28
|
+
Add this before `</body>` on your site:
|
|
25
29
|
|
|
26
30
|
```html
|
|
27
|
-
|
|
28
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/cookiecraft@1/dist/cookiecraft.min.css">
|
|
29
|
-
|
|
30
|
-
<!-- JavaScript -->
|
|
31
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/cookiecraft@1/dist/cookiecraft.css">
|
|
31
32
|
<script src="https://cdn.jsdelivr.net/npm/cookiecraft@1/dist/cookiecraft.min.js"></script>
|
|
32
33
|
|
|
33
|
-
<!-- Initialize -->
|
|
34
34
|
<script>
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
analytics: {
|
|
48
|
-
enabled: false,
|
|
49
|
-
readOnly: false,
|
|
50
|
-
label: 'Statistiques',
|
|
51
|
-
description: 'Pour comprendre comment vous utilisez notre site'
|
|
52
|
-
},
|
|
53
|
-
marketing: {
|
|
54
|
-
enabled: false,
|
|
55
|
-
readOnly: false,
|
|
56
|
-
label: 'Marketing',
|
|
57
|
-
description: 'Pour vous proposer du contenu personnalisé'
|
|
58
|
-
}
|
|
59
|
-
},
|
|
60
|
-
|
|
61
|
-
theme: 'auto',
|
|
62
|
-
primaryColor: '#0066cc'
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
cookieConsent.init();
|
|
35
|
+
new CookieCraft.CookieConsent({
|
|
36
|
+
primaryColor: '#0066cc',
|
|
37
|
+
categories: {
|
|
38
|
+
necessary: { enabled: true, readOnly: true, label: 'Essential', description: 'Required for the website to function.' },
|
|
39
|
+
analytics: { enabled: true, readOnly: false, label: 'Analytics', description: 'Help us understand how you use our site.' },
|
|
40
|
+
marketing: { enabled: true, readOnly: false, label: 'Marketing', description: 'Used to deliver relevant ads.' }
|
|
41
|
+
},
|
|
42
|
+
translations: {
|
|
43
|
+
title: 'Your privacy matters',
|
|
44
|
+
description: 'We use cookies to improve your experience. You choose which ones you accept.'
|
|
45
|
+
}
|
|
46
|
+
}).init();
|
|
66
47
|
</script>
|
|
67
48
|
```
|
|
68
49
|
|
|
69
|
-
|
|
50
|
+
Or use the **[Visual Configurator](https://fz3dev.github.io/cookiecraft/settings.html)** to generate your code without writing anything.
|
|
51
|
+
|
|
52
|
+
### Platform-specific instructions
|
|
53
|
+
|
|
54
|
+
**Webflow** — Paste in Site Settings > Custom Code > Footer Code.
|
|
55
|
+
|
|
56
|
+
**WordPress** — Paste in your theme's `footer.php` before `</body>`, or use a "Insert Headers and Footers" plugin.
|
|
70
57
|
|
|
71
|
-
|
|
58
|
+
**Shopify** — Paste in Online Store > Themes > Edit Code > `theme.liquid` before `</body>`.
|
|
59
|
+
|
|
60
|
+
## Script Blocking
|
|
61
|
+
|
|
62
|
+
Change tracking scripts to `type="text/plain"` with a `data-cookieconsent` attribute. CookieCraft blocks them until the user consents:
|
|
72
63
|
|
|
73
64
|
```html
|
|
74
|
-
<!-- Google Analytics
|
|
75
|
-
<script type="text/plain" data-cookieconsent="analytics"
|
|
76
|
-
|
|
77
|
-
ga('create', 'UA-XXXXX-Y', 'auto');
|
|
78
|
-
ga('send', 'pageview');
|
|
79
|
-
</script>
|
|
65
|
+
<!-- Google Analytics — blocked until analytics consent -->
|
|
66
|
+
<script type="text/plain" data-cookieconsent="analytics"
|
|
67
|
+
src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXX"></script>
|
|
80
68
|
|
|
81
|
-
<!-- Facebook Pixel
|
|
69
|
+
<!-- Facebook Pixel — blocked until marketing consent -->
|
|
82
70
|
<script type="text/plain" data-cookieconsent="marketing">
|
|
83
|
-
!function(f,b,e,v,n,t,s){...}
|
|
84
71
|
fbq('init', 'YOUR_PIXEL_ID');
|
|
85
72
|
fbq('track', 'PageView');
|
|
86
73
|
</script>
|
|
@@ -88,160 +75,56 @@ Change your tracking scripts to use `type="text/plain"` and `data-cookieconsent`
|
|
|
88
75
|
|
|
89
76
|
## Layout Options
|
|
90
77
|
|
|
91
|
-
Choose from multiple banner styles and positions to match your site's design:
|
|
92
|
-
|
|
93
78
|
### Banner Layouts
|
|
94
79
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
80
|
+
| Layout | Description |
|
|
81
|
+
|---|---|
|
|
82
|
+
| `bar` | Full-width banner at top or bottom |
|
|
83
|
+
| `box` | Compact modal in corner or center |
|
|
84
|
+
| `floating` | Small notification-style banner |
|
|
98
85
|
|
|
99
|
-
###
|
|
86
|
+
### Positions
|
|
100
87
|
|
|
101
|
-
|
|
102
|
-
- **`top`** - Top of the screen
|
|
103
|
-
- **`center`** - Centered modal with overlay
|
|
104
|
-
- **`bottom-left`** - Bottom left corner
|
|
105
|
-
- **`bottom-right`** - Bottom right corner
|
|
88
|
+
`bottom` (default), `top`, `center`, `bottom-left`, `bottom-right`
|
|
106
89
|
|
|
107
90
|
### Floating Widget
|
|
108
91
|
|
|
109
|
-
A permanent button that stays visible after consent,
|
|
92
|
+
A permanent button that stays visible after consent, letting users modify preferences:
|
|
110
93
|
|
|
111
|
-
|
|
112
|
-
|
|
94
|
+
```javascript
|
|
95
|
+
new CookieCraft.CookieConsent({
|
|
96
|
+
showWidget: true, // default: true
|
|
97
|
+
widgetPosition: 'bottom-left', // default: 'bottom-left'
|
|
98
|
+
widgetStyle: 'compact', // 'compact' or 'full'
|
|
99
|
+
});
|
|
100
|
+
```
|
|
113
101
|
|
|
114
102
|
### Examples
|
|
115
103
|
|
|
116
104
|
```javascript
|
|
117
105
|
// Full-width bar at bottom (classic)
|
|
118
|
-
|
|
119
|
-
layout: 'bar',
|
|
120
|
-
position: 'bottom',
|
|
121
|
-
showWidget: true,
|
|
122
|
-
widgetPosition: 'bottom-right'
|
|
123
|
-
});
|
|
106
|
+
new CookieCraft.CookieConsent({ layout: 'bar', position: 'bottom' }).init();
|
|
124
107
|
|
|
125
|
-
//
|
|
126
|
-
|
|
127
|
-
layout: 'box',
|
|
128
|
-
position: 'bottom-right',
|
|
129
|
-
showWidget: true,
|
|
130
|
-
widgetPosition: 'bottom-left' // Widget on opposite side
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
// Compact floating notification (minimal)
|
|
134
|
-
const consent = new CookieCraft.CookieConsent({
|
|
135
|
-
layout: 'floating',
|
|
136
|
-
position: 'bottom-right',
|
|
137
|
-
showWidget: false // No widget needed, already compact
|
|
138
|
-
});
|
|
108
|
+
// Compact box in bottom-right (modern)
|
|
109
|
+
new CookieCraft.CookieConsent({ layout: 'box', position: 'bottom-right' }).init();
|
|
139
110
|
|
|
140
111
|
// Centered modal with overlay (maximum attention)
|
|
141
|
-
|
|
112
|
+
new CookieCraft.CookieConsent({
|
|
142
113
|
layout: 'box',
|
|
143
114
|
position: 'center',
|
|
144
|
-
disablePageInteraction: true
|
|
145
|
-
|
|
146
|
-
});
|
|
115
|
+
disablePageInteraction: true
|
|
116
|
+
}).init();
|
|
147
117
|
```
|
|
148
118
|
|
|
149
|
-
##
|
|
119
|
+
## GTM Consent Mode v2
|
|
150
120
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
```typescript
|
|
154
|
-
interface ConsentConfig {
|
|
155
|
-
// Core settings
|
|
156
|
-
mode: 'opt-in' | 'opt-out'; // GDPR requires 'opt-in'
|
|
157
|
-
autoShow: boolean; // Show banner on first visit
|
|
158
|
-
revision: number; // Policy version (increment to re-ask)
|
|
159
|
-
|
|
160
|
-
// Categories
|
|
161
|
-
categories: {
|
|
162
|
-
necessary: CategoryConfig;
|
|
163
|
-
analytics: CategoryConfig;
|
|
164
|
-
marketing: CategoryConfig;
|
|
165
|
-
preferences?: CategoryConfig;
|
|
166
|
-
};
|
|
167
|
-
|
|
168
|
-
// UI customization
|
|
169
|
-
theme?: 'light' | 'dark' | 'auto';
|
|
170
|
-
layout?: 'bar' | 'box' | 'floating'; // Banner layout style
|
|
171
|
-
position?: 'bottom' | 'top' | 'center' | 'bottom-left' | 'bottom-right';
|
|
172
|
-
primaryColor?: string; // Hex color
|
|
173
|
-
backdropBlur?: boolean; // Backdrop blur effect
|
|
174
|
-
animationStyle?: 'smooth' | 'minimal';
|
|
175
|
-
|
|
176
|
-
// Floating widget
|
|
177
|
-
showWidget?: boolean; // Show permanent settings button
|
|
178
|
-
widgetPosition?: 'bottom-left' | 'bottom-right' | 'top-left' | 'top-right';
|
|
179
|
-
|
|
180
|
-
// Content
|
|
181
|
-
translations?: Translation;
|
|
182
|
-
|
|
183
|
-
// Integration
|
|
184
|
-
gtmConsentMode?: boolean; // Enable GTM Consent Mode v2
|
|
185
|
-
|
|
186
|
-
// Accessibility
|
|
187
|
-
disablePageInteraction?: boolean; // Block page until consent
|
|
188
|
-
|
|
189
|
-
// Callbacks
|
|
190
|
-
onAccept?: (categories) => void;
|
|
191
|
-
onChange?: (categories) => void;
|
|
192
|
-
onReject?: () => void;
|
|
193
|
-
}
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
### Category Configuration
|
|
197
|
-
|
|
198
|
-
```typescript
|
|
199
|
-
interface CategoryConfig {
|
|
200
|
-
enabled: boolean; // Default state
|
|
201
|
-
readOnly: boolean; // If true, user cannot toggle
|
|
202
|
-
label: string; // Display name
|
|
203
|
-
description: string; // Explanation
|
|
204
|
-
}
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
### Customization Examples
|
|
208
|
-
|
|
209
|
-
#### Custom Colors
|
|
210
|
-
|
|
211
|
-
```javascript
|
|
212
|
-
const cookieConsent = new CookieCraft.CookieConsent({
|
|
213
|
-
primaryColor: '#ff6b6b', // Red theme
|
|
214
|
-
theme: 'dark',
|
|
215
|
-
// ...
|
|
216
|
-
});
|
|
217
|
-
```
|
|
218
|
-
|
|
219
|
-
#### Custom Text
|
|
220
|
-
|
|
221
|
-
```javascript
|
|
222
|
-
const cookieConsent = new CookieCraft.CookieConsent({
|
|
223
|
-
translations: {
|
|
224
|
-
title: 'Nous respectons votre vie privée',
|
|
225
|
-
description: 'Choisissez les cookies que vous acceptez',
|
|
226
|
-
acceptAll: 'Tout accepter',
|
|
227
|
-
rejectAll: 'Tout refuser',
|
|
228
|
-
customize: 'Personnaliser',
|
|
229
|
-
savePreferences: 'Enregistrer',
|
|
230
|
-
cookieSettings: 'Paramètres cookies', // Floating widget tooltip
|
|
231
|
-
cookies: 'Cookies', // Floating widget text
|
|
232
|
-
},
|
|
233
|
-
// ...
|
|
234
|
-
});
|
|
235
|
-
```
|
|
236
|
-
|
|
237
|
-
#### With GTM Consent Mode v2
|
|
121
|
+
CookieCraft natively supports Google Consent Mode v2. Just enable it:
|
|
238
122
|
|
|
239
123
|
```html
|
|
240
|
-
<!-- In HEAD,
|
|
124
|
+
<!-- In HEAD, before GTM -->
|
|
241
125
|
<script>
|
|
242
126
|
window.dataLayer = window.dataLayer || [];
|
|
243
127
|
function gtag(){dataLayer.push(arguments);}
|
|
244
|
-
|
|
245
128
|
gtag('consent', 'default', {
|
|
246
129
|
'ad_storage': 'denied',
|
|
247
130
|
'analytics_storage': 'denied',
|
|
@@ -253,166 +136,150 @@ const cookieConsent = new CookieCraft.CookieConsent({
|
|
|
253
136
|
<!-- Google Tag Manager -->
|
|
254
137
|
<script>(function(w,d,s,l,i){...})(window,document,'script','dataLayer','GTM-XXXX');</script>
|
|
255
138
|
|
|
256
|
-
<!-- In FOOTER -->
|
|
139
|
+
<!-- In FOOTER, with CookieCraft -->
|
|
257
140
|
<script>
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
cookieConsent.init();
|
|
141
|
+
new CookieCraft.CookieConsent({
|
|
142
|
+
gtmConsentMode: true,
|
|
143
|
+
// ...
|
|
144
|
+
}).init();
|
|
263
145
|
</script>
|
|
264
146
|
```
|
|
265
147
|
|
|
266
|
-
|
|
148
|
+
CookieCraft automatically maps categories to GTM signals:
|
|
267
149
|
|
|
268
|
-
|
|
150
|
+
| Category | GTM Signals |
|
|
151
|
+
|---|---|
|
|
152
|
+
| `marketing` | `ad_storage`, `ad_user_data`, `ad_personalization` |
|
|
153
|
+
| `analytics` | `analytics_storage` |
|
|
154
|
+
| `preferences` | `functionality_storage`, `personalization_storage` |
|
|
269
155
|
|
|
270
|
-
|
|
271
|
-
// Initialize
|
|
272
|
-
cookieConsent.init();
|
|
156
|
+
## Configuration
|
|
273
157
|
|
|
274
|
-
|
|
275
|
-
|
|
158
|
+
```typescript
|
|
159
|
+
interface ConsentConfig {
|
|
160
|
+
// Core
|
|
161
|
+
mode?: 'opt-in' | 'opt-out'; // default: 'opt-in'
|
|
162
|
+
autoShow?: boolean; // default: true
|
|
163
|
+
revision?: number; // increment to re-ask consent
|
|
276
164
|
|
|
277
|
-
//
|
|
278
|
-
|
|
165
|
+
// Categories
|
|
166
|
+
categories?: Record<string, {
|
|
167
|
+
enabled: boolean;
|
|
168
|
+
readOnly: boolean;
|
|
169
|
+
label: string;
|
|
170
|
+
description: string;
|
|
171
|
+
}>;
|
|
172
|
+
|
|
173
|
+
// Appearance
|
|
174
|
+
theme?: 'light' | 'dark' | 'auto'; // default: 'light'
|
|
175
|
+
layout?: 'bar' | 'box' | 'floating'; // default: 'box'
|
|
176
|
+
position?: string; // default: 'bottom-left'
|
|
177
|
+
primaryColor?: string; // hex color
|
|
178
|
+
backdropBlur?: boolean;
|
|
179
|
+
animationStyle?: 'smooth' | 'minimal';
|
|
279
180
|
|
|
280
|
-
//
|
|
281
|
-
|
|
181
|
+
// Widget
|
|
182
|
+
showWidget?: boolean; // default: true
|
|
183
|
+
widgetPosition?: string; // default: 'bottom-left'
|
|
184
|
+
widgetStyle?: 'compact' | 'full'; // default: 'compact'
|
|
282
185
|
|
|
283
|
-
//
|
|
284
|
-
|
|
285
|
-
// Returns: { version, timestamp, categories, expiresAt }
|
|
186
|
+
// Content
|
|
187
|
+
translations?: Translation;
|
|
286
188
|
|
|
287
|
-
//
|
|
288
|
-
|
|
189
|
+
// GTM
|
|
190
|
+
gtmConsentMode?: boolean; // default: false
|
|
289
191
|
|
|
290
|
-
//
|
|
291
|
-
|
|
292
|
-
console.log('Accepted:', categories);
|
|
293
|
-
});
|
|
192
|
+
// Accessibility
|
|
193
|
+
disablePageInteraction?: boolean; // default: false
|
|
294
194
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
195
|
+
// Callbacks
|
|
196
|
+
onAccept?: (categories) => void;
|
|
197
|
+
onChange?: (categories) => void;
|
|
198
|
+
onReject?: () => void;
|
|
199
|
+
}
|
|
298
200
|
```
|
|
299
201
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
- `consent:init` - Library initialized
|
|
303
|
-
- `consent:show` - Banner shown
|
|
304
|
-
- `consent:accept` - All accepted
|
|
305
|
-
- `consent:reject` - All rejected
|
|
306
|
-
- `consent:update` - Consent changed
|
|
307
|
-
- `consent:load` - Stored consent loaded
|
|
308
|
-
- `preferences:show` - Preferences modal shown
|
|
309
|
-
- `script:activated` - Script unblocked
|
|
310
|
-
|
|
311
|
-
### Cookie Settings Access
|
|
312
|
-
|
|
313
|
-
#### Option 1: Floating Widget (Automatic)
|
|
314
|
-
|
|
315
|
-
The library automatically shows a permanent floating button after consent (enabled by default):
|
|
202
|
+
## API
|
|
316
203
|
|
|
317
204
|
```javascript
|
|
318
|
-
const
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
205
|
+
const cc = new CookieCraft.CookieConsent({ /* config */ });
|
|
206
|
+
|
|
207
|
+
cc.init(); // Initialize and show banner if needed
|
|
208
|
+
cc.show(); // Show banner manually
|
|
209
|
+
cc.hide(); // Hide banner
|
|
210
|
+
cc.showPreferences(); // Open preferences modal
|
|
211
|
+
cc.getConsent(); // Get current consent record
|
|
212
|
+
cc.reset(); // Clear consent and re-show banner
|
|
213
|
+
cc.destroy(); // Remove all UI elements
|
|
214
|
+
|
|
215
|
+
// Events
|
|
216
|
+
cc.on('consent:accept', (categories) => { /* ... */ });
|
|
217
|
+
cc.on('consent:reject', (categories) => { /* ... */ });
|
|
218
|
+
cc.on('consent:update', (categories) => { /* ... */ });
|
|
219
|
+
cc.on('preferences:show', () => { /* ... */ });
|
|
220
|
+
cc.on('script:activated', (script) => { /* ... */ });
|
|
323
221
|
```
|
|
324
222
|
|
|
325
|
-
|
|
223
|
+
### All Events
|
|
326
224
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
225
|
+
| Event | Payload | Description |
|
|
226
|
+
|---|---|---|
|
|
227
|
+
| `consent:init` | — | Library initialized |
|
|
228
|
+
| `consent:show` | — | Banner shown |
|
|
229
|
+
| `consent:accept` | `categories` | User accepted all |
|
|
230
|
+
| `consent:reject` | `categories` | User rejected non-essential |
|
|
231
|
+
| `consent:update` | `categories` | Consent changed via preferences |
|
|
232
|
+
| `consent:load` | `record` | Stored consent loaded |
|
|
233
|
+
| `preferences:show` | — | Preferences modal opened |
|
|
234
|
+
| `preferences:hide` | — | Preferences modal closed |
|
|
235
|
+
| `script:activated` | `element` | Blocked script re-enabled |
|
|
336
236
|
|
|
337
237
|
## Styling
|
|
338
238
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
Customize appearance using CSS variables:
|
|
239
|
+
Override any style with CSS variables:
|
|
342
240
|
|
|
343
241
|
```css
|
|
344
242
|
:root {
|
|
345
|
-
/* Colors */
|
|
346
243
|
--cc-primary: #0066cc;
|
|
347
244
|
--cc-bg: #ffffff;
|
|
348
245
|
--cc-text: #1a1a1a;
|
|
349
246
|
--cc-text-secondary: #666666;
|
|
350
|
-
|
|
351
|
-
/* Spacing */
|
|
352
247
|
--cc-padding: 1.5rem;
|
|
353
248
|
--cc-gap: 0.75rem;
|
|
354
|
-
|
|
355
|
-
/* Borders */
|
|
356
249
|
--cc-border-radius: 12px;
|
|
357
250
|
--cc-shadow: 0 -4px 24px rgba(0, 0, 0, 0.12);
|
|
358
|
-
|
|
359
|
-
/* Animations */
|
|
360
251
|
--cc-transition: 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
361
252
|
}
|
|
362
253
|
```
|
|
363
254
|
|
|
364
255
|
## Browser Support
|
|
365
256
|
|
|
366
|
-
|
|
367
|
-
- Firefox (last 2 versions)
|
|
368
|
-
- Safari (last 2 versions)
|
|
369
|
-
- iOS Safari (last 2 versions)
|
|
370
|
-
- Chrome Android (last 2 versions)
|
|
371
|
-
|
|
372
|
-
## Development
|
|
373
|
-
|
|
374
|
-
```bash
|
|
375
|
-
# Install dependencies
|
|
376
|
-
npm install
|
|
377
|
-
|
|
378
|
-
# Dev mode with watch
|
|
379
|
-
npm run dev
|
|
257
|
+
Chrome, Edge, Firefox, Safari (last 2 versions), iOS Safari, Chrome Android.
|
|
380
258
|
|
|
381
|
-
|
|
382
|
-
npm run build
|
|
259
|
+
## Why CookieCraft?
|
|
383
260
|
|
|
384
|
-
|
|
385
|
-
|
|
261
|
+
| | CookieCraft | Cookiebot | OneTrust |
|
|
262
|
+
|---|---|---|---|
|
|
263
|
+
| **Price** | Free | From 12/mo | From 200/mo |
|
|
264
|
+
| **Size** | ~15KB | ~100KB+ | ~150KB+ |
|
|
265
|
+
| **Dependencies** | 0 | Multiple | Multiple |
|
|
266
|
+
| **Self-hosted** | Yes | No | No |
|
|
267
|
+
| **GTM Consent Mode v2** | Yes | Yes | Yes |
|
|
268
|
+
| **Visual Configurator** | Yes | Dashboard | Dashboard |
|
|
269
|
+
| **Open Source** | MIT | No | No |
|
|
386
270
|
|
|
387
|
-
|
|
388
|
-
npm run type-check
|
|
271
|
+
## Development
|
|
389
272
|
|
|
390
|
-
|
|
391
|
-
npm
|
|
273
|
+
```bash
|
|
274
|
+
npm install # Install dependencies
|
|
275
|
+
npm run dev # Watch mode
|
|
276
|
+
npm run build # Production build
|
|
277
|
+
npm test # Run tests
|
|
278
|
+
npm run lint # Lint
|
|
279
|
+
npm run type-check # TypeScript check
|
|
280
|
+
npm run size # Bundle size check
|
|
392
281
|
```
|
|
393
282
|
|
|
394
|
-
## Why This Library?
|
|
395
|
-
|
|
396
|
-
### vs Premium Solutions
|
|
397
|
-
|
|
398
|
-
- **Cost**: Free vs €39+/month
|
|
399
|
-
- **Performance**: 10-15KB vs 50-100KB+
|
|
400
|
-
- **Privacy**: Self-hosted option vs SaaS only
|
|
401
|
-
- **Flexibility**: Full code access vs black box
|
|
402
|
-
|
|
403
|
-
## Contributing
|
|
404
|
-
|
|
405
|
-
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
406
|
-
|
|
407
283
|
## License
|
|
408
284
|
|
|
409
|
-
MIT
|
|
410
|
-
|
|
411
|
-
## Credits
|
|
412
|
-
|
|
413
|
-
Inspired by:
|
|
414
|
-
- [vanilla-cookieconsent](https://github.com/orestbida/cookieconsent) - Technical patterns
|
|
415
|
-
|
|
416
|
-
---
|
|
417
|
-
|
|
418
|
-
Made with ❤️ for the open web
|
|
285
|
+
MIT
|
package/dist/cookiecraft.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.cc-banner,.cc-modal,.cc-widget{--cc-primary:#1a1a1a;--cc-primary-hover:#333;--cc-primary-glow:color-mix(in srgb,var(--cc-primary) 30%,transparent);--cc-bg:#fff;--cc-text:#1a1a1a;--cc-text-secondary:#666;--cc-border:#e5e7eb;--cc-overlay:rgba(0,0,0,.4);--cc-padding:1.125rem;--cc-gap:0.5rem;--cc-border-radius:12px;--cc-shadow:0 -4px 24px rgba(0,0,0,.12);--cc-transition:0.3s cubic-bezier(0.4,0,0.2,1);--cc-backdrop-blur:10px;--cc-font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif}.cc-banner *,.cc-modal *,.cc-widget *{box-sizing:border-box;margin:0;padding:0}.cc-banner{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;background:var(--cc-bg);bottom:0;box-shadow:var(--cc-shadow);font-family:var(--cc-font-family);left:0;padding:var(--cc-padding);position:fixed;right:0;transform:translateY(100%);transition:transform var(--cc-transition);z-index:9999}.cc-banner.cc-backdrop-blur{backdrop-filter:blur(var(--cc-backdrop-blur));background:hsla(0,0%,100%,.95)}.cc-banner.is-visible{transform:translateY(0)}.cc-banner__container{margin:0 auto;max-width:1200px}.cc-banner__content{margin-bottom:1rem}.cc-banner__title{color:var(--cc-text);font-size:.9375rem;font-weight:600;letter-spacing:-.01em;line-height:1.3;margin:0 0 .375rem}.cc-banner__description{color:var(--cc-text-secondary);font-size:.8125rem;line-height:1.5;margin:0}.cc-banner__description a{color:var(--cc-primary);font-weight:500;text-decoration:none;transition:all .2s ease}.cc-banner__description a:hover{color:var(--cc-primary-hover);text-decoration:underline}.cc-banner__actions{display:flex;flex-wrap:wrap;gap:var(--cc-gap)}.cc-btn{align-items:center;border:none;border-radius:8px;cursor:pointer;display:inline-flex;font-family:inherit;font-size:.8125rem;font-weight:500;justify-content:center;letter-spacing:-.01em;min-height:36px;min-width:36px;padding:.5rem 1.125rem;text-decoration:none;transition:all .2s ease}.cc-btn:focus-visible{outline:3px solid var(--cc-primary);outline-offset:2px}.cc-btn:disabled{cursor:not-allowed;opacity:.6}.cc-btn--accept{background:var(--cc-primary);color:#fff}.cc-btn--accept:hover:not(:disabled){background:var(--cc-primary-hover);box-shadow:0 4px 12px var(--cc-primary-glow);transform:translateY(-1px)}.cc-btn--accept:active:not(:disabled){transform:translateY(0)}.cc-btn--ghost{background:transparent;color:var(--cc-text-secondary);font-size:.75rem;padding:.5rem .75rem}.cc-btn--ghost:hover:not(:disabled){color:var(--cc-text);text-decoration:underline}.cc-btn--ghost:active:not(:disabled){transform:translateY(0)}.cc-btn--primary{background:var(--cc-primary);color:#fff}.cc-btn--primary:hover:not(:disabled){background:var(--cc-primary-hover);box-shadow:0 4px 12px var(--cc-primary-glow);transform:translateY(-1px)}.cc-btn--primary:active:not(:disabled){transform:translateY(0)}.cc-btn--secondary{background:#f3f4f6;color:var(--cc-text)}.cc-btn--secondary:hover:not(:disabled){background:#e5e7eb;transform:translateY(-1px)}.cc-btn--secondary:active:not(:disabled){transform:translateY(0)}.cc-btn--tertiary{background:transparent;border:1px solid var(--cc-border);color:var(--cc-text-secondary)}.cc-btn--tertiary:hover:not(:disabled){background:rgba(0,0,0,.03);color:var(--cc-text);transform:translateY(-1px)}.cc-btn--tertiary:active:not(:disabled){transform:translateY(0)}@media (min-width:768px){.cc-banner--bar .cc-banner__container{align-items:center;display:flex;gap:2rem;justify-content:space-between}.cc-banner--bar .cc-banner__content{flex:1;margin-bottom:0}.cc-banner--bar .cc-banner__actions{flex-shrink:0}}.cc-banner--top{bottom:auto;box-shadow:0 4px 24px rgba(0,0,0,.12);top:0;transform:translateY(-100%)}.cc-banner--top.is-visible{transform:translateY(0)}.cc-banner--center{border-radius:var(--cc-border-radius);bottom:auto;left:50%;max-width:600px;opacity:0;right:auto;top:50%;transform:translate(-50%,-50%) scale(.9)}.cc-banner--center.is-visible{opacity:1;transform:translate(-50%,-50%) scale(1)}.cc-banner--bottom-right{border-radius:var(--cc-border-radius);bottom:1.5rem;left:auto;max-width:420px;right:1.5rem;transform:translateX(calc(100% + 2rem))}.cc-banner--bottom-right.is-visible{transform:translateX(0)}.cc-banner--bottom-left{border-radius:var(--cc-border-radius);bottom:1.5rem;left:1.5rem;max-width:420px;right:auto;transform:translateX(calc(-100% - 2rem))}.cc-banner--bottom-left.is-visible{transform:translateX(0)}.cc-banner--box{border-radius:var(--cc-border-radius);max-width:420px}.cc-banner--box .cc-banner__container{display:block}.cc-banner--box .cc-banner__actions{flex-direction:column;margin-top:1rem}.cc-banner--box .cc-banner__actions .cc-btn{width:100%}.cc-banner--floating{border-radius:var(--cc-border-radius);box-shadow:0 8px 32px rgba(0,0,0,.2);max-width:380px}.cc-banner--floating .cc-banner__container{display:block}.cc-banner--floating .cc-banner__title{font-size:1rem}.cc-banner--floating .cc-banner__description{font-size:.8125rem}.cc-banner--floating .cc-banner__actions{flex-direction:column;margin-top:1rem}.cc-banner--floating .cc-banner__actions .cc-btn{font-size:.8125rem;padding:.625rem 1rem;width:100%}@media (prefers-color-scheme:dark){.cc-banner[data-theme=auto]{--cc-bg:#1a1a1a;--cc-text:#fff;--cc-text-secondary:#a0a0a0;--cc-border:#333}.cc-banner[data-theme=auto].cc-backdrop-blur{background:rgba(26,26,26,.95)}.cc-banner[data-theme=auto] .cc-btn--secondary{background:#2a2a2a;color:#fff}.cc-banner[data-theme=auto] .cc-btn--secondary:hover:not(:disabled){background:#333}.cc-banner[data-theme=auto] .cc-btn--reject{background:#fff;color:#1a1a1a}.cc-banner[data-theme=auto] .cc-btn--tertiary{border-color:#555;color:#a0a0a0}}.cc-banner[data-theme=dark]{--cc-bg:#1a1a1a;--cc-text:#fff;--cc-text-secondary:#a0a0a0;--cc-border:#333}.cc-banner[data-theme=dark].cc-backdrop-blur{background:rgba(26,26,26,.95)}.cc-banner[data-theme=dark] .cc-btn--secondary{background:#2a2a2a;color:#fff}.cc-banner[data-theme=dark] .cc-btn--secondary:hover:not(:disabled){background:#333}.cc-banner[data-theme=dark] .cc-btn--reject{background:#fff;color:#1a1a1a}.cc-banner[data-theme=dark] .cc-btn--tertiary{border-color:#555;color:#a0a0a0}@keyframes cc-fadeIn{0%{opacity:0}to{opacity:1}}@keyframes cc-slideUp{0%{opacity:0;transform:translateY(100%)}to{opacity:1;transform:translateY(0)}}@keyframes cc-slideDown{0%{opacity:0;transform:translateY(-100%)}to{opacity:1;transform:translateY(0)}}@keyframes cc-scaleIn{0%{opacity:0;transform:scale(.9)}to{opacity:1;transform:scale(1)}}@keyframes cc-backdropFadeIn{0%{opacity:0}to{opacity:1}}.cc-animate-fadeIn{animation:cc-fadeIn .3s ease-out}.cc-animate-slideUp{animation:cc-slideUp .4s cubic-bezier(.4,0,.2,1)}.cc-animate-slideDown{animation:cc-slideDown .4s cubic-bezier(.4,0,.2,1)}.cc-animate-scaleIn{animation:cc-scaleIn .3s cubic-bezier(.4,0,.2,1)}@media (prefers-reduced-motion:reduce){.cc-banner{transition:none}.cc-animate-fadeIn,.cc-animate-scaleIn,.cc-animate-slideDown,.cc-animate-slideUp{animation:none}.cc-btn{transition:none}}.cc-modal{align-items:center;bottom:0;display:flex;justify-content:center;left:0;opacity:0;padding:1rem;pointer-events:none;position:fixed;right:0;top:0;transition:opacity var(--cc-transition);z-index:10000}.cc-modal.is-visible{opacity:1;pointer-events:all}.cc-modal__overlay{background:var(--cc-overlay);bottom:0;cursor:pointer;left:0;position:absolute;right:0;top:0}.cc-modal__content{background:var(--cc-bg);border-radius:var(--cc-border-radius);box-shadow:0 16px 48px rgba(0,0,0,.18),0 4px 12px rgba(0,0,0,.08);display:flex;flex-direction:column;max-height:90vh;max-width:480px;overflow:hidden;position:relative;transform:scale(.9);transition:transform var(--cc-transition);width:100%}.cc-modal.is-visible .cc-modal__content{transform:scale(1)}.cc-modal__header{align-items:center;background:linear-gradient(135deg,var(--cc-primary) 0,var(--cc-primary-hover) 100%);display:flex;flex-shrink:0;justify-content:space-between;padding:1.125rem 1.25rem}.cc-modal__header h2{color:#fff;font-size:.95rem;font-weight:600;letter-spacing:-.01em;margin:0}.cc-modal__close{align-items:center;background:hsla(0,0%,100%,.15);border:none;border-radius:6px;color:#fff;cursor:pointer;display:flex;justify-content:center;padding:.375rem;transition:all .2s ease}.cc-modal__close svg{height:18px;width:18px}.cc-modal__close:hover{background:hsla(0,0%,100%,.3);transform:scale(1.05)}.cc-modal__close:focus-visible{outline:2px solid hsla(0,0%,100%,.5);outline-offset:2px}.cc-modal__body{flex:1;overflow-y:auto;padding:1rem 1.25rem}.cc-category{border-bottom:1px solid var(--cc-border);padding:.75rem 0}.cc-category:last-child{border-bottom:none}.cc-category__header{align-items:center;display:flex;gap:.75rem}.cc-category__info{flex:1}.cc-category__info h3{color:var(--cc-text);font-size:.8125rem;font-weight:600;letter-spacing:-.01em;margin:0 0 .125rem}.cc-category__info p{color:var(--cc-text-secondary);font-size:.75rem;line-height:1.4;margin:0}.cc-toggle{align-items:center;cursor:pointer;display:inline-flex;flex-shrink:0;position:relative;-webkit-user-select:none;-moz-user-select:none;user-select:none}.cc-toggle input{height:0;opacity:0;position:absolute;width:0}.cc-toggle__slider{background:#d1d5db;border-radius:10px;height:20px;position:relative;transition:background-color .2s ease;width:36px}.cc-toggle__slider:before{background:#fff;border-radius:50%;box-shadow:0 1px 3px rgba(0,0,0,.15);content:"";height:16px;left:2px;position:absolute;top:2px;transition:transform .2s ease;width:16px}.cc-toggle input:checked+.cc-toggle__slider{background:var(--cc-primary)}.cc-toggle input:checked+.cc-toggle__slider:before{transform:translateX(16px)}.cc-toggle input:focus-visible+.cc-toggle__slider{outline:2px solid var(--cc-primary);outline-offset:2px}.cc-toggle--disabled{cursor:not-allowed;opacity:.6}.cc-toggle--disabled input:checked+.cc-toggle__slider{background:#9ca3af}.cc-modal__footer{align-items:center;border-top:1px solid var(--cc-border);display:flex;flex-shrink:0;gap:var(--cc-gap);justify-content:space-between;padding:1rem 1.25rem}.cc-modal__footer-links{align-items:center;display:flex;gap:.5rem}.cc-modal__footer-actions{display:flex;gap:var(--cc-gap)}.cc-privacy-link{align-items:center;color:var(--cc-text-secondary);display:inline-flex;font-size:.875rem;gap:.25rem;text-decoration:none;transition:color .2s ease}.cc-privacy-link:hover{color:var(--cc-primary);text-decoration:underline}@media (prefers-color-scheme:dark){.cc-modal[data-theme=auto] .cc-modal__content{background:#1a1a1a}.cc-modal[data-theme=auto] .cc-category__info h3{color:#fff}.cc-modal[data-theme=auto] .cc-category__info p{color:#a0a0a0}.cc-modal[data-theme=auto] .cc-category,.cc-modal[data-theme=auto] .cc-modal__footer{border-color:#333}.cc-modal[data-theme=auto] .cc-toggle__slider{background:#444}.cc-modal[data-theme=auto] .cc-btn--secondary{background:#2a2a2a;color:#fff}.cc-modal[data-theme=auto] .cc-btn--secondary:hover:not(:disabled){background:#333}.cc-modal[data-theme=auto] .cc-modal__close:hover{background:hsla(0,0%,100%,.1)}}.cc-modal[data-theme=dark] .cc-modal__content{background:#1a1a1a}.cc-modal[data-theme=dark] .cc-category__info h3{color:#fff}.cc-modal[data-theme=dark] .cc-category__info p{color:#a0a0a0}.cc-modal[data-theme=dark] .cc-category,.cc-modal[data-theme=dark] .cc-modal__footer{border-color:#333}.cc-modal[data-theme=dark] .cc-toggle__slider{background:#444}.cc-modal[data-theme=dark] .cc-btn--secondary{background:#2a2a2a;color:#fff}.cc-modal[data-theme=dark] .cc-btn--secondary:hover:not(:disabled){background:#333}.cc-modal[data-theme=dark] .cc-modal__close:hover{background:hsla(0,0%,100%,.1)}.cc-modal--bottom-right{align-items:flex-end;justify-content:flex-end;padding:1.5rem}.cc-modal--bottom-right .cc-modal__content{max-width:450px;transform:translateX(100%)}.cc-modal--bottom-right.is-visible .cc-modal__content{transform:translateX(0)}.cc-modal--bottom-left{align-items:flex-end;justify-content:flex-start;padding:1.5rem}.cc-modal--bottom-left .cc-modal__content{max-width:450px;transform:translateX(-100%)}.cc-modal--bottom-left.is-visible .cc-modal__content{transform:translateX(0)}.cc-modal--top-right{align-items:flex-start;justify-content:flex-end;padding:1.5rem}.cc-modal--top-right .cc-modal__content{max-width:450px;transform:translateX(100%)}.cc-modal--top-right.is-visible .cc-modal__content{transform:translateX(0)}.cc-modal--top-left{align-items:flex-start;justify-content:flex-start;padding:1.5rem}.cc-modal--top-left .cc-modal__content{max-width:450px;transform:translateX(-100%)}.cc-modal--top-left.is-visible .cc-modal__content{transform:translateX(0)}@media (max-width:640px){.cc-modal{align-items:flex-end;padding:0}.cc-modal__content{border-radius:16px 16px 0 0;max-height:85vh;max-width:100%;transform:translateY(100%);width:100%}.cc-modal.is-visible .cc-modal__content{transform:translateY(0)}.cc-modal__body{padding:1rem 1.25rem}.cc-modal__footer{align-items:stretch;flex-direction:column;padding:1rem 1.25rem 1.5rem}.cc-modal__footer-links{justify-content:center;margin-top:.75rem;order:2}.cc-modal__footer-actions{flex-direction:column;order:1;width:100%}.cc-modal__footer .cc-btn{width:100%}}.cc-widget{align-items:center;background:#fff;border:1.5px solid var(--cc-primary);border-radius:50px;box-shadow:0 2px 8px rgba(0,0,0,.08);color:var(--cc-primary);cursor:pointer;display:flex;font-family:var(--cc-font-family);gap:.5rem;min-height:40px;opacity:0;padding:.625rem .875rem;position:fixed;transform:scale(0);transition:all .3s cubic-bezier(.4,0,.2,1);-webkit-user-select:none;-moz-user-select:none;user-select:none;z-index:9998}.cc-widget.is-visible{opacity:1;transform:scale(1)}.cc-widget:hover{background:var(--cc-primary);box-shadow:0 4px 16px rgba(0,0,0,.12);color:#fff;transform:scale(1.05)}.cc-widget:active{transform:scale(.98)}.cc-widget:focus-visible{outline:3px solid #fff;outline-offset:2px}.cc-widget__icon{flex-shrink:0;height:20px;width:20px}.cc-widget__text{color:inherit;font-size:.8125rem;font-weight:500;white-space:nowrap}.cc-widget--bottom-right{bottom:1.5rem;right:1.5rem}.cc-widget--bottom-left{bottom:1.5rem;left:1.5rem}.cc-widget--top-right{right:1.5rem;top:1.5rem}.cc-widget--top-left{left:1.5rem;top:1.5rem}.cc-widget--compact{border-radius:50%;height:42px;justify-content:center;padding:.625rem;width:42px}.cc-widget--compact .cc-widget__text{display:none}@media (max-width:640px){.cc-widget--full .cc-widget__text{display:none}.cc-widget--full{border-radius:50%;height:44px;justify-content:center;padding:.625rem;width:44px}}@keyframes cc-widget-bounce{0%{transform:scale(0)}50%{transform:scale(1.1)}to{transform:scale(1)}}.cc-widget.is-visible{animation:cc-widget-bounce .4s cubic-bezier(.4,0,.2,1)}.cc-widget[data-theme=dark]{background:#1a1a1a;border-color:var(--cc-primary);color:var(--cc-primary)}.cc-widget[data-theme=dark]:hover{background:var(--cc-primary);color:#fff}@media (prefers-color-scheme:dark){.cc-widget[data-theme=auto]{background:#1a1a1a;border-color:var(--cc-primary);color:var(--cc-primary)}.cc-widget[data-theme=auto]:hover{background:var(--cc-primary);color:#fff}}@media (prefers-reduced-motion:reduce){.cc-widget{transition:none}.cc-widget.is-visible{animation:none}.cc-widget:hover{transform:none}}
|
|
1
|
+
.cc-banner,.cc-modal,.cc-widget{--cc-primary:#1a1a1a;--cc-primary-hover:#333;--cc-primary-glow:rgba(0,0,0,.12);--cc-bg:#fff;--cc-text:#1a1a1a;--cc-text-secondary:#666;--cc-border:#e5e7eb;--cc-overlay:rgba(0,0,0,.4);--cc-padding:1.125rem;--cc-gap:0.5rem;--cc-border-radius:12px;--cc-shadow:0 -4px 24px rgba(0,0,0,.12);--cc-transition:0.3s cubic-bezier(0.4,0,0.2,1);--cc-backdrop-blur:10px;--cc-font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif}.cc-banner *,.cc-modal *,.cc-widget *{box-sizing:border-box;margin:0;padding:0}.cc-banner{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;background:var(--cc-bg);bottom:0;box-shadow:var(--cc-shadow);font-family:var(--cc-font-family);left:0;padding:var(--cc-padding);position:fixed;right:0;transform:translateY(100%);transition:transform var(--cc-transition);z-index:2147483647}.cc-banner.cc-backdrop-blur{backdrop-filter:blur(var(--cc-backdrop-blur));background:hsla(0,0%,100%,.95)}.cc-banner.is-visible{transform:translateY(0)}.cc-banner__container{margin:0 auto;max-width:1200px}.cc-banner__content{margin-bottom:1rem}.cc-banner__title{color:var(--cc-text);font-size:.9375rem;font-weight:600;letter-spacing:-.01em;line-height:1.3;margin:0 0 .375rem}.cc-banner__description{color:var(--cc-text-secondary);font-size:.8125rem;line-height:1.5;margin:0}.cc-banner__description a{color:var(--cc-primary);font-weight:500;text-decoration:none;transition:all .2s ease}.cc-banner__description a:hover{color:var(--cc-primary-hover);text-decoration:underline}.cc-banner__actions{display:flex;flex-wrap:wrap;gap:var(--cc-gap)}.cc-btn{align-items:center;border:none;border-radius:8px;cursor:pointer;display:inline-flex;font-family:inherit;font-size:.8125rem;font-weight:500;justify-content:center;letter-spacing:-.01em;min-height:36px;min-width:36px;padding:.5rem 1.125rem;text-decoration:none;transition:all .2s ease}.cc-btn:focus-visible{outline:3px solid var(--cc-primary);outline-offset:2px}.cc-btn:disabled{cursor:not-allowed;opacity:.6}.cc-btn--accept{background:var(--cc-primary);color:#fff}.cc-btn--accept:hover:not(:disabled){background:var(--cc-primary-hover);box-shadow:0 4px 12px var(--cc-primary-glow);transform:translateY(-1px)}.cc-btn--accept:active:not(:disabled){transform:translateY(0)}.cc-btn--ghost{background:transparent;color:var(--cc-text-secondary);font-size:.75rem;padding:.5rem .75rem}.cc-btn--ghost:hover:not(:disabled){color:var(--cc-text);text-decoration:underline}.cc-btn--ghost:active:not(:disabled){transform:translateY(0)}.cc-btn--primary{background:var(--cc-primary);color:#fff}.cc-btn--primary:hover:not(:disabled){background:var(--cc-primary-hover);box-shadow:0 4px 12px var(--cc-primary-glow);transform:translateY(-1px)}.cc-btn--primary:active:not(:disabled){transform:translateY(0)}.cc-btn--secondary{background:#f3f4f6;color:var(--cc-text)}.cc-btn--secondary:hover:not(:disabled){background:#e5e7eb;transform:translateY(-1px)}.cc-btn--secondary:active:not(:disabled){transform:translateY(0)}.cc-btn--tertiary{background:transparent;border:1px solid var(--cc-border);color:var(--cc-text-secondary)}.cc-btn--tertiary:hover:not(:disabled){background:rgba(0,0,0,.03);color:var(--cc-text);transform:translateY(-1px)}.cc-btn--tertiary:active:not(:disabled){transform:translateY(0)}@media (min-width:768px){.cc-banner--bar .cc-banner__container{align-items:center;display:flex;gap:2rem;justify-content:space-between}.cc-banner--bar .cc-banner__content{flex:1;margin-bottom:0}.cc-banner--bar .cc-banner__actions{flex-shrink:0}}.cc-banner--top{bottom:auto;box-shadow:0 4px 24px rgba(0,0,0,.12);top:0;transform:translateY(-100%)}.cc-banner--top.is-visible{transform:translateY(0)}.cc-banner--center{border-radius:var(--cc-border-radius);bottom:auto;left:50%;max-width:600px;opacity:0;right:auto;top:50%;transform:translate(-50%,-50%) scale(.9)}.cc-banner--center.is-visible{opacity:1;transform:translate(-50%,-50%) scale(1)}.cc-banner--bottom-right{border-radius:var(--cc-border-radius);bottom:1.5rem;left:auto;max-width:420px;right:1.5rem;transform:translateX(calc(100% + 2rem))}.cc-banner--bottom-right.is-visible{transform:translateX(0)}.cc-banner--bottom-left{border-radius:var(--cc-border-radius);bottom:1.5rem;left:1.5rem;max-width:420px;right:auto;transform:translateX(calc(-100% - 2rem))}.cc-banner--bottom-left.is-visible{transform:translateX(0)}.cc-banner--box{border-radius:var(--cc-border-radius);max-width:420px}.cc-banner--box .cc-banner__container{display:block}.cc-banner--box .cc-banner__actions{flex-direction:column;margin-top:1rem}.cc-banner--box .cc-banner__actions .cc-btn{width:100%}.cc-banner--floating{border-radius:var(--cc-border-radius);box-shadow:0 8px 32px rgba(0,0,0,.2);max-width:380px}.cc-banner--floating .cc-banner__container{display:block}.cc-banner--floating .cc-banner__title{font-size:1rem}.cc-banner--floating .cc-banner__description{font-size:.8125rem}.cc-banner--floating .cc-banner__actions{flex-direction:column;margin-top:1rem}.cc-banner--floating .cc-banner__actions .cc-btn{font-size:.8125rem;padding:.625rem 1rem;width:100%}@media (prefers-color-scheme:dark){.cc-banner[data-theme=auto]{--cc-bg:#1a1a1a;--cc-text:#fff;--cc-text-secondary:#a0a0a0;--cc-border:#333}.cc-banner[data-theme=auto].cc-backdrop-blur{background:rgba(26,26,26,.95)}.cc-banner[data-theme=auto] .cc-btn--secondary{background:#2a2a2a;color:#fff}.cc-banner[data-theme=auto] .cc-btn--secondary:hover:not(:disabled){background:#333}.cc-banner[data-theme=auto] .cc-btn--tertiary{border-color:#555;color:#a0a0a0}}.cc-banner[data-theme=dark]{--cc-bg:#1a1a1a;--cc-text:#fff;--cc-text-secondary:#a0a0a0;--cc-border:#333}.cc-banner[data-theme=dark].cc-backdrop-blur{background:rgba(26,26,26,.95)}.cc-banner[data-theme=dark] .cc-btn--secondary{background:#2a2a2a;color:#fff}.cc-banner[data-theme=dark] .cc-btn--secondary:hover:not(:disabled){background:#333}.cc-banner[data-theme=dark] .cc-btn--tertiary{border-color:#555;color:#a0a0a0}@keyframes cc-fadeIn{0%{opacity:0}to{opacity:1}}@keyframes cc-slideUp{0%{opacity:0;transform:translateY(100%)}to{opacity:1;transform:translateY(0)}}@keyframes cc-slideDown{0%{opacity:0;transform:translateY(-100%)}to{opacity:1;transform:translateY(0)}}@keyframes cc-scaleIn{0%{opacity:0;transform:scale(.9)}to{opacity:1;transform:scale(1)}}@keyframes cc-backdropFadeIn{0%{opacity:0}to{opacity:1}}.cc-animate-fadeIn{animation:cc-fadeIn .3s ease-out}.cc-animate-slideUp{animation:cc-slideUp .4s cubic-bezier(.4,0,.2,1)}.cc-animate-slideDown{animation:cc-slideDown .4s cubic-bezier(.4,0,.2,1)}.cc-animate-scaleIn{animation:cc-scaleIn .3s cubic-bezier(.4,0,.2,1)}@media (prefers-reduced-motion:reduce){.cc-banner{transition:none}.cc-animate-fadeIn,.cc-animate-scaleIn,.cc-animate-slideDown,.cc-animate-slideUp{animation:none}.cc-btn{transition:none}}.cc-modal{align-items:center;bottom:0;display:flex;justify-content:center;left:0;opacity:0;padding:1rem;pointer-events:none;position:fixed;right:0;top:0;transition:opacity var(--cc-transition);z-index:10000}.cc-modal.is-visible{opacity:1;pointer-events:all}.cc-modal__overlay{background:var(--cc-overlay);bottom:0;cursor:pointer;left:0;position:absolute;right:0;top:0}.cc-modal__content{background:var(--cc-bg);border-radius:var(--cc-border-radius);box-shadow:0 16px 48px rgba(0,0,0,.18),0 4px 12px rgba(0,0,0,.08);display:flex;flex-direction:column;max-height:90vh;max-width:480px;overflow:hidden;position:relative;transform:scale(.9);transition:transform var(--cc-transition);width:100%}.cc-modal.is-visible .cc-modal__content{transform:scale(1)}.cc-modal__header{align-items:center;background:linear-gradient(135deg,var(--cc-primary) 0,var(--cc-primary-hover) 100%);display:flex;flex-shrink:0;justify-content:space-between;padding:1.125rem 1.25rem}.cc-modal__header h2{color:#fff;font-size:.95rem;font-weight:600;letter-spacing:-.01em;margin:0}.cc-modal__body{flex:1;overflow-y:auto;padding:1rem 1.25rem}.cc-category{border-bottom:1px solid var(--cc-border);padding:.75rem 0}.cc-category:last-child{border-bottom:none}.cc-category__header{align-items:center;display:flex;gap:.75rem}.cc-category__info{flex:1}.cc-category__info h3{color:var(--cc-text);font-size:.8125rem;font-weight:600;letter-spacing:-.01em;margin:0 0 .125rem}.cc-category__info p{color:var(--cc-text-secondary);font-size:.75rem;line-height:1.4;margin:0}.cc-toggle{align-items:center;cursor:pointer;display:inline-flex;flex-shrink:0;position:relative;-webkit-user-select:none;-moz-user-select:none;user-select:none}.cc-toggle input{height:0;opacity:0;position:absolute;width:0}.cc-toggle__slider{background:#d1d5db;border-radius:10px;height:20px;position:relative;transition:background-color .2s ease;width:36px}.cc-toggle__slider:before{background:#fff;border-radius:50%;box-shadow:0 1px 3px rgba(0,0,0,.15);content:"";height:16px;left:2px;position:absolute;top:2px;transition:transform .2s ease;width:16px}.cc-toggle input:checked+.cc-toggle__slider{background:var(--cc-primary)}.cc-toggle input:checked+.cc-toggle__slider:before{transform:translateX(16px)}.cc-toggle input:focus-visible+.cc-toggle__slider{outline:2px solid var(--cc-primary);outline-offset:2px}.cc-toggle--disabled{cursor:not-allowed;opacity:.6}.cc-toggle--disabled input:checked+.cc-toggle__slider{background:#9ca3af}.cc-modal__footer{align-items:center;border-top:1px solid var(--cc-border);display:flex;flex-shrink:0;gap:var(--cc-gap);justify-content:space-between;padding:1rem 1.25rem}.cc-modal__footer-links{align-items:center;display:flex;gap:.5rem}.cc-modal__footer-actions{display:flex;gap:var(--cc-gap)}.cc-privacy-link{align-items:center;color:var(--cc-text-secondary);display:inline-flex;font-size:.875rem;gap:.25rem;text-decoration:none;transition:color .2s ease}.cc-privacy-link:hover{color:var(--cc-primary);text-decoration:underline}@media (prefers-color-scheme:dark){.cc-modal[data-theme=auto] .cc-modal__content{background:#1a1a1a}.cc-modal[data-theme=auto] .cc-category__info h3{color:#fff}.cc-modal[data-theme=auto] .cc-category__info p{color:#a0a0a0}.cc-modal[data-theme=auto] .cc-category,.cc-modal[data-theme=auto] .cc-modal__footer{border-color:#333}.cc-modal[data-theme=auto] .cc-toggle__slider{background:#444}.cc-modal[data-theme=auto] .cc-btn--secondary{background:#2a2a2a;color:#fff}.cc-modal[data-theme=auto] .cc-btn--secondary:hover:not(:disabled){background:#333}}.cc-modal[data-theme=dark] .cc-modal__content{background:#1a1a1a}.cc-modal[data-theme=dark] .cc-category__info h3{color:#fff}.cc-modal[data-theme=dark] .cc-category__info p{color:#a0a0a0}.cc-modal[data-theme=dark] .cc-category,.cc-modal[data-theme=dark] .cc-modal__footer{border-color:#333}.cc-modal[data-theme=dark] .cc-toggle__slider{background:#444}.cc-modal[data-theme=dark] .cc-btn--secondary{background:#2a2a2a;color:#fff}.cc-modal[data-theme=dark] .cc-btn--secondary:hover:not(:disabled){background:#333}.cc-modal--bottom-right{align-items:flex-end;justify-content:flex-end;padding:1.5rem}.cc-modal--bottom-right .cc-modal__content{max-width:450px;transform:translateX(100%)}.cc-modal--bottom-right.is-visible .cc-modal__content{transform:translateX(0)}.cc-modal--bottom-left{align-items:flex-end;justify-content:flex-start;padding:1.5rem}.cc-modal--bottom-left .cc-modal__content{max-width:450px;transform:translateX(-100%)}.cc-modal--bottom-left.is-visible .cc-modal__content{transform:translateX(0)}.cc-modal--top-right{align-items:flex-start;justify-content:flex-end;padding:1.5rem}.cc-modal--top-right .cc-modal__content{max-width:450px;transform:translateX(100%)}.cc-modal--top-right.is-visible .cc-modal__content{transform:translateX(0)}.cc-modal--top-left{align-items:flex-start;justify-content:flex-start;padding:1.5rem}.cc-modal--top-left .cc-modal__content{max-width:450px;transform:translateX(-100%)}.cc-modal--top-left.is-visible .cc-modal__content{transform:translateX(0)}@media (max-width:640px){.cc-modal{align-items:flex-end;padding:0}.cc-modal__content{border-radius:16px 16px 0 0;max-height:85vh;max-width:100%;transform:translateY(100%);width:100%}.cc-modal.is-visible .cc-modal__content{transform:translateY(0)}.cc-modal__body{padding:1rem 1.25rem}.cc-modal__footer{align-items:stretch;flex-direction:column;padding:1rem 1.25rem 1.5rem}.cc-modal__footer-links{justify-content:center;margin-top:.75rem;order:2}.cc-modal__footer-actions{flex-direction:column;order:1;width:100%}.cc-modal__footer .cc-btn{width:100%}}.cc-widget{align-items:center;background:#fff;border:1.5px solid var(--cc-primary);border-radius:50px;box-shadow:0 2px 8px rgba(0,0,0,.08);color:var(--cc-primary);cursor:pointer;display:flex;font-family:var(--cc-font-family);gap:.5rem;min-height:40px;opacity:0;padding:.625rem .875rem;position:fixed;transform:scale(0);transition:all .3s cubic-bezier(.4,0,.2,1);-webkit-user-select:none;-moz-user-select:none;user-select:none;z-index:9998}.cc-widget.is-visible{opacity:1;transform:scale(1)}.cc-widget:hover{background:var(--cc-primary);box-shadow:0 4px 16px rgba(0,0,0,.12);color:#fff;transform:scale(1.05)}.cc-widget:active{transform:scale(.98)}.cc-widget:focus-visible{outline:3px solid var(--cc-primary);outline-offset:2px}.cc-widget__icon{flex-shrink:0;height:20px;width:20px}.cc-widget__text{color:inherit;font-size:.8125rem;font-weight:500;white-space:nowrap}.cc-widget--bottom-right{bottom:1.5rem;right:1.5rem}.cc-widget--bottom-left{bottom:1.5rem;left:1.5rem}.cc-widget--top-right{right:1.5rem;top:1.5rem}.cc-widget--top-left{left:1.5rem;top:1.5rem}.cc-widget--compact{border-radius:50%;height:42px;justify-content:center;padding:.625rem;width:42px}.cc-widget--compact .cc-widget__text{display:none}@media (max-width:640px){.cc-widget--full .cc-widget__text{display:none}.cc-widget--full{border-radius:50%;height:44px;justify-content:center;padding:.625rem;width:44px}}@keyframes cc-widget-bounce{0%{transform:scale(0)}50%{transform:scale(1.1)}to{transform:scale(1)}}.cc-widget.is-visible{animation:cc-widget-bounce .4s cubic-bezier(.4,0,.2,1)}.cc-widget[data-theme=dark]{background:#1a1a1a;border-color:var(--cc-primary);color:var(--cc-primary)}.cc-widget[data-theme=dark]:hover{background:var(--cc-primary);color:#fff}@media (prefers-color-scheme:dark){.cc-widget[data-theme=auto]{background:#1a1a1a;border-color:var(--cc-primary);color:var(--cc-primary)}.cc-widget[data-theme=auto]:hover{background:var(--cc-primary);color:#fff}}@media (prefers-reduced-motion:reduce){.cc-widget{transition:none}.cc-widget.is-visible{animation:none}.cc-widget:hover{transform:none}}
|