@sensorario/sg-components 0.0.101 → 0.0.102

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.
@@ -0,0 +1,10 @@
1
+ import './AppAccessGate.css';
2
+ export declare const DEFAULT_HEIMDALL_URL = "https://api.simonegentili.com/heimdall";
3
+ interface AppAccessGateProps {
4
+ /** Logged-in user's JWT. Without it there's nothing to check: the app's own login flow applies. */
5
+ token: string | null;
6
+ /** Base URL of the Heimdall API (`/access`, `/access-requests`). */
7
+ heimdallUrl?: string;
8
+ }
9
+ export declare const AppAccessGate: ({ token, heimdallUrl }: AppAccessGateProps) => import("react/jsx-runtime").JSX.Element | null;
10
+ export default AppAccessGate;
@@ -0,0 +1,8 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import AppAccessGate from './AppAccessGate';
3
+ declare const meta: Meta<typeof AppAccessGate>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof AppAccessGate>;
6
+ export declare const NotGranted: Story;
7
+ export declare const Pending: Story;
8
+ export declare const Rejected: Story;
@@ -9,6 +9,8 @@ interface AppLauncherProps {
9
9
  appsUrl?: string;
10
10
  /** Accessible name of the grid button - this library has no i18n of its own. */
11
11
  label?: string;
12
+ /** Logged-in user's JWT: the API then lists only the apps this user may use. */
13
+ token?: string | null;
12
14
  }
13
- export declare const AppLauncher: ({ appsUrl, label }: AppLauncherProps) => import("react/jsx-runtime").JSX.Element;
15
+ export declare const AppLauncher: ({ appsUrl, label, token }: AppLauncherProps) => import("react/jsx-runtime").JSX.Element;
14
16
  export default AppLauncher;
@@ -17,6 +17,8 @@ interface QuadratoHeaderProps {
17
17
  onUserAuthenticated?: (isAuthenticated: boolean, username: string | null) => void;
18
18
  /** Endpoint of the app launcher menu. Default: the Heimdall-managed list on api.simonegentili.com. */
19
19
  appsUrl?: string;
20
+ /** Base URL of the Heimdall API, used to check whether the logged-in user may use this app. */
21
+ heimdallUrl?: string;
20
22
  }
