@rune-kit/rune 2.2.3 → 2.2.6

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/docs/style.css CHANGED
@@ -2,6 +2,36 @@
2
2
  *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
3
3
 
4
4
  :root {
5
+ /* Warm cream palette (default — light) */
6
+ --bg-base: #ece4d6;
7
+ --bg-card: #f5f0e8;
8
+ --bg-elevated: #ede7db;
9
+ --bg-section-alt: #e4dbc9;
10
+ --bg-code: rgba(31,45,61,0.06);
11
+ --text-primary: #1f2d3d;
12
+ --text-secondary: #4b5563;
13
+ --text-muted: #7a8494;
14
+ --border: rgba(31,45,61,0.1);
15
+ --accent: #5b7852;
16
+ --accent-dim: rgba(91,120,82,0.1);
17
+ --accent-glow: rgba(91,120,82,0.2);
18
+ --cyan: #3d7a6a;
19
+ --loss: #c0392b;
20
+ --profit: #5b7852;
21
+ --nav-bg: rgba(236,228,214,0.9);
22
+ --font-display: 'Space Grotesk', system-ui, sans-serif;
23
+ --font-body: 'Inter', system-ui, sans-serif;
24
+ --font-mono: 'JetBrains Mono', 'Fira Code', monospace;
25
+ --radius-sm: 6px;
26
+ --radius-md: 10px;
27
+ --radius-lg: 16px;
28
+ --shadow-card: 0 4px 24px rgba(31,45,61,0.08);
29
+ --transition: 250ms ease;
30
+ --max-width: 1120px;
31
+ }
32
+
33
+ /* ─── DARK MODE ─── */
34
+ [data-theme="dark"] {
5
35
  --bg-base: #0a0f1a;
6
36
  --bg-card: #111827;
7
37
  --bg-elevated: #1a2332;
@@ -14,47 +44,12 @@
14
44
  --accent: #10b981;
15
45
  --accent-dim: rgba(16, 185, 129, 0.15);
16
46
  --accent-glow: rgba(16, 185, 129, 0.3);
17
- --cyan: #06b6d4;
18
47
  --loss: #ef4444;
19
48
  --profit: #10b981;
20
49
  --nav-bg: rgba(10, 15, 26, 0.85);
21
- --font-display: 'Space Grotesk', system-ui, sans-serif;
22
- --font-body: 'Inter', system-ui, sans-serif;
23
- --font-mono: 'JetBrains Mono', 'Fira Code', monospace;
24
- --radius-sm: 6px;
25
- --radius-md: 10px;
26
- --radius-lg: 16px;
27
50
  --shadow-card: 0 4px 24px rgba(0,0,0,0.3);
28
- --transition: 250ms ease;
29
- --max-width: 1120px;
30
51
  }
31
52
 
32
- /* ─── LIGHT MODE ─── */
33
- [data-theme="light"] {
34
- --bg-base: #f8fafb;
35
- --bg-card: #ffffff;
36
- --bg-elevated: #f1f5f9;
37
- --bg-section-alt: #eef2f6;
38
- --bg-code: rgba(0,0,0,0.04);
39
- --text-primary: #0f172a;
40
- --text-secondary: #475569;
41
- --text-muted: #94a3b8;
42
- --border: #e2e8f0;
43
- --accent: #059669;
44
- --accent-dim: rgba(5, 150, 105, 0.1);
45
- --accent-glow: rgba(5, 150, 105, 0.2);
46
- --loss: #dc2626;
47
- --profit: #059669;
48
- --nav-bg: rgba(248, 250, 251, 0.88);
49
- --shadow-card: 0 4px 24px rgba(0,0,0,0.08);
50
- }
51
- [data-theme="light"] .hero-mesh { opacity: 0.15; }
52
- [data-theme="light"] .compare-diagram { background: rgba(0,0,0,0.04); }
53
- [data-theme="light"] .code-block { background: var(--bg-code); }
54
- [data-theme="light"] .phase { background: rgba(0,0,0,0.02); }
55
- [data-theme="light"] .layer-count { background: rgba(0,0,0,0.05); }
56
- [data-theme="light"] .compare-table tbody tr:hover { background: rgba(0,0,0,0.02); }
57
-
58
53
  html { scroll-behavior: smooth; }
59
54
 