21
23
  export interface QuadratoHeaderHandle {
22
24
  /** Forces the login modal open, e.g. when a consumer action requires auth first. */
package/dist/index.d.ts CHANGED
@@ -16,3 +16,4 @@ export * from './components/ColorPicker/ColorPicker';
16
16
  export * from './components/FontPicker/FontPicker';
17
17
  export * from './components/Toggle/Toggle';
18
18
  export * from './components/AppLauncher/AppLauncher';
19
+ export * from './components/AppAccessGate/AppAccessGate';
package/dist/index.es.js CHANGED
@@ -347,51 +347,117 @@ var v = ({ privacyPolicyHref: e = "https://simonegentili.com/privacy" }) => {
347
347
  onNavigate: e,
348
348
  title: "Simone Gentili - senior web developer, tech author and chess enthusiast",
349
349
  homePageKey: "home"
350
- }), C = "https://api.simonegentili.com/heimdall/launcher", w = ({ appsUrl: e = C, label: t = "App" }) => {
351
- let [r, i] = o(!1), [s, u] = o(null), [f, p] = o(!1), m = a(null);
350
+ }), C = "https://api.simonegentili.com/heimdall", w = (e) => e.endsWith("/") ? e : `${e}/`, T = (e) => {
351
+ let t = w(window.location.origin + window.location.pathname);
352
+ return e.filter((e) => t.startsWith(w(e.url))).sort((e, t) => t.url.length - e.url.length)[0] ?? null;
353
+ }, E = ({ token: e, heimdallUrl: t = C }) => {
354
+ let [r, i] = o(null), [a, u] = o(!1), [d, p] = o(!1);
355
+ n(() => {
356
+ e && fetch(`${t}/access`, { headers: { Authorization: `Bearer ${e}` } }).then((e) => e.ok ? e.json() : Promise.reject(e.status)).then((t) => i({
357
+ token: e,
358
+ app: T(t.apps)
359
+ })).catch(() => i({
360
+ token: e,
361
+ app: null
362
+ }));
363
+ }, [e, t]);
364
+ let m = r?.token === e ? r.app : null;
365
+ return !e || m === null || m.access === "open" || m.access === "approved" ? null : /* @__PURE__ */ c("div", {
366
+ className: "sg-access-gate",
367
+ role: "dialog",
368
+ "aria-modal": "true",
369
+ "aria-labelledby": "sg-access-gate-title",
370
+ children: /* @__PURE__ */ l("div", {
371
+ className: "sg-access-gate-card",
372
+ children: [/* @__PURE__ */ l("h2", {
373
+ id: "sg-access-gate-title",
374
+ children: ["Non hai accesso a ", m.name]
375
+ }), m.access === "pending" ? /* @__PURE__ */ c("p", { children: "La tua richiesta è in attesa di approvazione." }) : /* @__PURE__ */ l(s, { children: [
376
+ /* @__PURE__ */ c("p", { children: m.access === "rejected" ? "La tua richiesta di accesso è stata rifiutata. Puoi inviarne una nuova." : "Per usare questa app devi chiedere l’accesso a un amministratore." }),
377
+ d && /* @__PURE__ */ c("p", {
378
+ className: "sg-access-gate-error",
379
+ children: "Invio non riuscito, riprova."
380
+ }),
381
+ /* @__PURE__ */ c(f, {
382
+ label: a ? "Invio…" : "Richiedi accesso",
383
+ disabled: a,
384
+ onClick: async () => {
385
+ u(!0), p(!1);
386
+ try {
387
+ let n = await fetch(`${t}/access-requests`, {
388
+ method: "POST",
389
+ headers: {
390
+ Authorization: `Bearer ${e}`,
391
+ "Content-Type": "application/json"
392
+ },
393
+ body: JSON.stringify({ app: m.slug })
394
+ });
395
+ n.ok || n.status === 409 ? i({
396
+ token: e,
397
+ app: {
398
+ ...m,
399
+ access: "pending"
400
+ }
401
+ }) : p(!0);
402
+ } catch {
403
+ p(!0);
404
+ } finally {
405
+ u(!1);
406
+ }
407
+ }
408
+ })
409
+ ] })]
410
+ })
411
+ });
412
+ }, D = "https://api.simonegentili.com/heimdall/launcher", O = ({ appsUrl: e = D, label: t = "App", token: r = null }) => {
413
+ let [i, s] = o(!1), [u, f] = o(null), p = u?.token === r ? u.apps : null, [m, h] = o(!1), g = a(null);
352
414
  return n(() => {
353
- !r || s !== null || fetch(e).then((e) => e.ok ? e.json() : Promise.reject(e.status)).then((e) => u(e.apps)).catch(() => p(!0));
415
+ !i || p !== null || fetch(e, r ? { headers: { Authorization: `Bearer ${r}` } } : void 0).then((e) => e.ok ? e.json() : Promise.reject(e.status)).then((e) => f({
416
+ token: r,
417
+ apps: e.apps
418
+ })).catch(() => h(!0));
354
419
  }, [
355
- r,
356
- s,
357
- e
420
+ i,
421
+ p,
422
+ e,
423
+ r
358
424
  ]), n(() => {
359
- if (!r) return;
425
+ if (!i) return;
360
426
  let e = (e) => {
361
- m.current?.contains(e.target) || i(!1);
427
+ g.current?.contains(e.target) || s(!1);
362
428
  }, t = (e) => {
363
- e.key === "Escape" && i(!1);
429
+ e.key === "Escape" && s(!1);
364
430
  };
365
431
  return document.addEventListener("pointerdown", e), document.addEventListener("keydown", t), () => {
366
432
  document.removeEventListener("pointerdown", e), document.removeEventListener("keydown", t);
367
433
  };
368
- }, [r]), /* @__PURE__ */ l("div", {
434
+ }, [i]), /* @__PURE__ */ l("div", {
369
435
  className: "sg-app-launcher",
370
- ref: m,
436
+ ref: g,
371
437
  children: [/* @__PURE__ */ c("button", {
372
438
  type: "button",
373
439
  className: "sg-app-launcher-toggle",
374
440
  "aria-label": t,
375
441
  title: t,
376
- "aria-expanded": r,
442
+ "aria-expanded": i,
377
443
  onClick: () => {
378
- r || p(!1), i(!r);
444
+ i || h(!1), s(!i);
379
445
  },
380
446
  children: /* @__PURE__ */ c(d, {
381
447
  name: "grid",
382
448
  size: 22
383
449
  })
384
- }), r && /* @__PURE__ */ c("div", {
450
+ }), i && /* @__PURE__ */ c("div", {
385
451
  className: "sg-app-launcher-panel",
386
- children: f ? /* @__PURE__ */ c("p", {
452
+ children: m ? /* @__PURE__ */ c("p", {
387
453
  className: "sg-app-launcher-message",
388
454
  children: "Impossibile caricare le app."
389
- }) : s === null ? /* @__PURE__ */ c("p", {
455
+ }) : p === null ? /* @__PURE__ */ c("p", {
390
456
  className: "sg-app-launcher-message",
391
457
  children: "Caricamento…"
392
458
  }) : /* @__PURE__ */ c("ul", {
393
459
  className: "sg-app-launcher-grid",
394
- children: s.map((e) => /* @__PURE__ */ c("li", { children: /* @__PURE__ */ l("a", {
460
+ children: p.map((e) => /* @__PURE__ */ c("li", { children: /* @__PURE__ */ l("a", {
395
461
  href: e.url,
396
462
  className: new URL(e.url).origin === window.location.origin ? "sg-app-launcher-app current" : "sg-app-launcher-app",
397
463
  children: [/* @__PURE__ */ c("span", {
@@ -406,7 +472,7 @@ var v = ({ privacyPolicyHref: e = "https://simonegentili.com/privacy" }) => {
406
472
  })
407
473
  })]
408
474
  });
409
- }, T = ({ isLoggedIn: e, handleLogin: t, handleLogout: n }) => /* @__PURE__ */ c(s, { children: e ? /* @__PURE__ */ c("button", {
475
+ }, k = ({ isLoggedIn: e, handleLogin: t, handleLogout: n }) => /* @__PURE__ */ c(s, { children: e ? /* @__PURE__ */ c("button", {
410
476
  onClick: n,
411
477
  className: "sg-authenticator-button",
412
478
  children: "logout"
@@ -414,14 +480,14 @@ var v = ({ privacyPolicyHref: e = "https://simonegentili.com/privacy" }) => {
414
480
  onClick: t,
415
481
  className: "sg-authenticator-button",
416
482
  children: "Login"
417
- }) }), E = 220, D = ({ open: t, onClose: r, title: i, icon: a, children: s, buttons: u, footer: d, closeLabel: p = "Close", className: m }) => {
483
+ }) }), A = 220, j = ({ open: t, onClose: r, title: i, icon: a, children: s, buttons: u, footer: d, closeLabel: p = "Close", className: m }) => {
418
484
  let [h, g] = o(!1), [_, v] = o({
419
485
  x: 0,
420
486
  y: 0
421
487
  }), y = e.useRef(null), [b, x] = o(!1), S = (e) => {
422
488
  h || (g(!0), setTimeout(() => {
423
489
  g(!1), e();
424
- }, E));
490
+ }, A));
425
491
  };
426
492
  n(() => {
427
493
  if (!t) return;
@@ -443,7 +509,7 @@ var v = ({ privacyPolicyHref: e = "https://simonegentili.com/privacy" }) => {
443
509
  offsetY: _.y
444
510
  }, x(!0), e.currentTarget.setPointerCapture(e.pointerId));
445
511
  }
446
- function D(e) {
512
+ function E(e) {
447
513
  if (!y.current) return;
448
514
  let { pointerX: t, pointerY: n, offsetX: r, offsetY: i } = y.current;
449
515
  v({
@@ -451,7 +517,7 @@ var v = ({ privacyPolicyHref: e = "https://simonegentili.com/privacy" }) => {
451
517
  y: i + (e.clientY - n)
452
518
  });
453
519
  }
454
- function O() {
520
+ function D() {
455
521
  y.current = null, x(!1);
456
522
  }
457
523
  return /* @__PURE__ */ c("div", {
@@ -468,9 +534,9 @@ var v = ({ privacyPolicyHref: e = "https://simonegentili.com/privacy" }) => {
468
534
  /* @__PURE__ */ l("div", {
469
535
  className: `modal-header${b ? " modal-header-dragging" : ""}`,
470
536
  onPointerDown: T,
471
- onPointerMove: D,
472
- onPointerUp: O,
473
- onPointerCancel: O,
537
+ onPointerMove: E,
538
+ onPointerUp: D,
539
+ onPointerCancel: D,
474
540
  children: [
475
541
  a && /* @__PURE__ */ c("span", {
476
542
  className: "modal-icon",
@@ -509,7 +575,7 @@ var v = ({ privacyPolicyHref: e = "https://simonegentili.com/privacy" }) => {
509
575
  ]
510
576
  })
511
577
  });
512
- }, O = ({ label: e, invalid: t, className: n, id: i, ...a }) => {
578
+ }, M = ({ label: e, invalid: t, className: n, id: i, ...a }) => {
513
579
  let o = r(), s = i ?? o;
514
580
  return /* @__PURE__ */ l("div", {
515
581
  className: "input-wrapper",
@@ -527,7 +593,7 @@ var v = ({ privacyPolicyHref: e = "https://simonegentili.com/privacy" }) => {
527
593
  ...a
528
594
  })]
529
595
  });
530
- }, k = ({ label: e, className: t, id: n, ...i }) => {
596
+ }, N = ({ label: e, className: t, id: n, ...i }) => {
531
597
  let a = r(), o = n ?? a;
532
598
  return /* @__PURE__ */ l("div", {
533
599
  className: "input-wrapper",
@@ -542,9 +608,9 @@ var v = ({ privacyPolicyHref: e = "https://simonegentili.com/privacy" }) => {
542
608
  ...i
543
609
  })]
544
610
  });
545
- }, A = ({ open: e, onClose: t, onLogin: n }) => {
611
+ }, P = ({ open: e, onClose: t, onLogin: n }) => {
546
612
  let [r, i] = o(""), [a, s] = o("");
547
- return /* @__PURE__ */ c(D, {
613
+ return /* @__PURE__ */ c(j, {
548
614
  open: e,
549
615
  onClose: t,
550
616
  title: "Login",
@@ -553,13 +619,13 @@ var v = ({ privacyPolicyHref: e = "https://simonegentili.com/privacy" }) => {
553
619
  e.preventDefault(), n(r, a);
554
620
  },
555
621
  children: [
556
- /* @__PURE__ */ c(O, {
622
+ /* @__PURE__ */ c(M, {
557
623
  label: "Username",
558
624
  value: r,
559
625
  onChange: (e) => i(e.target.value),
560
626
  autoFocus: !0
561
627
  }),
562
- /* @__PURE__ */ c(k, {
628
+ /* @__PURE__ */ c(N, {
563
629
  label: "Password",
564
630
  value: a,
565
631
  onChange: (e) => s(e.target.value)
@@ -572,57 +638,67 @@ var v = ({ privacyPolicyHref: e = "https://simonegentili.com/privacy" }) => {
572
638
  ]
573
639
  })
574
640
  });
575
- }, j = "simonegentili.com-access-token", M = (e) => document.cookie.split("; ").some((t) => t.startsWith(`${e}=`) && t.slice(e.length + 1).length > 0), N = (e) => {
641
+ }, F = "simonegentili.com-access-token", I = (e) => document.cookie.split("; ").some((t) => t.startsWith(`${e}=`) && t.slice(e.length + 1).length > 0), L = (e) => {
576
642
  let t = document.cookie.split("; ").find((t) => t.startsWith(`${e}=`));
577
643
  return t ? t.slice(e.length + 1) : null;
578
- }, P = (e, t) => {
644
+ }, R = (e, t) => {
579
645
  try {
580
646
  return JSON.parse(atob(e.split(".")[1].replace(/-/g, "+").replace(/_/g, "/")))[t] ?? null;
581
647
  } catch {
582
648
  return null;
583
649
  }
584
- }, F = t(({ title: e = "Quadrato", homePageKey: t = "home", onNavigate: r, cookieName: a = j, username: u = null, usernameJwtField: d = "sub", onLogin: f, onLogout: p, onUserAuthenticated: m, appsUrl: h }, g) => {
585
- let [_, v] = o(() => M(a)), [y, b] = o(!1);
586
- i(g, () => ({ openLoginModal: () => b(!0) }));
587
- let S = u ?? (_ ? P(N(a) ?? "", d) : null);
650
+ }, z = t(({ title: e = "Quadrato", homePageKey: t = "home", onNavigate: r, cookieName: a = F, username: u = null, usernameJwtField: d = "sub", onLogin: f, onLogout: p, onUserAuthenticated: m, appsUrl: h, heimdallUrl: g }, _) => {
651
+ let [v, y] = o(() => I(a)), [b, S] = o(!1);
652
+ i(_, () => ({ openLoginModal: () => S(!0) }));
653
+ let C = v ? L(a) : null, w = u ?? (C ? R(C, d) : null);
588
654
  return n(() => {
589
- m?.(_, _ ? S : null);
590
- }, []), /* @__PURE__ */ l(s, { children: [/* @__PURE__ */ l(x, {
591
- onNavigate: r,
592
- title: e,
593
- homePageKey: t,
594
- className: "quadrato-header",
595
- children: [/* @__PURE__ */ c(w, { appsUrl: h }), /* @__PURE__ */ l("div", {
596
- className: "quadrato-header-auth",
597
- children: [_ && S && /* @__PURE__ */ c("span", {
598
- className: "quadrato-header-username",
599
- children: S
600
- }), /* @__PURE__ */ c(T, {
601
- isLoggedIn: _,
602
- handleLogin: () => b(!0),
603
- handleLogout: () => {
604
- p?.();
605
- let e = M(a);
606
- v(e), m?.(e, null);
607
- }
655
+ m?.(v, v ? w : null);
656
+ }, []), /* @__PURE__ */ l(s, { children: [
657
+ /* @__PURE__ */ l(x, {
658
+ onNavigate: r,
659
+ title: e,
660
+ homePageKey: t,
661
+ className: "quadrato-header",
662
+ children: [/* @__PURE__ */ c(O, {
663
+ appsUrl: h,
664
+ token: C
665
+ }), /* @__PURE__ */ l("div", {
666
+ className: "quadrato-header-auth",
667
+ children: [v && w && /* @__PURE__ */ c("span", {
668
+ className: "quadrato-header-username",
669
+ children: w
670
+ }), /* @__PURE__ */ c(k, {
671
+ isLoggedIn: v,
672
+ handleLogin: () => S(!0),
673
+ handleLogout: () => {
674
+ p?.();
675
+ let e = I(a);
676
+ y(e), m?.(e, null);
677
+ }
678
+ })]
608
679
  })]
609
- })]
610
- }), /* @__PURE__ */ c(A, {
611
- open: y,
612
- onClose: () => b(!1),
613
- onLogin: async (e, t) => {
614
- await f(e, t);
615
- let n = M(a);
616
- v(n), b(!1), m?.(n, n ? u ?? e : null);
617
- }
618
- })] });
680
+ }),
681
+ /* @__PURE__ */ c(E, {
682
+ token: C,
683
+ heimdallUrl: g
684
+ }),
685
+ /* @__PURE__ */ c(P, {
686
+ open: b,
687
+ onClose: () => S(!1),
688
+ onLogin: async (e, t) => {
689
+ await f(e, t);
690
+ let n = I(a);
691
+ y(n), S(!1), m?.(n, n ? u ?? e : null);
692
+ }
693
+ })
694
+ ] });
619
695
  });
620
- F.displayName = "QuadratoHeader";
696
+ z.displayName = "QuadratoHeader";
621
697
  //#endregion
622
698
  //#region src/components/SetPasswordModal/SetPasswordModal.tsx
623
- var I = ({ open: e, onClose: t, onSubmit: n }) => {
699
+ var B = ({ open: e, onClose: t, onSubmit: n }) => {
624
700
  let [r, i] = o(""), [a, s] = o(""), [u, d] = o("");
625
- return /* @__PURE__ */ c(D, {
701
+ return /* @__PURE__ */ c(j, {
626
702
  open: e,
627
703
  onClose: t,
628
704
  title: "Imposta una nuova password",
@@ -640,13 +716,13 @@ var I = ({ open: e, onClose: t, onSubmit: n }) => {
640
716
  d(""), n(r);
641
717
  },
642
718
  children: [
643
- /* @__PURE__ */ c(k, {
719
+ /* @__PURE__ */ c(N, {
644
720
  label: "Nuova password",
645
721
  value: r,
646
722
  onChange: (e) => i(e.target.value),
647
723
  autoFocus: !0
648
724
  }),
649
- /* @__PURE__ */ c(k, {
725
+ /* @__PURE__ */ c(N, {
650
726
  label: "Conferma password",
651
727
  value: a,
652
728
  onChange: (e) => s(e.target.value)
@@ -663,7 +739,7 @@ var I = ({ open: e, onClose: t, onSubmit: n }) => {
663
739
  ]
664
740
  })
665
741
  });
666
- }, L = ({ value: e, onChange: t, swatches: r }) => {
742
+ }, V = ({ value: e, onChange: t, swatches: r }) => {
667
743
  let [i, s] = o(!1), u = a(null);
668
744
  return n(() => {
669
745
  if (!i) return;
@@ -712,7 +788,7 @@ var I = ({ open: e, onClose: t, onSubmit: n }) => {
712
788
  })]
713
789
  })]
714
790
  });
715
- }, R = (e) => e.split(",")[0].replace(/'/g, ""), z = ({ value: e, onChange: t, options: r }) => {
791
+ }, H = (e) => e.split(",")[0].replace(/'/g, ""), U = ({ value: e, onChange: t, options: r }) => {
716
792
  let [i, s] = o(!1), u = a(null);
717
793
  return n(() => {
718
794
  if (!i) return;
@@ -734,7 +810,7 @@ var I = ({ open: e, onClose: t, onSubmit: n }) => {
734
810
  style: { fontFamily: e },
735
811
  children: [/* @__PURE__ */ c("span", {
736
812
  className: "sg-font-picker-toggle-label",
737
- children: R(e)
813
+ children: H(e)
738
814
  }), /* @__PURE__ */ c("span", {
739
815
  className: "sg-font-picker-toggle-caret",
740
816
  children: i ? "▲" : "▼"
@@ -748,11 +824,11 @@ var I = ({ open: e, onClose: t, onSubmit: n }) => {
748
824
  t(n), s(!1);
749
825
  },
750
826
  style: { fontFamily: n },
751
- children: R(n)
827
+ children: H(n)
752
828
  }) }, n))
753
829
  })]
754
830
  });
755
- }, B = ({ checked: e, onChange: t, label: n }) => /* @__PURE__ */ l("label", {
831
+ }, W = ({ checked: e, onChange: t, label: n }) => /* @__PURE__ */ l("label", {
756
832
  className: "sg-toggle",
757
833
  children: [
758
834
  /* @__PURE__ */ c("input", {
@@ -772,4 +848,4 @@ var I = ({ open: e, onClose: t, onSubmit: n }) => {
772
848
  ]
773
849
  });
774
850
  //#endregion
775
- export { w as AppLauncher, T as Authenticator, f as Button, L as ColorPicker, v as CookieConsent, C as DEFAULT_APPS_URL, z as FontPicker, p as Footer, x as Header, d as Icon, O as Input, D as Modal, k as PasswordInput, F as QuadratoHeader, b as SGFooter, S as SGHeader, I as SetPasswordModal, B as Toggle };
851
+ export { E as AppAccessGate, O as AppLauncher, k as Authenticator, f as Button, V as ColorPicker, v as CookieConsent, D as DEFAULT_APPS_URL, C as DEFAULT_HEIMDALL_URL, U as FontPicker, p as Footer, x as Header, d as Icon, M as Input, j as Modal, N as PasswordInput, z as QuadratoHeader, b as SGFooter, S as SGHeader, B as SetPasswordModal, W as Toggle };
@@ -1,2 +1,2 @@
1
- .custom-button{border-radius:var(--button-radius);background:var(--button-bg);color:var(--button-color);cursor:pointer;font-size:var(--primary-font);font-weight:600;font-family:var(--font-family);box-shadow:var(--button-shadow);transition:background .15s var(--button-ease-standard), transform var(--button-ease-bounce) .2s;border:none;padding:8px 20px}.custom-button:hover:not(:disabled){background:var(--button-bg-hover);transform:translateY(-1px)}.custom-button:active:not(:disabled){transform:scale(.97)}.custom-button:disabled{opacity:.6;cursor:default}.custom-button-with-icon{align-items:center;gap:8px;display:inline-flex}.custom-button-label-visually-hidden{clip:rect(0, 0, 0, 0);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.sg-icon{vertical-align:middle;flex-shrink:0;display:inline-block}.footer{background-color:var(--primary-bg);border-top:1px solid var(--primary-border);font-family:var(--font-family);color:#555;justify-content:space-between;align-items:center;width:100%;padding:16px 32px;font-size:14px;display:flex;position:fixed;bottom:0;left:0}.footer a{color:#1ea7fd;text-decoration:none}.footer a:hover{text-decoration:underline}.cookie-consent{background-color:var(--primary-bg);border-top:1px solid var(--primary-border);font-family:var(--font-family);color:#555;z-index:1000;box-sizing:border-box;flex-wrap:wrap;justify-content:center;align-items:center;gap:16px;width:100%;padding:16px 32px;font-size:14px;display:flex;position:fixed;bottom:0;left:0}.cookie-consent-text{flex:320px;margin:0}.cookie-consent a{color:#1ea7fd;text-decoration:none}.cookie-consent a:hover{text-decoration:underline}.cookie-consent-accept{flex:none}.logo-text{font-size:var(--font-size-h1);font-family:var(--font-family);margin:0;font-weight:400}.header{z-index:100;width:100%;font-size:var(--font-size);background-color:#fff;border-bottom:1px solid #e1e5e9;position:sticky;top:0;box-shadow:0 2px 4px #0000001a}.header-container{justify-content:flex-start;align-items:center;max-width:1200px;margin:0 auto;padding:16px;display:flex}.header-actions{align-items:center;gap:12px;margin-left:auto;display:flex}.logo{cursor:pointer;color:#333;font-size:24px;font-weight:700;transition:color .2s}.logo:hover{color:#007acc}.logo-full{display:inline}.logo-short{display:none}@media (width<=768px){.header-container{padding:12px 16px}.logo{font-size:var(--font-size)}.logo-full{display:none}.logo-short{display:inline}}@media (width<=480px){.header-container{padding:8px 12px}.logo{font-size:var(--font-size)}}.sg-app-launcher{font-family:var(--font-family);position:relative}.sg-app-launcher-toggle{width:40px;height:40px;color:var(--ink-muted);cursor:pointer;background:0 0;border:none;border-radius:50%;justify-content:center;align-items:center;padding:0;display:inline-flex}.sg-app-launcher-toggle:hover,.sg-app-launcher-toggle[aria-expanded=true]{background:var(--primary-hover-bg)}.sg-app-launcher-panel{z-index:1000;box-sizing:border-box;border:1px solid var(--primary-border);border-radius:calc(var(--radius) * 3);background:var(--modal-bg);width:320px;max-width:calc(100vw - 24px);max-height:70vh;box-shadow:var(--shadow-2);padding:12px;position:absolute;top:calc(100% + 8px);right:0;overflow-y:auto}.sg-app-launcher-grid{grid-template-columns:repeat(3,minmax(0,1fr));gap:4px;margin:0;padding:0;list-style:none;display:grid}.sg-app-launcher-app{border-radius:var(--radius);color:inherit;flex-direction:column;align-items:center;gap:6px;padding:12px 4px;text-decoration:none;display:flex}.sg-app-launcher-app:hover,.sg-app-launcher-app:focus-visible{background:var(--primary-hover-bg)}.sg-app-launcher-app.current{background:var(--accent-soft)}.sg-app-launcher-tile{border-radius:var(--radius);background:var(--accent);color:#fff;justify-content:center;align-items:center;width:40px;height:40px;font-size:18px;font-weight:600;display:flex}.sg-app-launcher-name{text-overflow:ellipsis;white-space:nowrap;max-width:100%;font-size:13px;overflow:hidden}.sg-app-launcher-message{color:var(--ink-muted);margin:0;padding:8px;font-size:13px}.sg-authenticator-button{font-size:.9rem;font-family:var(--font-family);border:1px solid var(--primary-border);border-radius:var(--radius);background:var(--primary-bg);color:#333;cursor:pointer;padding:.4rem 1rem;transition:background .15s,border-color .15s}.sg-authenticator-button:hover{background:var(--primary-hover-bg);border-color:var(--ink-muted)}.modal-overlay{background:var(--modal-overlay);z-index:1000;justify-content:center;align-items:center;width:100vw;height:100vh;animation:.25s ease-out sg-modal-overlay-fade-in;display:flex;position:fixed;top:0;left:0}.modal-overlay.modal-overlay-closing{animation:.22s ease-in forwards sg-modal-overlay-fade-out}.modal-content{--drag-x:0px;--drag-y:0px;background:var(--modal-bg);border-radius:var(--primary-radius);font-size:var(--primary-font);min-width:320px;max-width:calc(100vw - 40px);max-height:90vh;transform:translate(var(--drag-x), var(--drag-y));flex-direction:column;animation:.3s ease-out sg-modal-slide-in;display:flex;overflow:hidden;box-shadow:0 2px 16px #00000026}.modal-content.modal-content-closing{animation:.22s ease-in forwards sg-modal-slide-out}@keyframes sg-modal-overlay-fade-in{0%{opacity:0}to{opacity:1}}@keyframes sg-modal-overlay-fade-out{0%{opacity:1}to{opacity:0}}@keyframes sg-modal-slide-in{0%{transform:translate(var(--drag-x), calc(var(--drag-y) - 24px)) scale(.97);opacity:0}to{transform:translate(var(--drag-x), var(--drag-y)) scale(1);opacity:1}}@keyframes sg-modal-slide-out{0%{transform:translate(var(--drag-x), var(--drag-y)) scale(1);opacity:1}to{transform:translate(var(--drag-x), calc(var(--drag-y) - 24px)) scale(.97);opacity:0}}.modal-header{background:var(--primary-bg);border-top-left-radius:var(--primary-radius);border-top-right-radius:var(--primary-radius);cursor:grab;touch-action:none;flex:none;align-items:center;gap:8px;padding:16px;display:flex}.modal-header-dragging{cursor:grabbing;-webkit-user-select:none;user-select:none}.modal-icon{color:var(--modal-title-color);display:inline-flex}.modal-title{color:var(--modal-title-color);font-family:var(--font-family);font-size:var(--primary-font);flex:1;margin:0}.modal-close{cursor:pointer;color:var(--modal-title-color);background:0 0;border:none;padding:4px 8px;font-size:20px;line-height:1}.modal-close:disabled{cursor:default;opacity:.6}.modal-children{font-family:var(--font-family);padding:16px;overflow-y:auto}.modal-footer{border-top:1px solid var(--primary-border);flex-wrap:wrap;flex:none;justify-content:flex-end;gap:8px;padding:12px 16px;display:flex}.input-label{font-weight:500;font-family:var(--font-family);font-size:var(--primary-font);margin-bottom:4px;display:block}.input-field--invalid{background-color:#ffe5e5;border-color:#c00}.input-wrapper{margin-bottom:16px}.input-label{font-weight:500;font-size:var(--primary-font);margin-bottom:4px;display:block}.input-field{box-sizing:border-box;border-radius:var(--radius);width:100%;font-size:var(--primary-font);border-style:solid;border-width:1px;padding:8px}.login-modal-form{font-family:var(--font-family);font-size:var(--primary-font);flex-direction:column;gap:16px;display:flex}.header.quadrato-header{z-index:999}.quadrato-header-auth{align-items:center;gap:12px;display:flex}.quadrato-header-username{font-size:var(--font-size);color:#333;transition:color .2s}.quadrato-header-username:hover{color:var(--accent)}form{font-family:var(--font-family)}.set-password-modal-form{font-family:var(--font-family);font-size:var(--primary-font);flex-direction:column;gap:16px;display:flex}.set-password-modal-error{color:#d32f2f;font-size:var(--primary-font);margin:0}.sg-color-picker{font-family:var(--font-family);position:relative}.sg-color-picker-toggle{border-radius:var(--input-radius);border:1px solid var(--input-border);background:var(--input-bg);width:100%;color:inherit;cursor:pointer;justify-content:space-between;align-items:center;gap:8px;padding:6px 8px;font-family:inherit;font-size:13px;display:flex}.sg-color-picker-toggle-label{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.sg-color-picker-swatch{border:1px solid #00000026;border-radius:4px;flex:none;width:18px;height:18px}.sg-color-picker-popover{z-index:30;background:var(--input-bg);border:1px solid var(--input-border);border-radius:var(--input-radius);box-shadow:var(--shadow-1);width:170px;padding:10px;position:absolute;top:calc(100% + 4px);left:0}.sg-color-picker-grid{grid-template-columns:repeat(6,1fr);gap:6px;display:grid}.sg-color-picker-swatch-button{cursor:pointer;border:1px solid #00000026;border-radius:4px;width:20px;height:20px;padding:0}.sg-color-picker-swatch-button.active{border:2px solid var(--accent)}.sg-color-picker-custom{border-top:1px solid var(--input-border);color:var(--ink-muted);cursor:pointer;justify-content:space-between;align-items:center;gap:8px;margin-top:8px;padding-top:8px;font-size:11px;display:flex}.sg-color-picker-custom input[type=color]{cursor:pointer;border:none;width:26px;height:20px;padding:0}.sg-font-picker{font-family:var(--font-family);position:relative}.sg-font-picker-toggle{border-radius:var(--input-radius);border:1px solid var(--input-border);background:var(--input-bg);width:100%;color:inherit;cursor:pointer;justify-content:space-between;align-items:center;gap:8px;padding:6px 8px;font-size:13px;display:flex}.sg-font-picker-toggle-label{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.sg-font-picker-toggle-caret{opacity:.5;flex:none;font-size:10px}.sg-font-picker-list{background:var(--input-bg);border:1px solid var(--input-border);border-radius:var(--input-radius);max-height:260px;box-shadow:var(--shadow-1);z-index:30;margin:0;padding:4px 0;list-style:none;position:absolute;top:calc(100% + 4px);left:0;right:0;overflow-y:auto}.sg-font-picker-option{text-align:left;width:100%;color:inherit;cursor:pointer;background:0 0;border:none;padding:8px 10px;font-size:15px;display:block}.sg-font-picker-option.active{background:var(--accent-soft)}:root{--unit:3px;--primary-bg:#f5f5f5;--primary-border:#ccc;--radius:calc(var(--unit) * 2);--primary-radius:var(--radius);--primary-font:var(--font-size);--primary-hover-bg:#e0e0e0;--modal-bg:#fff;--modal-overlay:#0000004d;--modal-title-color:#222;--input-bg:#fff;--input-border:#ccc;--input-radius:var(--radius);--input-font:1rem;--font-size:14px;--font-family:Arial, sans-serif;--font-size-h1:calc(var(--font-size) * 1.5);--button-bg:#6f9cf7;--button-bg-hover:#5480e6;--button-color:#fff;--button-radius:999px;--button-shadow:0 1px 2px #5480e61f, 0 1px 3px #5480e61a;--button-ease-standard:cubic-bezier(.4, 0, .2, 1);--button-ease-bounce:cubic-bezier(.34, 1.56, .64, 1);--accent:#3d5fc4;--accent-strong:#2e4aa0;--accent-soft:#e2e7f8;--ink-muted:#647089;--shadow-1:0 1px 2px #0f172a14, 0 1px 3px #0f172a0f;--shadow-2:0 4px 12px #0f172a1f}.theme-dark{--primary-bg:#222;--primary-border:#444;--primary-font:1rem;--font-family:"Inter", Arial, sans-serif;--primary-hover-bg:#333;--modal-bg:#222;--modal-title-color:#fff;--input-bg:#333;--input-border:#555;--input-font:1rem;--button-bg:#6f9cf7;--button-bg-hover:#86aefc;--button-color:#fff;--accent:#6f9cf7;--accent-strong:#86aefc;--accent-soft:#6f9cf72e;--ink-muted:#9aa3b5;--shadow-1:0 1px 2px #0000004d, 0 1px 3px #0000003d;--shadow-2:0 4px 12px #0006}.sg-toggle{cursor:pointer;-webkit-user-select:none;user-select:none;font-family:var(--font-family);align-items:center;gap:6px;display:flex}.sg-toggle-input{opacity:0;width:1px;height:1px;position:absolute}.sg-toggle-track{background:var(--input-border);border-radius:999px;flex:none;width:34px;height:20px;transition:background .15s cubic-bezier(.4,0,.2,1);position:relative}.sg-toggle-input:checked+.sg-toggle-track{background:var(--accent)}.sg-toggle-thumb{background:var(--input-bg);width:16px;height:16px;box-shadow:var(--shadow-1);border-radius:50%;transition:left .15s cubic-bezier(.4,0,.2,1);position:absolute;top:2px;left:2px}.sg-toggle-input:checked+.sg-toggle-track .sg-toggle-thumb{left:16px}.sg-toggle-input:focus-visible+.sg-toggle-track{outline:2px solid var(--accent-strong);outline-offset:2px}.sg-toggle-label{color:var(--ink-muted);white-space:nowrap;font-size:13px}
1
+ .custom-button{border-radius:var(--button-radius);background:var(--button-bg);color:var(--button-color);cursor:pointer;font-size:var(--primary-font);font-weight:600;font-family:var(--font-family);box-shadow:var(--button-shadow);transition:background .15s var(--button-ease-standard), transform var(--button-ease-bounce) .2s;border:none;padding:8px 20px}.custom-button:hover:not(:disabled){background:var(--button-bg-hover);transform:translateY(-1px)}.custom-button:active:not(:disabled){transform:scale(.97)}.custom-button:disabled{opacity:.6;cursor:default}.custom-button-with-icon{align-items:center;gap:8px;display:inline-flex}.custom-button-label-visually-hidden{clip:rect(0, 0, 0, 0);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.sg-icon{vertical-align:middle;flex-shrink:0;display:inline-block}.footer{background-color:var(--primary-bg);border-top:1px solid var(--primary-border);font-family:var(--font-family);color:#555;justify-content:space-between;align-items:center;width:100%;padding:16px 32px;font-size:14px;display:flex;position:fixed;bottom:0;left:0}.footer a{color:#1ea7fd;text-decoration:none}.footer a:hover{text-decoration:underline}.cookie-consent{background-color:var(--primary-bg);border-top:1px solid var(--primary-border);font-family:var(--font-family);color:#555;z-index:1000;box-sizing:border-box;flex-wrap:wrap;justify-content:center;align-items:center;gap:16px;width:100%;padding:16px 32px;font-size:14px;display:flex;position:fixed;bottom:0;left:0}.cookie-consent-text{flex:320px;margin:0}.cookie-consent a{color:#1ea7fd;text-decoration:none}.cookie-consent a:hover{text-decoration:underline}.cookie-consent-accept{flex:none}.logo-text{font-size:var(--font-size-h1);font-family:var(--font-family);margin:0;font-weight:400}.header{z-index:100;width:100%;font-size:var(--font-size);background-color:#fff;border-bottom:1px solid #e1e5e9;position:sticky;top:0;box-shadow:0 2px 4px #0000001a}.header-container{justify-content:flex-start;align-items:center;max-width:1200px;margin:0 auto;padding:16px;display:flex}.header-actions{align-items:center;gap:12px;margin-left:auto;display:flex}.logo{cursor:pointer;color:#333;font-size:24px;font-weight:700;transition:color .2s}.logo:hover{color:#007acc}.logo-full{display:inline}.logo-short{display:none}@media (width<=768px){.header-container{padding:12px 16px}.logo{font-size:var(--font-size)}.logo-full{display:none}.logo-short{display:inline}}@media (width<=480px){.header-container{padding:8px 12px}.logo{font-size:var(--font-size)}}.sg-access-gate{z-index:998;box-sizing:border-box;background:var(--primary-bg);font-family:var(--font-family);justify-content:center;align-items:center;padding:16px;display:flex;position:fixed;inset:0}.sg-access-gate-card{border:1px solid var(--primary-border);border-radius:calc(var(--radius) * 3);background:var(--modal-bg);max-width:420px;box-shadow:var(--shadow-2);text-align:center;padding:24px}.sg-access-gate-card h2{font-size:var(--font-size-h1);color:var(--modal-title-color);margin:0 0 12px}.sg-access-gate-card p{color:var(--ink-muted);margin:0 0 16px}.sg-access-gate-card .sg-access-gate-error{color:#c0392b}.sg-app-launcher{font-family:var(--font-family);position:relative}.sg-app-launcher-toggle{width:40px;height:40px;color:var(--ink-muted);cursor:pointer;background:0 0;border:none;border-radius:50%;justify-content:center;align-items:center;padding:0;display:inline-flex}.sg-app-launcher-toggle:hover,.sg-app-launcher-toggle[aria-expanded=true]{background:var(--primary-hover-bg)}.sg-app-launcher-panel{z-index:1000;box-sizing:border-box;border:1px solid var(--primary-border);border-radius:calc(var(--radius) * 3);background:var(--modal-bg);width:320px;max-width:calc(100vw - 24px);max-height:70vh;box-shadow:var(--shadow-2);padding:12px;position:absolute;top:calc(100% + 8px);right:0;overflow-y:auto}.sg-app-launcher-grid{grid-template-columns:repeat(3,minmax(0,1fr));gap:4px;margin:0;padding:0;list-style:none;display:grid}.sg-app-launcher-app{border-radius:var(--radius);color:inherit;flex-direction:column;align-items:center;gap:6px;padding:12px 4px;text-decoration:none;display:flex}.sg-app-launcher-app:hover,.sg-app-launcher-app:focus-visible{background:var(--primary-hover-bg)}.sg-app-launcher-app.current{background:var(--accent-soft)}.sg-app-launcher-tile{border-radius:var(--radius);background:var(--accent);color:#fff;justify-content:center;align-items:center;width:40px;height:40px;font-size:18px;font-weight:600;display:flex}.sg-app-launcher-name{text-overflow:ellipsis;white-space:nowrap;max-width:100%;font-size:13px;overflow:hidden}.sg-app-launcher-message{color:var(--ink-muted);margin:0;padding:8px;font-size:13px}.sg-authenticator-button{font-size:.9rem;font-family:var(--font-family);border:1px solid var(--primary-border);border-radius:var(--radius);background:var(--primary-bg);color:#333;cursor:pointer;padding:.4rem 1rem;transition:background .15s,border-color .15s}.sg-authenticator-button:hover{background:var(--primary-hover-bg);border-color:var(--ink-muted)}.modal-overlay{background:var(--modal-overlay);z-index:1000;justify-content:center;align-items:center;width:100vw;height:100vh;animation:.25s ease-out sg-modal-overlay-fade-in;display:flex;position:fixed;top:0;left:0}.modal-overlay.modal-overlay-closing{animation:.22s ease-in forwards sg-modal-overlay-fade-out}.modal-content{--drag-x:0px;--drag-y:0px;background:var(--modal-bg);border-radius:var(--primary-radius);font-size:var(--primary-font);min-width:320px;max-width:calc(100vw - 40px);max-height:90vh;transform:translate(var(--drag-x), var(--drag-y));flex-direction:column;animation:.3s ease-out sg-modal-slide-in;display:flex;overflow:hidden;box-shadow:0 2px 16px #00000026}.modal-content.modal-content-closing{animation:.22s ease-in forwards sg-modal-slide-out}@keyframes sg-modal-overlay-fade-in{0%{opacity:0}to{opacity:1}}@keyframes sg-modal-overlay-fade-out{0%{opacity:1}to{opacity:0}}@keyframes sg-modal-slide-in{0%{transform:translate(var(--drag-x), calc(var(--drag-y) - 24px)) scale(.97);opacity:0}to{transform:translate(var(--drag-x), var(--drag-y)) scale(1);opacity:1}}@keyframes sg-modal-slide-out{0%{transform:translate(var(--drag-x), var(--drag-y)) scale(1);opacity:1}to{transform:translate(var(--drag-x), calc(var(--drag-y) - 24px)) scale(.97);opacity:0}}.modal-header{background:var(--primary-bg);border-top-left-radius:var(--primary-radius);border-top-right-radius:var(--primary-radius);cursor:grab;touch-action:none;flex:none;align-items:center;gap:8px;padding:16px;display:flex}.modal-header-dragging{cursor:grabbing;-webkit-user-select:none;user-select:none}.modal-icon{color:var(--modal-title-color);display:inline-flex}.modal-title{color:var(--modal-title-color);font-family:var(--font-family);font-size:var(--primary-font);flex:1;margin:0}.modal-close{cursor:pointer;color:var(--modal-title-color);background:0 0;border:none;padding:4px 8px;font-size:20px;line-height:1}.modal-close:disabled{cursor:default;opacity:.6}.modal-children{font-family:var(--font-family);padding:16px;overflow-y:auto}.modal-footer{border-top:1px solid var(--primary-border);flex-wrap:wrap;flex:none;justify-content:flex-end;gap:8px;padding:12px 16px;display:flex}.input-label{font-weight:500;font-family:var(--font-family);font-size:var(--primary-font);margin-bottom:4px;display:block}.input-field--invalid{background-color:#ffe5e5;border-color:#c00}.input-wrapper{margin-bottom:16px}.input-label{font-weight:500;font-size:var(--primary-font);margin-bottom:4px;display:block}.input-field{box-sizing:border-box;border-radius:var(--radius);width:100%;font-size:var(--primary-font);border-style:solid;border-width:1px;padding:8px}.login-modal-form{font-family:var(--font-family);font-size:var(--primary-font);flex-direction:column;gap:16px;display:flex}.header.quadrato-header{z-index:999}.quadrato-header-auth{align-items:center;gap:12px;display:flex}.quadrato-header-username{font-size:var(--font-size);color:#333;transition:color .2s}.quadrato-header-username:hover{color:var(--accent)}form{font-family:var(--font-family)}.set-password-modal-form{font-family:var(--font-family);font-size:var(--primary-font);flex-direction:column;gap:16px;display:flex}.set-password-modal-error{color:#d32f2f;font-size:var(--primary-font);margin:0}.sg-color-picker{font-family:var(--font-family);position:relative}.sg-color-picker-toggle{border-radius:var(--input-radius);border:1px solid var(--input-border);background:var(--input-bg);width:100%;color:inherit;cursor:pointer;justify-content:space-between;align-items:center;gap:8px;padding:6px 8px;font-family:inherit;font-size:13px;display:flex}.sg-color-picker-toggle-label{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.sg-color-picker-swatch{border:1px solid #00000026;border-radius:4px;flex:none;width:18px;height:18px}.sg-color-picker-popover{z-index:30;background:var(--input-bg);border:1px solid var(--input-border);border-radius:var(--input-radius);box-shadow:var(--shadow-1);width:170px;padding:10px;position:absolute;top:calc(100% + 4px);left:0}.sg-color-picker-grid{grid-template-columns:repeat(6,1fr);gap:6px;display:grid}.sg-color-picker-swatch-button{cursor:pointer;border:1px solid #00000026;border-radius:4px;width:20px;height:20px;padding:0}.sg-color-picker-swatch-button.active{border:2px solid var(--accent)}.sg-color-picker-custom{border-top:1px solid var(--input-border);color:var(--ink-muted);cursor:pointer;justify-content:space-between;align-items:center;gap:8px;margin-top:8px;padding-top:8px;font-size:11px;display:flex}.sg-color-picker-custom input[type=color]{cursor:pointer;border:none;width:26px;height:20px;padding:0}.sg-font-picker{font-family:var(--font-family);position:relative}.sg-font-picker-toggle{border-radius:var(--input-radius);border:1px solid var(--input-border);background:var(--input-bg);width:100%;color:inherit;cursor:pointer;justify-content:space-between;align-items:center;gap:8px;padding:6px 8px;font-size:13px;display:flex}.sg-font-picker-toggle-label{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.sg-font-picker-toggle-caret{opacity:.5;flex:none;font-size:10px}.sg-font-picker-list{background:var(--input-bg);border:1px solid var(--input-border);border-radius:var(--input-radius);max-height:260px;box-shadow:var(--shadow-1);z-index:30;margin:0;padding:4px 0;list-style:none;position:absolute;top:calc(100% + 4px);left:0;right:0;overflow-y:auto}.sg-font-picker-option{text-align:left;width:100%;color:inherit;cursor:pointer;background:0 0;border:none;padding:8px 10px;font-size:15px;display:block}.sg-font-picker-option.active{background:var(--accent-soft)}:root{--unit:3px;--primary-bg:#f5f5f5;--primary-border:#ccc;--radius:calc(var(--unit) * 2);--primary-radius:var(--radius);--primary-font:var(--font-size);--primary-hover-bg:#e0e0e0;--modal-bg:#fff;--modal-overlay:#0000004d;--modal-title-color:#222;--input-bg:#fff;--input-border:#ccc;--input-radius:var(--radius);--input-font:1rem;--font-size:14px;--font-family:Arial, sans-serif;--font-size-h1:calc(var(--font-size) * 1.5);--button-bg:#6f9cf7;--button-bg-hover:#5480e6;--button-color:#fff;--button-radius:999px;--button-shadow:0 1px 2px #5480e61f, 0 1px 3px #5480e61a;--button-ease-standard:cubic-bezier(.4, 0, .2, 1);--button-ease-bounce:cubic-bezier(.34, 1.56, .64, 1);--accent:#3d5fc4;--accent-strong:#2e4aa0;--accent-soft:#e2e7f8;--ink-muted:#647089;--shadow-1:0 1px 2px #0f172a14, 0 1px 3px #0f172a0f;--shadow-2:0 4px 12px #0f172a1f}.theme-dark{--primary-bg:#222;--primary-border:#444;--primary-font:1rem;--font-family:"Inter", Arial, sans-serif;--primary-hover-bg:#333;--modal-bg:#222;--modal-title-color:#fff;--input-bg:#333;--input-border:#555;--input-font:1rem;--button-bg:#6f9cf7;--button-bg-hover:#86aefc;--button-color:#fff;--accent:#6f9cf7;--accent-strong:#86aefc;--accent-soft:#6f9cf72e;--ink-muted:#9aa3b5;--shadow-1:0 1px 2px #0000004d, 0 1px 3px #0000003d;--shadow-2:0 4px 12px #0006}.sg-toggle{cursor:pointer;-webkit-user-select:none;user-select:none;font-family:var(--font-family);align-items:center;gap:6px;display:flex}.sg-toggle-input{opacity:0;width:1px;height:1px;position:absolute}.sg-toggle-track{background:var(--input-border);border-radius:999px;flex:none;width:34px;height:20px;transition:background .15s cubic-bezier(.4,0,.2,1);position:relative}.sg-toggle-input:checked+.sg-toggle-track{background:var(--accent)}.sg-toggle-thumb{background:var(--input-bg);width:16px;height:16px;box-shadow:var(--shadow-1);border-radius:50%;transition:left .15s cubic-bezier(.4,0,.2,1);position:absolute;top:2px;left:2px}.sg-toggle-input:checked+.sg-toggle-track .sg-toggle-thumb{left:16px}.sg-toggle-input:focus-visible+.sg-toggle-track{outline:2px solid var(--accent-strong);outline-offset:2px}.sg-toggle-label{color:var(--ink-muted);white-space:nowrap;font-size:13px}
2
2
  /*$vite$:1*/
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sensorario/sg-components",
3
- "version": "0.0.101",
3
+ "version": "0.0.102",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "scripts": {