60
55
  body {
@@ -118,7 +113,7 @@ a:hover { opacity: 0.85; }
118
113
  padding: 120px 24px 80px;
119
114
  }
120
115
  .hero-mesh {
121
- position: absolute; inset: 0; overflow: hidden; opacity: 0.4;
116
+ position: absolute; inset: 0; overflow: hidden; opacity: 0.45;
122
117
  }
123
118
  #mesh-canvas { width: 100%; height: 100%; }
124
119
  .hero-content {
@@ -128,7 +123,7 @@ a:hover { opacity: 0.85; }
128
123
  display: inline-block; font-family: var(--font-mono); font-size: 13px;
129
124
  color: var(--accent); background: var(--accent-dim);
130
125
  padding: 6px 16px; border-radius: 999px; margin-bottom: 28px;
131
- border: 1px solid rgba(16, 185, 129, 0.2);
126
+ border: 1px solid rgba(91,120,82,0.25);
132
127
  }
133
128
  .hero h1 {
134
129
  font-family: var(--font-display); font-size: clamp(40px, 7vw, 72px);
@@ -167,7 +162,7 @@ a:hover { opacity: 0.85; }
167
162
  .compare-diagram {
168
163
  font-family: var(--font-mono); font-size: 14px; line-height: 1.8;
169
164
  color: var(--text-secondary); margin-bottom: 14px;
170
- background: rgba(0,0,0,0.3); padding: 14px; border-radius: var(--radius-sm);
165
+ background: rgba(31,45,61,0.05); padding: 14px; border-radius: var(--radius-sm);
171
166
  }
172
167
  .compare-good { border-color: var(--accent); }
173
168
  .compare-good h3 { color: var(--accent); }
@@ -199,7 +194,7 @@ a:hover { opacity: 0.85; }
199
194
  .layer-content strong { font-family: var(--font-display); font-size: 16px; }
200
195
  .layer-count {
201
196
  font-family: var(--font-mono); font-size: 12px;
202
- color: var(--text-muted); background: rgba(255,255,255,0.06);
197
+ color: var(--text-muted); background: rgba(31,45,61,0.06);
203
198
  padding: 2px 8px; border-radius: 4px;
204
199
  }
205
200
  .layer-content p {
@@ -220,7 +215,7 @@ a:hover { opacity: 0.85; }
220
215
  .workflow-phases { display: flex; flex-direction: column; gap: 6px; }
221
216
  .phase {
222
217
  font-size: 13px; color: var(--text-secondary); padding: 6px 10px;
223
- background: rgba(255,255,255,0.03); border-radius: var(--radius-sm);
218
+ background: rgba(31,45,61,0.03); border-radius: var(--radius-sm);
224
219
  border-left: 2px solid var(--border);
225
220
  transition: border-color var(--transition);
226
221
  }
@@ -256,7 +251,7 @@ a:hover { opacity: 0.85; }
256
251
  color: var(--accent); display: inline-block; margin-bottom: 18px;
257
252
  }
258
253
  .code-block {
259
- background: rgba(0,0,0,0.4); border: 1px solid var(--border);
254
+ background: var(--bg-code); border: 1px solid var(--border);
260
255
  border-radius: var(--radius-sm); padding: 14px 20px;
261
256
  font-family: var(--font-mono); font-size: 14px;
262
257
  color: var(--accent); margin-bottom: 14px; text-align: left;
@@ -307,12 +302,18 @@ a:hover { opacity: 0.85; }
307
302
  display: flex; flex-direction: column;
308
303
  }
309
304
  .pricing-pro {
310
- border-color: #f59e0b;
311
- background: linear-gradient(168deg, var(--bg-card) 60%, rgba(245, 158, 11, 0.06) 100%);
305
+ border-color: rgba(180,120,40,0.3);
306
+ background: linear-gradient(168deg, var(--bg-card) 60%, rgba(180,120,40,0.05) 100%);
312
307
  }
313
308
  .pricing-biz {
314
- border-color: #8b5cf6;
315
- background: linear-gradient(168deg, var(--bg-card) 60%, rgba(139, 92, 246, 0.06) 100%);
309
+ border-color: rgba(100,70,180,0.3);
310
+ background: linear-gradient(168deg, var(--bg-card) 60%, rgba(100,70,180,0.06) 100%);
311
+ transform: scale(1.03);
312
+ box-shadow: 0 0 30px rgba(100,70,180,0.08), 0 8px 32px rgba(31,45,61,0.1);
313
+ z-index: 1;
314
+ }
315
+ @media (max-width: 768px) {
316
+ .pricing-biz { transform: scale(1); }
316
317
  }
317
318
  .pricing-tier { margin-bottom: 16px; }
318
319
  .pricing-badge {
@@ -321,8 +322,8 @@ a:hover { opacity: 0.85; }
321
322
  padding: 3px 10px; border-radius: 4px; margin-bottom: 12px;
322
323
  }
323
324
  .pricing-badge-free { background: var(--accent-dim); color: var(--accent); }
324
- .pricing-badge-pro { background: rgba(245, 158, 11, 0.15); color: #f59e0b; }
325
- .pricing-badge-biz { background: rgba(139, 92, 246, 0.15); color: #8b5cf6; }
325
+ .pricing-badge-pro { background: rgba(180,120,40,0.12); color: #b47828; }
326
+ .pricing-badge-biz { background: rgba(100,70,180,0.12); color: #6446b4; }
326
327
  .pricing-card h3 {
327
328
  font-family: var(--font-display); font-size: 26px; font-weight: 700;
328
329
  margin-bottom: 4px;
@@ -353,27 +354,96 @@ a:hover { opacity: 0.85; }
353
354
  content: '\2713'; position: absolute; left: 0;
354
355
  color: var(--accent); font-weight: 700; font-size: 12px;
355
356
  }
356
- .pricing-pro .pricing-features li::before { color: #f59e0b; }
357
- .pricing-biz .pricing-features li::before { color: #8b5cf6; }
357
+ .pricing-pro .pricing-features li::before { color: #b47828; }
358
+ .pricing-biz .pricing-features li::before { color: #6446b4; }
358
359
  .pricing-features li strong { color: var(--text-primary); font-weight: 600; }
360
+
361
+ /* BEST VALUE badge */
362
+ .pricing-badge-best {
363
+ background: linear-gradient(135deg, #b47828, #6446b4);
364
+ color: #fff; font-size: 12px; letter-spacing: 1px;
365
+ }
366
+
367
+ /* What's Included breakdown (Business card) */
368
+ .includes-breakdown {
369
+ margin-bottom: 16px;
370
+ }
371
+ .includes-label {
372
+ font-family: var(--font-display); font-size: 14px; font-weight: 700;
373
+ color: var(--text-primary); margin-bottom: 10px;
374
+ }
375
+ .includes-box {
376
+ border: 1px solid var(--border); border-radius: 8px;
377
+ padding: 12px 14px; margin-bottom: 8px;
378
+ background: rgba(31,45,61,0.03);
379
+ }
380
+ .includes-box strong {
381
+ font-family: var(--font-display); font-size: 13px; color: var(--text-primary);
382
+ }
383
+ .includes-value {
384
+ font-family: var(--font-mono); font-size: 11px; color: var(--text-muted);
385
+ margin-left: 6px;
386
+ }
387
+ .includes-box ul {
388
+ list-style: none; margin-top: 6px; display: flex; flex-direction: column; gap: 3px;
389
+ }
390
+ .includes-box ul li {
391
+ font-size: 12px; color: var(--text-secondary); line-height: 1.5;
392
+ padding-left: 16px; position: relative;
393
+ }
394
+ .includes-box ul li::before {
395
+ content: '\2713'; position: absolute; left: 0;
396
+ font-weight: 700; font-size: 11px;
397
+ }
398
+ .includes-box-pro ul li::before { color: #b47828; }
399
+ .includes-box-biz ul li::before { color: #6446b4; }
400
+
401
+ /* Guarantee note */
402
+ .pricing-guarantee {
403
+ color: var(--accent) !important; font-weight: 500;
404
+ }
405
+
406
+ /* Promo ribbon on pricing cards */
407
+ .promo-ribbon {
408
+ position: absolute; top: -1px; right: 24px;
409
+ background: linear-gradient(135deg, #5b7852, #7a9e6e);
410
+ color: #fff; font-family: var(--font-mono); font-size: 11px;
411
+ font-weight: 700; letter-spacing: 0.5px; text-transform: uppercase;
412
+ padding: 6px 14px 8px; border-radius: 0 0 8px 8px;
413
+ box-shadow: 0 4px 12px rgba(91,120,82,0.3);
414
+ animation: promo-pulse 2s ease-in-out infinite;
415
+ }
416
+ @keyframes promo-pulse {
417
+ 0%, 100% { box-shadow: 0 4px 12px rgba(91,120,82,0.3); }
418
+ 50% { box-shadow: 0 4px 20px rgba(91,120,82,0.5); }
419
+ }
420
+ .pricing-card { position: relative; overflow: visible; }
421
+
422
+ /* Promo save badge under price */
423
+ .promo-save {
424
+ display: inline-block; margin-top: 6px;
425
+ font-family: var(--font-mono); font-size: 13px; font-weight: 700;
426
+ color: #5b7852; background: rgba(91,120,82,0.1);
427
+ padding: 3px 10px; border-radius: 4px;
428
+ }
359
429
  .btn-pro {
360
430
  display: inline-flex; align-items: center; justify-content: center;
361
431
  padding: 10px 22px; border-radius: var(--radius-sm);
362
432
  font-family: var(--font-body); font-weight: 600; font-size: 14px;
363
433
  cursor: pointer; transition: all var(--transition); border: none;
364
- background: #f59e0b; color: #000;
365
- box-shadow: 0 0 20px rgba(245, 158, 11, 0.3);
434
+ background: #b47828; color: #fff;
435
+ box-shadow: 0 2px 12px rgba(180,120,40,0.2);
366
436
  }
367
- .btn-pro:hover { background: #d97706; transform: translateY(-1px); opacity: 1; }
437
+ .btn-pro:hover { background: #9a6520; transform: translateY(-1px); opacity: 1; }
368
438
  .btn-biz {
369
439
  display: inline-flex; align-items: center; justify-content: center;
370
440
  padding: 10px 22px; border-radius: var(--radius-sm);
371
441
  font-family: var(--font-body); font-weight: 600; font-size: 14px;
372
442
  cursor: pointer; transition: all var(--transition); border: none;
373
- background: #8b5cf6; color: #fff;
374
- box-shadow: 0 0 20px rgba(139, 92, 246, 0.3);
443
+ background: #6446b4; color: #fff;
444
+ box-shadow: 0 2px 12px rgba(100,70,180,0.2);
375
445
  }
376
- .btn-biz:hover { background: #7c3aed; transform: translateY(-1px); opacity: 1; }
446
+ .btn-biz:hover { background: #5538a0; transform: translateY(-1px); opacity: 1; }
377
447
  .pricing-note {
378
448
  font-size: 12px; color: var(--text-muted); text-align: center;
379
449
  margin-top: 10px; line-height: 1.5;
@@ -408,7 +478,7 @@ a:hover { opacity: 0.85; }
408
478
  .compare-table tbody td:first-child { text-align: left; color: var(--text-primary); }
409
479
  .compare-table .check { color: var(--accent); font-weight: 700; font-size: 16px; }
410
480
  .compare-table .dash { color: var(--text-muted); }
411
- .compare-table tbody tr:hover { background: rgba(255,255,255,0.02); }
481
+ .compare-table tbody tr:hover { background: rgba(31,45,61,0.03); }
412
482
 
413
483
  /* ─── EXTENSIONS ─── */
414
484
  .ext-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; }
@@ -439,6 +509,7 @@ a:hover { opacity: 0.85; }
439
509
  /* ─── FOOTER ─── */
440
510
  .footer {
441
511
  border-top: 1px solid var(--border); padding: 32px 0;
512
+ background: var(--bg-section-alt);
442
513
  }
443
514
  .footer-inner {
444
515
  display: flex; align-items: center; justify-content: space-between;
@@ -482,10 +553,14 @@ a:hover { opacity: 0.85; }
482
553
  .theme-toggle:hover, .lang-toggle:hover {
483
554
  border-color: var(--accent); color: var(--text-primary);
484
555
  }
485
- /* Google Translate — hide injected banner */
556
+ /* Google Translate — hide ALL injected elements */
486
557
  .goog-te-banner-frame { display: none !important; }
487
- body { top: 0 !important; }
488
- .skiptranslate { display: none !important; }
558
+ body { top: 0 !important; position: static !important; }
559
+ .skiptranslate { display: none !important; height: 0 !important; overflow: hidden !important; }
560
+ .goog-te-spinner-pos, .goog-te-balloon-frame, #goog-gt-tt, .goog-te-ftab-frame { display: none !important; }
561
+ .goog-text-highlight { background: none !important; box-shadow: none !important; }
562
+ font[style] > font { vertical-align: unset !important; }
563
+ #_gt_dummy { display: none !important; visibility: hidden !important; height: 0 !important; overflow: hidden !important; }
489
564
  /* Language dropdown */
490
565
  .lang-dropdown { position: relative; }
491
566
  .lang-menu {
@@ -584,6 +659,203 @@ body { top: 0 !important; }
584
659
  margin: 0 auto 16px; font-weight: 700;
585
660
  }
586
661
 
662
+ /* ─── MESH SECTION ─── */
663
+ .mesh-diagram { display: flex; flex-direction: column; gap: 0; margin: 32px 0; }
664
+
665
+ .mesh-tier {
666
+ border: 1px solid var(--border);
667
+ border-radius: 12px;
668
+ padding: 20px;
669
+ background: var(--bg-card);
670
+ }
671
+ .mesh-tier-free { border-color: var(--accent); }
672
+ .mesh-tier-pro { border-color: #a78bfa; }
673
+ .mesh-tier-biz { border-color: #f59e0b; }
674
+
675
+ .mesh-tier-header {
676
+ display: flex;
677
+ align-items: center;
678
+ gap: 12px;
679
+ margin-bottom: 16px;
680
+ flex-wrap: wrap;
681
+ }
682
+ .mesh-tier-badge {
683
+ font-size: 10px;
684
+ font-weight: 700;
685
+ padding: 3px 10px;
686
+ border-radius: 4px;
687
+ text-transform: uppercase;
688
+ letter-spacing: 0.5px;
689
+ }
690
+ .mesh-badge-free { background: rgba(var(--accent-rgb, 74,104,67), 0.15); color: var(--accent); }
691
+ .mesh-badge-pro { background: rgba(167,139,250,0.15); color: #a78bfa; }
692
+ .mesh-badge-biz { background: rgba(245,158,11,0.15); color: #f59e0b; }
693
+ .mesh-tier-stats { font-size: 12px; color: var(--text-muted); margin-left: auto; }
694
+
695
+ .mesh-layers { display: flex; flex-direction: column; gap: 8px; }
696
+ .mesh-layer {
697
+ display: flex;
698
+ align-items: flex-start;
699
+ gap: 10px;
700
+ }
701
+ .mesh-layer-label {
702
+ font-size: 10px;
703
+ font-weight: 700;
704
+ color: var(--text-muted);
705
+ background: var(--bg-section-alt);
706
+ padding: 3px 8px;
707
+ border-radius: 4px;
708
+ min-width: 28px;
709
+ text-align: center;
710
+ flex-shrink: 0;
711
+ margin-top: 2px;
712
+ }
713
+ .mesh-nodes {
714
+ display: flex;
715
+ flex-wrap: wrap;
716
+ gap: 6px;
717
+ }
718
+ .mesh-node {
719
+ font-size: 11px;
720
+ font-family: 'JetBrains Mono', monospace;
721
+ padding: 3px 8px;
722
+ border-radius: 4px;
723
+ background: var(--bg-section-alt);
724
+ color: var(--text-secondary);
725
+ border: 1px solid var(--border);
726
+ }
727
+ .mesh-node-router {
728
+ background: rgba(var(--accent-rgb, 74,104,67), 0.1);
729
+ color: var(--accent);
730
+ border-color: var(--accent);
731
+ font-weight: 600;
732
+ }
733
+ .mesh-node-more {
734
+ font-style: italic;
735
+ color: var(--text-muted);
736
+ border-style: dashed;
737
+ }
738
+
739
+ .mesh-flow-example {
740
+ margin-top: 14px;
741
+ padding: 10px 14px;
742
+ background: var(--bg-section-alt);
743
+ border-radius: 8px;
744
+ font-size: 12px;
745
+ display: flex;
746
+ align-items: center;
747
+ gap: 10px;
748
+ flex-wrap: wrap;
749
+ overflow-x: auto;
750
+ }
751
+ .mesh-flow-label { color: var(--text-muted); font-weight: 600; white-space: nowrap; }
752
+ .mesh-flow {
753
+ font-family: 'JetBrains Mono', monospace;
754
+ font-size: 11px;
755
+ color: var(--text-secondary);
756
+ white-space: nowrap;
757
+ }
758
+ .mesh-flow-fail { color: #ef4444; font-weight: 700; }
759
+ .mesh-flow-pass { color: var(--accent); font-weight: 700; }
760
+
761
+ .mesh-arrows {
762
+ display: flex;
763
+ flex-direction: column;
764
+ align-items: center;
765
+ padding: 8px 0;
766
+ }
767
+ .mesh-arrow-line {
768
+ width: 2px;
769
+ height: 24px;
770
+ background: linear-gradient(to bottom, var(--accent), #a78bfa);
771
+ }
772
+ .mesh-arrow-line-biz {
773
+ background: linear-gradient(to bottom, #a78bfa, #f59e0b);
774
+ }
775
+ .mesh-arrow-labels { text-align: center; }
776
+ .mesh-arrow-label {
777
+ display: block;
778
+ font-size: 12px;
779
+ font-weight: 700;
780
+ color: var(--text-primary);
781
+ }
782
+ .mesh-arrow-desc {
783
+ display: block;
784
+ font-size: 11px;
785
+ color: var(--text-muted);
786
+ }
787
+
788
+ .mesh-nodes-grid {
789
+ display: grid;
790
+ grid-template-columns: 1fr 1fr;
791
+ gap: 10px;
792
+ }
793
+ .mesh-pack {
794
+ padding: 10px 14px;
795
+ background: var(--bg-section-alt);
796
+ border-radius: 8px;
797
+ border: 1px solid var(--border);
798
+ }
799
+ .mesh-pack strong {
800
+ display: block;
801
+ font-size: 13px;
802
+ color: var(--text-primary);
803
+ margin-bottom: 2px;
804
+ }
805
+ .mesh-pack span { font-size: 12px; color: var(--text-secondary); line-height: 1.4; }
806
+ .mesh-pack em { color: #a78bfa; font-style: normal; font-weight: 600; }
807
+
808
+ .mesh-tier-note {
809
+ margin-top: 12px;
810
+ font-size: 12px;
811
+ color: var(--text-muted);
812
+ line-height: 1.5;
813
+ }
814
+ .mesh-tier-note code {
815
+ font-size: 11px;
816
+ background: var(--bg-section-alt);
817
+ padding: 1px 5px;
818
+ border-radius: 3px;
819
+ }
820
+
821
+ .mesh-points {
822
+ display: grid;
823
+ grid-template-columns: repeat(3, 1fr);
824
+ gap: 20px;
825
+ margin-top: 32px;
826
+ }
827
+ .mesh-point {
828
+ padding: 20px;
829
+ border-radius: 12px;
830
+ background: var(--bg-card);
831
+ border: 1px solid var(--border);
832
+ }
833
+ .mesh-point-icon {
834
+ font-size: 20px;
835
+ color: var(--accent);
836
+ margin-bottom: 8px;
837
+ }
838
+ .mesh-point h3 {
839
+ font-size: 15px;
840
+ font-weight: 700;
841
+ margin-bottom: 6px;
842
+ font-family: 'Space Grotesk', sans-serif;
843
+ }
844
+ .mesh-point p { font-size: 13px; color: var(--text-secondary); line-height: 1.5; }
845
+ .mesh-point code {
846
+ font-size: 12px;
847
+ background: var(--bg-section-alt);
848
+ padding: 1px 5px;
849
+ border-radius: 3px;
850
+ }
851
+
852
+ @media (max-width: 768px) {
853
+ .mesh-nodes-grid { grid-template-columns: 1fr; }
854
+ .mesh-points { grid-template-columns: 1fr; }
855
+ .mesh-tier-stats { margin-left: 0; width: 100%; }
856
+ .mesh-flow-example { flex-direction: column; align-items: flex-start; }
857
+ }
858
+
587
859
  /* ─── ANIMATIONS ─── */
588
860
  @media (prefers-reduced-motion: no-preference) {
589
861
  .layer, .feature-card, .workflow-card, .compare-card, .ext-card, .install-card, .pricing-card, .stat {
@@ -598,3 +870,27 @@ body { top: 0 !important; }
598
870
  @keyframes fadeUp {
599
871
  to { opacity: 1; transform: translateY(0); }
600
872
  }
873
+
874
+ /* ─── DARK MODE OVERRIDES ─── */
875
+ [data-theme="dark"] .hero-mesh { opacity: 0.4; }
876
+ [data-theme="dark"] .compare-diagram { background: rgba(0,0,0,0.3); }
877
+ [data-theme="dark"] .layer-count { background: rgba(255,255,255,0.06); }
878
+ [data-theme="dark"] .phase { background: rgba(255,255,255,0.03); }
879
+ [data-theme="dark"] .compare-table tbody tr:hover { background: rgba(255,255,255,0.02); }
880
+ [data-theme="dark"] .includes-box { background: rgba(255,255,255,0.02); }
881
+ [data-theme="dark"] .pricing-pro { border-color: #f59e0b; background: linear-gradient(168deg, var(--bg-card) 60%, rgba(245,158,11,0.06) 100%); }
882
+ [data-theme="dark"] .pricing-biz { border-color: #8b5cf6; background: linear-gradient(168deg, var(--bg-card) 60%, rgba(139,92,246,0.06) 100%); }
883
+ [data-theme="dark"] .pricing-badge-pro { background: rgba(245,158,11,0.15); color: #f59e0b; }
884
+ [data-theme="dark"] .pricing-badge-biz { background: rgba(139,92,246,0.15); color: #8b5cf6; }
885
+ [data-theme="dark"] .pricing-badge-best { background: linear-gradient(135deg, #f59e0b, #8b5cf6); }
886
+ [data-theme="dark"] .pricing-pro .pricing-features li::before { color: #f59e0b; }
887
+ [data-theme="dark"] .pricing-biz .pricing-features li::before { color: #8b5cf6; }
888
+ [data-theme="dark"] .includes-box-pro ul li::before { color: #f59e0b; }
889
+ [data-theme="dark"] .includes-box-biz ul li::before { color: #8b5cf6; }
890
+ [data-theme="dark"] .btn-pro { background: #f59e0b; color: #000; box-shadow: 0 0 20px rgba(245,158,11,0.3); }
891
+ [data-theme="dark"] .btn-pro:hover { background: #d97706; }
892
+ [data-theme="dark"] .btn-biz { background: #8b5cf6; box-shadow: 0 0 20px rgba(139,92,246,0.3); }
893
+ [data-theme="dark"] .btn-biz:hover { background: #7c3aed; }
894
+ [data-theme="dark"] .promo-ribbon { background: linear-gradient(135deg, #059669, #10b981); box-shadow: 0 4px 12px rgba(16,185,129,0.3); }
895
+ [data-theme="dark"] .promo-save { color: #10b981; background: rgba(16,185,129,0.1); }
896
+ [data-theme="dark"] .pricing-biz { box-shadow: 0 0 30px rgba(139,92,246,0.12), 0 8px 32px rgba(0,0,0,0.15); }
@@ -23,7 +23,7 @@ SaaS applications share a common set of hard problems that most teams solve from
23
23
 
24
24
  ## Triggers
25
25
 
26
- - Auto-trigger: when `tenant`, `subscription`, `billing`, `stripe`, `paddle`, `lemonsqueezy`, `plan`, `pricing`, `featureFlag`, `rbac`, `permission`, `onboarding` patterns detected in codebase
26
+ - Auto-trigger: when `tenant`, `subscription`, `billing`, `stripe`, `paddle`, `lemonsqueezy`, `polar`, `checkout`, `plan`, `pricing`, `featureFlag`, `rbac`, `permission`, `onboarding` patterns detected in codebase
27
27
  - `/rune multi-tenant` — audit or implement tenant isolation
28
28
  - `/rune billing-integration` — set up or audit billing provider integration
29
29
  - `/rune subscription-flow` — build subscription management UI
@@ -37,7 +37,7 @@ SaaS applications share a common set of hard problems that most teams solve from
37
37
  | Skill | Model | Description |
38
38
  |-------|-------|-------------|
39
39
  | [multi-tenant](skills/multi-tenant.md) | sonnet | Multi-tenancy patterns — database isolation strategies, tenant context middleware, data partitioning, cross-tenant query prevention, tenant-aware background jobs, and GDPR data export. |
40
- | [billing-integration](skills/billing-integration.md) | sonnet | Billing integration — Stripe and LemonSqueezy. Subscription lifecycle, webhook handling, usage-based billing, dunning management, and tax handling. |
40
+ | [billing-integration](skills/billing-integration.md) | sonnet | Billing integration — Stripe, LemonSqueezy, and Polar. Subscription + one-time checkout, Standard Webhooks verification, digital product delivery (repo invite, license key), dunning management, and tax handling. |
41
41
  | [subscription-flow](skills/subscription-flow.md) | sonnet | Subscription UI flows — pricing page, checkout, plan upgrades/downgrades, plan migration, annual/monthly toggle with proration preview, coupon codes, lifetime deal support, and cancellation with retention. |
42
42
  | [feature-flags](skills/feature-flags.md) | sonnet | Feature flag management — gradual rollouts, kill switches, A/B testing, user-segment targeting, and stale flag cleanup. |
43
43
  | [team-management](skills/team-management.md) | sonnet | Organization, team, and member permissions — RBAC hierarchy, invite flow with expiry, permission checking at API and UI layers, and audit trail for permission changes. |
@@ -53,11 +53,12 @@ SaaS applications share a common set of hard problems that most teams solve from
53
53
 
54
54
  ## Tech Stack Support
55
55
 
56
- | Billing Provider | SDK | Webhook Verification | Vietnam/Global |
57
- |---|---|---|---|
58
- | Stripe | stripe-node v17+ | Built-in `constructEvent` | Requires US/EU entity |
59
- | LemonSqueezy | @lemonsqueezy/lemonsqueezy.js | HMAC SHA256 header | ✅ Works globally, Merchant of Record |
60
- | Paddle | @paddle/paddle-node-sdk | Paddle webhook SDK | ✅ Works globally, Merchant of Record |
56
+ | Billing Provider | SDK | Webhook Verification | Vietnam/Global | Best For |
57
+ |---|---|---|---|---|
58
+ | Stripe | stripe-node v17+ | Built-in `constructEvent` | Requires US/EU entity | Full-featured SaaS billing |
59
+ | LemonSqueezy | @lemonsqueezy/lemonsqueezy.js | HMAC SHA256 `x-signature` | ✅ MoR, global | Subscriptions, global sellers |
60
+ | Polar | @polar-sh/sdk | Standard Webhooks (HMAC SHA256) | ✅ MoR, global | Developer tools, one-time purchases, OSS monetization |
61
+ | Paddle | @paddle/paddle-node-sdk | Paddle webhook SDK | ✅ MoR, global | B2B SaaS, complex tax |
61
62
 
62
63
  | Feature Flag Provider | Self-hosted | Managed | Best For |
63
64
  |---|---|---|---|
@@ -95,11 +96,15 @@ Called By ← ba (L2): translating business requirements into SaaS implementatio
95
96
  | Feature gate checked client-side only (bypassed via API) | HIGH | Enforce feature gates in API middleware, not just UI components |
96
97
  | Last org Owner removed (org locked out) | HIGH | Block role change that would leave org with zero Owners |
97
98
  | Stale feature flags accumulate (>50 flags, no cleanup) | MEDIUM | Weekly CI job: detect flags in code not in provider and vice versa |
99
+ | Checkout metadata missing fulfillment context (no user ID, no GitHub username) | HIGH | Always pass user identifier in checkout metadata — webhook handler cannot look up user without it |
100
+ | GitHub invite fails silently, order marked delivered | HIGH | Check invite API response status; mark order as `partial` if any repo invite fails; implement admin retry endpoint |
101
+ | Standard Webhooks timestamp replay attack | MEDIUM | Reject webhook-timestamp older than 5 minutes; prevents replayed webhook payloads |
98
102
 
99
103
  ## Done When
100
104
 
101
105
  - Tenant isolation audited: every query scoped, RLS or middleware enforced, background jobs carry tenantId, GDPR export endpoint implemented
102
- - Billing webhooks verified, idempotent, and handling all lifecycle events including dunning flow
106
+ - Billing webhooks verified (provider-specific signature or Standard Webhooks HMAC), idempotent, and handling all lifecycle events including dunning flow
107
+ - One-time checkout flow implemented with metadata-driven delivery (repo invite, license key, or download link)
103
108
  - Subscription flow has pricing page, checkout, upgrade, downgrade, proration preview, coupon codes, cancellation, and lifetime deal support
104
109
  - Feature flags implemented with evaluation caching, stale flag detection, and test mocking
105
110
  - Team RBAC implemented with invite flow, permission middleware, and audit trail