lib-pixelbuild 0.2.2 → 0.3.1

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.
Files changed (72) hide show
  1. package/dist/builders/PageBuilder.js +42 -29
  2. package/dist/components/ButtonsComponent.js +6 -5
  3. package/dist/components/CardComponent.js +13 -7
  4. package/dist/components/FormComponent.js +3 -2
  5. package/dist/components/IconComponent.d.ts +5 -0
  6. package/dist/components/IconComponent.js +12 -0
  7. package/dist/components/ImageComponent.js +4 -3
  8. package/dist/components/ListComponent.js +1 -2
  9. package/dist/components/LoadingComponent.js +2 -2
  10. package/dist/components/MapComponent.js +10 -11
  11. package/dist/components/SliderComponent.d.ts +1 -1
  12. package/dist/components/SliderComponent.js +8 -10
  13. package/dist/components/SocialIconsComponent.js +3 -4
  14. package/dist/components/TextComponent.js +3 -2
  15. package/dist/components/VideoComponent.d.ts +4 -0
  16. package/dist/components/VideoComponent.js +34 -0
  17. package/dist/constants/ComponentEnum.d.ts +1 -0
  18. package/dist/constants/ComponentEnum.js +1 -0
  19. package/dist/designSystem/baseCss.d.ts +8 -0
  20. package/dist/designSystem/baseCss.js +406 -0
  21. package/dist/designSystem/buildSiteCss.d.ts +8 -0
  22. package/dist/designSystem/buildSiteCss.js +11 -0
  23. package/dist/designSystem/index.d.ts +6 -0
  24. package/dist/designSystem/index.js +5 -0
  25. package/dist/designSystem/theme.d.ts +9 -0
  26. package/dist/designSystem/theme.js +11 -0
  27. package/dist/designSystem/themeVars.d.ts +8 -0
  28. package/dist/designSystem/themeVars.js +9 -0
  29. package/dist/designSystem/tokens.d.ts +82 -0
  30. package/dist/designSystem/tokens.js +144 -0
  31. package/dist/elements/AlertElement.js +4 -4
  32. package/dist/elements/ButtonElement.js +5 -3
  33. package/dist/elements/ElementColWrapper.js +2 -2
  34. package/dist/elements/IconMap.js +2 -2
  35. package/dist/elements/InputElement.js +10 -9
  36. package/dist/elements/TextElement.js +4 -0
  37. package/dist/factories/ComponentFactory.d.ts +2 -1
  38. package/dist/factories/ComponentFactory.js +28 -11
  39. package/dist/index.d.ts +16 -3
  40. package/dist/index.js +14 -1
  41. package/dist/layouts/Footer.js +16 -5
  42. package/dist/layouts/Header.js +20 -10
  43. package/dist/layouts/SiteLayout.js +3 -2
  44. package/dist/renderers/BlockRenderer.d.ts +8 -0
  45. package/dist/renderers/BlockRenderer.js +68 -0
  46. package/dist/types/{SectionColumnType.d.ts → BlockType.d.ts} +2 -6
  47. package/dist/types/ComponentType.d.ts +3 -0
  48. package/dist/types/PageType.d.ts +2 -2
  49. package/dist/types/WebsiteType.d.ts +5 -0
  50. package/dist/ui/PbAlert.d.ts +10 -0
  51. package/dist/ui/PbAlert.js +8 -0
  52. package/dist/ui/PbButton.d.ts +20 -0
  53. package/dist/ui/PbButton.js +20 -0
  54. package/dist/ui/PbCol.d.ts +14 -0
  55. package/dist/ui/PbCol.js +43 -0
  56. package/dist/ui/PbContainer.d.ts +7 -0
  57. package/dist/ui/PbContainer.js +17 -0
  58. package/dist/ui/PbRow.d.ts +7 -0
  59. package/dist/ui/PbRow.js +17 -0
  60. package/dist/ui/PbSpinner.d.ts +3 -0
  61. package/dist/ui/PbSpinner.js +5 -0
  62. package/dist/ui/index.d.ts +6 -0
  63. package/dist/ui/index.js +6 -0
  64. package/dist/utils/imageCustomization.js +1 -3
  65. package/dist/utils/responsiveStyles.d.ts +2 -2
  66. package/dist/utils/responsiveStyles.js +10 -19
  67. package/package.json +1 -6
  68. package/dist/renderers/SectionRenderer.d.ts +0 -6
  69. package/dist/renderers/SectionRenderer.js +0 -88
  70. package/dist/types/SectionType.d.ts +0 -10
  71. package/dist/types/SectionType.js +0 -1
  72. /package/dist/types/{SectionColumnType.js → BlockType.js} +0 -0
@@ -1,12 +1,12 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Suspense, memo, useMemo } from 'react';
3
3
  import { Helmet } from 'react-helmet-async';
4
- import { SectionRenderer } from '../renderers/SectionRenderer.js';
4
+ import { BlockRenderer } from '../renderers/BlockRenderer.js';
5
5
  import { buildResponsiveCssForStyles } from '../utils/responsiveStyles.js';
6
6
  import { buildFontFamily } from '../utils/fonts.js';
7
7
  function mergeStyles(websiteStyles, pageStyles) {
8
- const merged = Object.assign({}, websiteStyles);
9
- for (const key of Object.keys(pageStyles)) {
8
+ const merged = Object.assign({}, (websiteStyles || {}));
9
+ for (const key of Object.keys(pageStyles || {})) {
10
10
  const val = pageStyles[key];
11
11
  if (val !== '' && val !== null && val !== undefined) {
12
12
  ;
@@ -21,32 +21,45 @@ function toCssValue(val) {
21
21
  return undefined;
22
22
  }
23
23
  const PageBuilder = memo(function PageBuilder({ website, page, editionMode }) {
24
+ var _a, _b, _c, _d, _e;
24
25
  const mergedStyles = useMemo(() => mergeStyles(website.styles, page.styles), [website.styles, page.styles]);
25
- const pageStyle = useMemo(() => ({
26
- backgroundColor: toCssValue(mergedStyles.backgroundColor),
27
- color: toCssValue(mergedStyles.color),
28
- backgroundImage: mergedStyles.backgroundGradientColorStart
29
- ? `linear-gradient(${mergedStyles.backgroundGradientColorStart}, ${mergedStyles.backgroundGradientColorEnd}), url(${mergedStyles.backgroundImage})`
30
- : mergedStyles.backgroundImage
31
- ? `url(${mergedStyles.backgroundImage})`
32
- : undefined,
33
- backgroundSize: toCssValue(mergedStyles.backgroundSize),
34
- backgroundPosition: toCssValue(mergedStyles.backgroundPosition),
35
- width: toCssValue(mergedStyles.width),
36
- height: toCssValue(mergedStyles.height),
37
- fontFamily: buildFontFamily(mergedStyles.fontFamily),
38
- fontSize: toCssValue(mergedStyles.fontSize),
39
- fontWeight: toCssValue(mergedStyles.fontWeight),
40
- textAlign: mergedStyles.textAlign,
41
- paddingTop: toCssValue(mergedStyles.paddingTop),
42
- paddingBottom: toCssValue(mergedStyles.paddingBottom),
43
- paddingLeft: toCssValue(mergedStyles.paddingLeft),
44
- paddingRight: toCssValue(mergedStyles.paddingRight),
45
- marginTop: toCssValue(mergedStyles.marginTop),
46
- marginBottom: toCssValue(mergedStyles.marginBottom),
47
- borderRadius: toCssValue(mergedStyles.borderRadius),
48
- minHeight: '100vh'
49
- }), [mergedStyles]);
50
- return (_jsxs(Suspense, { fallback: _jsx("div", { children: website.properties.loadingMessage }), children: [!editionMode && (_jsxs(Helmet, { children: [_jsx("title", { children: page.title }), _jsx("meta", { name: "description", content: page.title }), _jsx("meta", { property: "og:title", content: page.title }), _jsx("meta", { property: "og:description", content: page.title }), _jsx("meta", { property: "og:image", content: page.title })] })), _jsxs("div", { style: pageStyle, "data-pb-page": true, children: [_jsx("style", { children: buildResponsiveCssForStyles('[data-pb-page]', page.styles) }), _jsx(SectionRenderer, { sections: page.sections, editionMode: editionMode }), page.sections.length === 0 && editionMode && (_jsx("div", { style: { padding: '40px', textAlign: 'center', color: '#94a3b8' }, children: "No sections configured. Use the layout editor to add content." }))] })] }));
26
+ const designSystem = website.designSystem;
27
+ const pageStyle = useMemo(() => {
28
+ var _a, _b, _c, _d, _e, _f, _g;
29
+ return ({
30
+ backgroundColor: (_b = toCssValue((_a = designSystem === null || designSystem === void 0 ? void 0 : designSystem.colors) === null || _a === void 0 ? void 0 : _a.background)) !== null && _b !== void 0 ? _b : toCssValue(mergedStyles.backgroundColor),
31
+ color: (_d = toCssValue((_c = designSystem === null || designSystem === void 0 ? void 0 : designSystem.colors) === null || _c === void 0 ? void 0 : _c.text)) !== null && _d !== void 0 ? _d : toCssValue(mergedStyles.color),
32
+ backgroundImage: mergedStyles.backgroundGradientColorStart
33
+ ? `linear-gradient(${mergedStyles.backgroundGradientColorStart}, ${mergedStyles.backgroundGradientColorEnd}), url(${mergedStyles.backgroundImage})`
34
+ : mergedStyles.backgroundImage
35
+ ? `url(${mergedStyles.backgroundImage})`
36
+ : undefined,
37
+ backgroundSize: toCssValue(mergedStyles.backgroundSize),
38
+ backgroundPosition: toCssValue(mergedStyles.backgroundPosition),
39
+ width: toCssValue(mergedStyles.width),
40
+ height: toCssValue(mergedStyles.height),
41
+ fontFamily: toCssValue((_e = designSystem === null || designSystem === void 0 ? void 0 : designSystem.typography) === null || _e === void 0 ? void 0 : _e.fontFamily)
42
+ ? buildFontFamily(designSystem.typography.fontFamily)
43
+ : buildFontFamily(mergedStyles.fontFamily),
44
+ fontSize: (_g = toCssValue((_f = designSystem === null || designSystem === void 0 ? void 0 : designSystem.typography) === null || _f === void 0 ? void 0 : _f.fontSizeBase)) !== null && _g !== void 0 ? _g : toCssValue(mergedStyles.fontSize),
45
+ fontWeight: toCssValue(mergedStyles.fontWeight),
46
+ textAlign: mergedStyles.textAlign,
47
+ paddingTop: toCssValue(mergedStyles.paddingTop),
48
+ paddingBottom: toCssValue(mergedStyles.paddingBottom),
49
+ paddingLeft: toCssValue(mergedStyles.paddingLeft),
50
+ paddingRight: toCssValue(mergedStyles.paddingRight),
51
+ marginTop: toCssValue(mergedStyles.marginTop),
52
+ marginBottom: toCssValue(mergedStyles.marginBottom),
53
+ borderRadius: toCssValue(mergedStyles.borderRadius),
54
+ minHeight: '100vh'
55
+ });
56
+ }, [
57
+ (_a = designSystem === null || designSystem === void 0 ? void 0 : designSystem.colors) === null || _a === void 0 ? void 0 : _a.background,
58
+ (_b = designSystem === null || designSystem === void 0 ? void 0 : designSystem.colors) === null || _b === void 0 ? void 0 : _b.text,
59
+ (_c = designSystem === null || designSystem === void 0 ? void 0 : designSystem.typography) === null || _c === void 0 ? void 0 : _c.fontFamily,
60
+ (_d = designSystem === null || designSystem === void 0 ? void 0 : designSystem.typography) === null || _d === void 0 ? void 0 : _d.fontSizeBase,
61
+ mergedStyles
62
+ ]);
63
+ return (_jsxs(Suspense, { fallback: _jsx("div", { children: ((_e = website.properties) === null || _e === void 0 ? void 0 : _e.loadingMessage) || 'Carregando...' }), children: [!editionMode && (_jsxs(Helmet, { children: [_jsx("title", { children: page.title }), _jsx("meta", { name: "description", content: page.title }), _jsx("meta", { property: "og:title", content: page.title }), _jsx("meta", { property: "og:description", content: page.title }), _jsx("meta", { property: "og:image", content: page.title })] })), _jsxs("div", { style: pageStyle, "data-pb-page": true, children: [_jsx("style", { children: buildResponsiveCssForStyles('[data-pb-page]', page.styles) }), _jsx(BlockRenderer, { blocks: page.blocks, editionMode: editionMode, componentDefaults: website.componentDefaults }), (page.blocks || []).length === 0 && editionMode && (_jsx("div", { style: { padding: '40px', textAlign: 'center', color: '#94a3b8' }, children: "Nenhum conte\u00FAdo adicionado." }))] })] }));
51
64
  });
52
65
  export { PageBuilder };
@@ -1,12 +1,13 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { memo, useMemo } from 'react';
3
- import { Button, Container } from 'react-bootstrap';
3
+ import { PbContainer } from '../ui/PbContainer.js';
4
+ import { PbButton } from '../ui/PbButton.js';
4
5
  import { orderBySort } from '../utils/orderBySort.js';
5
6
  import { getString, getNumber, getBoolean } from '../utils/propertyUtils.js';
6
7
  const ALIGN_JUSTIFY = {
7
8
  left: 'flex-start',
8
9
  center: 'center',
9
- right: 'flex-end',
10
+ right: 'flex-end'
10
11
  };
11
12
  const ButtonsComponent = memo(function ButtonsComponent({ component }) {
12
13
  var _a, _b;
@@ -20,13 +21,13 @@ const ButtonsComponent = memo(function ButtonsComponent({ component }) {
20
21
  display: 'flex',
21
22
  flexDirection: isColumn ? 'column' : 'row',
22
23
  flexWrap: 'wrap',
23
- gap: `${gap}px`,
24
+ gap: `${gap}px`
24
25
  };
25
26
  if (isColumn)
26
27
  containerStyle.alignItems = align;
27
28
  else
28
29
  containerStyle.justifyContent = align;
29
- return (_jsx(Container, { "data-pb-component": component.id, style: component.styles, children: _jsx("div", { style: containerStyle, children: elements.map((element) => {
30
+ return (_jsx(PbContainer, { "data-pb-component": component.id, style: component.styles, children: _jsx("div", { style: containerStyle, children: elements.map((element) => {
30
31
  const props = element.properties || {};
31
32
  const href = getString(props, 'path') || getString(props, 'href');
32
33
  const text = getString(props, 'text') || getString(props, 'title');
@@ -38,7 +39,7 @@ const ButtonsComponent = memo(function ButtonsComponent({ component }) {
38
39
  else
39
40
  style.flex = '1 1 0%';
40
41
  }
41
- return (_jsx(Button, { "data-pb-element": element.id, as: href ? 'a' : 'button', variant: getString(props, 'variant', 'primary'), size: size === 'sm' || size === 'lg' ? size : undefined, href: href || undefined, target: href ? getString(props, 'target', '_self') : undefined, rel: href ? 'noopener noreferrer' : undefined, style: style, children: text }, element.id));
42
+ return (_jsx(PbButton, { "data-pb-element": element.id, href: href || undefined, variant: getString(props, 'variant', 'primary'), size: size === 'sm' || size === 'lg' ? size : undefined, target: href ? getString(props, 'target', '_self') : undefined, style: style, children: text }, element.id));
42
43
  }) }) }));
43
44
  });
44
45
  export { ButtonsComponent };
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { memo, useMemo } from 'react';
3
- import { Row, Container } from 'react-bootstrap';
3
+ import { PbContainer } from '../ui/PbContainer.js';
4
+ import { PbRow } from '../ui/PbRow.js';
4
5
  import { ElementFactory } from '../factories/ElementFactory.js';
5
6
  import { orderBySort } from '../utils/orderBySort.js';
6
7
  const elementFactory = new ElementFactory();
@@ -44,7 +45,8 @@ const CardComponent = memo(function CardComponent({ component }) {
44
45
  cardTitleColor: properties === null || properties === void 0 ? void 0 : properties.cardTitleColor,
45
46
  cardTitleSize: properties === null || properties === void 0 ? void 0 : properties.cardTitleSize,
46
47
  cardTextColor: properties === null || properties === void 0 ? void 0 : properties.cardTextColor,
47
- cardTextSize: properties === null || properties === void 0 ? void 0 : properties.cardTextSize
48
+ cardTextSize: properties === null || properties === void 0 ? void 0 : properties.cardTextSize,
49
+ cardElementGap: properties === null || properties === void 0 ? void 0 : properties.cardElementGap
48
50
  }), [
49
51
  properties === null || properties === void 0 ? void 0 : properties.cardElement1,
50
52
  properties === null || properties === void 0 ? void 0 : properties.cardElement2,
@@ -55,7 +57,8 @@ const CardComponent = memo(function CardComponent({ component }) {
55
57
  properties === null || properties === void 0 ? void 0 : properties.cardTitleColor,
56
58
  properties === null || properties === void 0 ? void 0 : properties.cardTitleSize,
57
59
  properties === null || properties === void 0 ? void 0 : properties.cardTextColor,
58
- properties === null || properties === void 0 ? void 0 : properties.cardTextSize
60
+ properties === null || properties === void 0 ? void 0 : properties.cardTextSize,
61
+ properties === null || properties === void 0 ? void 0 : properties.cardElementGap
59
62
  ]);
60
63
  const orderedElements = useMemo(() => {
61
64
  const cardOrder = [
@@ -79,18 +82,21 @@ const CardComponent = memo(function CardComponent({ component }) {
79
82
  ]);
80
83
  const elements = useMemo(() => orderedElements.map((el) => applyCardStyles(el, cardProps)), [orderedElements, cardProps]);
81
84
  const layout = String((properties === null || properties === void 0 ? void 0 : properties.cardLayout) || 'stacked');
85
+ const rawGap = cardProps.cardElementGap;
86
+ const elementGap = rawGap === '' || rawGap == null ? '0' : String(rawGap);
87
+ const rowGapStyle = { gap: elementGap };
82
88
  if (layout === 'icon-left' || layout === 'icon-right') {
83
89
  const icon = elements.find((element) => element.elementType === 'icon');
84
90
  const others = elements.filter((element) => element !== icon);
85
91
  const iconBox = icon ? _jsx("div", { style: { flex: '0 0 auto' }, children: elementFactory.build(stripWidth(icon)) }) : null;
86
- const contentBox = _jsx("div", { style: { flex: '1 1 220px', minWidth: 0 }, children: others.map((element) => elementFactory.build(stripWidth(element))) });
87
- return (_jsx(Container, { "data-pb-component": component.id, style: component.styles, children: _jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: '1rem', flexWrap: 'wrap' }, children: [layout === 'icon-left' ? iconBox : contentBox, layout === 'icon-left' ? contentBox : iconBox] }) }));
92
+ const contentBox = (_jsx("div", { style: { flex: '1 1 220px', minWidth: 0 }, children: others.map((element) => elementFactory.build(stripWidth(element))) }));
93
+ return (_jsx(PbContainer, { "data-pb-component": component.id, style: component.styles, children: _jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: elementGap, flexWrap: 'wrap' }, children: [layout === 'icon-left' ? iconBox : contentBox, layout === 'icon-left' ? contentBox : iconBox] }) }));
88
94
  }
89
95
  if (layout === 'icon-top') {
90
96
  const icon = elements.find((element) => element.elementType === 'icon');
91
97
  const others = elements.filter((element) => element !== icon);
92
- return (_jsx(Container, { "data-pb-component": component.id, style: component.styles, children: _jsxs("div", { style: { textAlign: 'center' }, children: [icon && _jsx("div", { style: { display: 'inline-block' }, children: elementFactory.build(centerStyles(icon)) }), _jsx("div", { children: others.map((element) => elementFactory.build(centerStyles(element))) })] }) }));
98
+ return (_jsx(PbContainer, { "data-pb-component": component.id, style: component.styles, children: _jsxs("div", { style: { textAlign: 'center', display: 'flex', flexDirection: 'column', gap: elementGap }, children: [icon && _jsx("div", { style: { display: 'inline-block' }, children: elementFactory.build(centerStyles(icon)) }), _jsx("div", { style: { display: 'flex', flexDirection: 'column', gap: elementGap }, children: others.map((element) => elementFactory.build(centerStyles(element))) })] }) }));
93
99
  }
94
- return (_jsx(Container, { style: component.styles, children: _jsx(Row, { id: "element-row", children: elements.map((element) => elementFactory.build(element)) }) }));
100
+ return (_jsx(PbContainer, { style: component.styles, children: _jsx(PbRow, { id: "element-row", style: rowGapStyle, children: elements.map((element) => elementFactory.build(element)) }) }));
95
101
  });
96
102
  export { CardComponent };
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { memo, useEffect, useMemo } from 'react';
3
- import { Form, Row, Container } from 'react-bootstrap';
3
+ import { PbContainer } from '../ui/PbContainer.js';
4
+ import { PbRow } from '../ui/PbRow.js';
4
5
  import { UseFormStore } from '../stores/UseFormStore.js';
5
6
  import { ElementFactory } from '../factories/ElementFactory.js';
6
7
  import { orderBySort } from '../utils/orderBySort.js';
@@ -18,6 +19,6 @@ const FormComponent = memo(function FormComponent({ component }) {
18
19
  const handleSubmit = (event) => {
19
20
  event.preventDefault();
20
21
  };
21
- return (_jsx(Container, { "data-pb-component": component.id, style: component.styles, children: _jsx(Form, { onSubmit: handleSubmit, children: _jsx(Row, { children: elements.map((element) => elementFactory.build(element, component.id)) }) }) }));
22
+ return (_jsx(PbContainer, { "data-pb-component": component.id, style: component.styles, children: _jsx("form", { onSubmit: handleSubmit, noValidate: true, children: _jsx(PbRow, { children: elements.map((element) => elementFactory.build(element, component.id)) }) }) }));
22
23
  });
23
24
  export { FormComponent };
@@ -0,0 +1,5 @@
1
+ import type { ComponentType } from '../types/ComponentType.js';
2
+ declare const IconComponent: import("react").NamedExoticComponent<{
3
+ readonly component: ComponentType;
4
+ }>;
5
+ export { IconComponent };
@@ -0,0 +1,12 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { memo, useMemo } from 'react';
3
+ import { PbContainer } from '../ui/PbContainer.js';
4
+ import { PbRow } from '../ui/PbRow.js';
5
+ import { ElementFactory } from '../factories/ElementFactory.js';
6
+ import { orderBySort } from '../utils/orderBySort.js';
7
+ const elementFactory = new ElementFactory();
8
+ const IconComponent = memo(function IconComponent({ component }) {
9
+ const elements = useMemo(() => orderBySort(component.elements), [component.elements]);
10
+ return (_jsx(PbContainer, { "data-pb-component": component.id, style: component.styles, children: _jsx(PbRow, { id: "element-row", style: { justifyContent: 'center' }, children: elements.map((element) => elementFactory.build(element)) }) }));
11
+ });
12
+ export { IconComponent };
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { memo, useMemo } from 'react';
3
- import { Row, Container } from 'react-bootstrap';
3
+ import { PbContainer } from '../ui/PbContainer.js';
4
+ import { PbRow } from '../ui/PbRow.js';
4
5
  import { ElementFactory } from '../factories/ElementFactory.js';
5
6
  import { orderBySort } from '../utils/orderBySort.js';
6
7
  import { resolveImageElement } from '../utils/imageCustomization.js';
@@ -10,8 +11,8 @@ const ImageComponent = memo(function ImageComponent({ component }) {
10
11
  const fullBleed = getBoolean(component.properties, 'fullBleed', false);
11
12
  const elements = useMemo(() => orderBySort(component.elements).map((element) => resolveImageElement(component, element)), [component.elements, component.properties]);
12
13
  if (fullBleed) {
13
- return (_jsx("div", { "data-pb-component": component.id, style: Object.assign(Object.assign({}, component.styles), { width: 'calc(100% + var(--bs-gutter-x, 1.5rem))', marginLeft: 'calc(var(--bs-gutter-x, 1.5rem) * -0.5)', marginRight: 'calc(var(--bs-gutter-x, 1.5rem) * -0.5)' }), children: elements.map((element) => elementFactory.build(Object.assign(Object.assign({}, element), { fullBleed: true }))) }));
14
+ return (_jsx("div", { "data-pb-component": component.id, style: Object.assign(Object.assign({}, component.styles), { width: 'calc(100% + var(--pb-gutter, 1.5rem))', marginLeft: 'calc(var(--pb-gutter, 1.5rem) * -0.5)', marginRight: 'calc(var(--pb-gutter, 1.5rem) * -0.5)' }), children: elements.map((element) => elementFactory.build(Object.assign(Object.assign({}, element), { fullBleed: true }))) }));
14
15
  }
15
- return (_jsx(Container, { "data-pb-component": component.id, style: component.styles, children: _jsx(Row, { id: "element-row", children: elements.map((element) => elementFactory.build(element)) }) }));
16
+ return (_jsx(PbContainer, { "data-pb-component": component.id, style: component.styles, children: _jsx(PbRow, { id: "element-row", children: elements.map((element) => elementFactory.build(element)) }) }));
16
17
  });
17
18
  export { ImageComponent };
@@ -1,6 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { memo, useMemo } from 'react';
3
- import { Col } from 'react-bootstrap';
4
3
  import { ElementFactory } from '../factories/ElementFactory.js';
5
4
  import { ElementTypeEnum } from '../constants/ElementEnum.js';
6
5
  import { orderBySort } from '../utils/orderBySort.js';
@@ -28,6 +27,6 @@ const ListComponent = memo(function ListComponent({ component }) {
28
27
  }
29
28
  return result;
30
29
  }, [elements]);
31
- return (_jsx(Col, { "data-pb-component": component.id, style: component.styles, children: _jsx("ul", { style: { listStyle: 'none' }, children: items.map(({ icon, text, id }) => (_jsxs("li", { style: { display: 'flex', alignItems: 'center', justifyContent: itemAlign, marginBottom: itemGap }, children: [_jsx("span", { children: elementFactory.build(icon) }), _jsx("span", { style: { fontSize: itemFontSize }, children: text ? elementFactory.build(text) : null })] }, id))) }) }));
30
+ return (_jsx("div", { "data-pb-component": component.id, style: component.styles, children: _jsx("ul", { style: { listStyle: 'none', paddingLeft: 0 }, children: items.map(({ icon, text, id }) => (_jsxs("li", { style: { display: 'flex', alignItems: 'center', justifyContent: itemAlign, marginBottom: itemGap }, children: [_jsx("span", { children: elementFactory.build(icon) }), _jsx("span", { style: { fontSize: itemFontSize }, children: text ? elementFactory.build(text) : null })] }, id))) }) }));
32
31
  });
33
32
  export { ListComponent };
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Container, Spinner } from 'react-bootstrap';
2
+ import { PbSpinner } from '../ui/PbSpinner.js';
3
3
  export function LoadingComponent() {
4
- return (_jsxs(Container, { className: "d-flex flex-column align-items-center justify-content-center", style: { minHeight: '100vh' }, children: [_jsx("output", { "aria-busy": "true", children: _jsx(Spinner, { animation: "border" }) }), _jsx("p", { className: "mt-3", children: "LOADING" })] }));
4
+ return (_jsxs("div", { className: "pb-loading", children: [_jsx("output", { "aria-busy": "true", children: _jsx(PbSpinner, {}) }), _jsx("p", { className: "pb-mb-0", children: "LOADING" })] }));
5
5
  }
@@ -1,6 +1,5 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useMemo } from 'react';
3
- import { Row, Col } from 'react-bootstrap';
4
3
  const COORDS_PATTERN = /^-?\d+(\.\d+)?$/;
5
4
  function isValidCoord(value) {
6
5
  if (typeof value !== 'string')
@@ -19,14 +18,14 @@ export function MapComponent({ component }) {
19
18
  }
20
19
  return `https://maps.google.com/maps?q=${encodeURIComponent(`${latStr},${lngStr}`)}&z=${zoom}&output=embed`;
21
20
  }, [lat, lng, zoom]);
22
- return (_jsx(Col, { "data-pb-component": component.id, style: component.styles, children: _jsx(Row, { children: _jsx(Col, { children: src ? (_jsx("iframe", { title: "Localiza\u00E7\u00E3o", src: src, width: "100%", height: height, style: { border: 0, borderRadius: '4px' }, allowFullScreen: true, loading: "lazy", referrerPolicy: "no-referrer-when-downgrade" })) : (_jsx("div", { style: {
23
- width: '100%',
24
- height,
25
- backgroundColor: placeholderBackgroundColor,
26
- display: 'flex',
27
- alignItems: 'center',
28
- justifyContent: 'center',
29
- borderRadius: '4px',
30
- color: placeholderTextColor
31
- }, children: "Map not configured" })) }) }) }));
21
+ return (_jsx("div", { "data-pb-component": component.id, style: component.styles, children: src ? (_jsx("iframe", { title: "Localiza\u00E7\u00E3o", src: src, width: "100%", height: height, style: { border: 0, borderRadius: '4px' }, allowFullScreen: true, loading: "lazy", referrerPolicy: "no-referrer-when-downgrade" })) : (_jsx("div", { style: {
22
+ width: '100%',
23
+ height,
24
+ backgroundColor: placeholderBackgroundColor,
25
+ display: 'flex',
26
+ alignItems: 'center',
27
+ justifyContent: 'center',
28
+ borderRadius: '4px',
29
+ color: placeholderTextColor
30
+ }, children: "Map not configured" })) }));
32
31
  }
@@ -1,5 +1,5 @@
1
1
  import type { ComponentType } from '../types/ComponentType.js';
2
- export declare function SliderComponent({ component, editionMode, }: {
2
+ export declare function SliderComponent({ component, editionMode }: {
3
3
  readonly component: ComponentType;
4
4
  readonly editionMode?: boolean;
5
5
  }): import("react").JSX.Element;
@@ -26,7 +26,7 @@ function resolveChromeColors(properties) {
26
26
  dotBackground: String(properties.dotBackground || 'rgba(0,0,0,0.15)'),
27
27
  dotActiveColor: String(properties.dotActiveColor || '#fff'),
28
28
  dotColor: String(properties.dotColor || '#666'),
29
- dotSize: Number(properties.dotSize) || 28,
29
+ dotSize: Number(properties.dotSize) || 28
30
30
  };
31
31
  }
32
32
  const ARROW_BASE_STYLE = {
@@ -43,12 +43,12 @@ const ARROW_BASE_STYLE = {
43
43
  display: 'flex',
44
44
  alignItems: 'center',
45
45
  justifyContent: 'center',
46
- transition: 'background 0.2s',
46
+ transition: 'background 0.2s'
47
47
  };
48
- function ArrowButton({ side, size, background, color, onClick, }) {
48
+ function ArrowButton({ side, size, background, color, onClick }) {
49
49
  return (_jsx("button", { type: "button", "aria-label": side === 'left' ? 'Slide anterior' : 'Próximo slide', onClick: onClick, style: Object.assign(Object.assign({}, ARROW_BASE_STYLE), { [side]: 8, width: size, height: size, background, color }), children: _jsx("svg", { width: "10", height: "16", viewBox: "0 0 10 16", fill: "none", children: _jsx("path", { d: side === 'left' ? 'M8.5 1L1.5 8L8.5 15' : 'M1.5 1L8.5 8L1.5 15', stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) }));
50
50
  }
51
- function Dots({ count, current, size, activeBackground, background, activeColor, color, onGoTo, }) {
51
+ function Dots({ count, current, size, activeBackground, background, activeColor, color, onGoTo }) {
52
52
  return (_jsx("div", { "aria-label": "Navega\u00E7\u00E3o do slider", style: { display: 'flex', justifyContent: 'center', gap: 6, marginTop: 12 }, children: Array.from({ length: count }).map((_, index) => (_jsx("button", { type: "button", "aria-label": `Ir para o slide ${index + 1}`, "aria-current": current === index ? 'true' : undefined, onClick: () => onGoTo(index), style: {
53
53
  width: size,
54
54
  height: size,
@@ -63,7 +63,7 @@ function Dots({ count, current, size, activeBackground, background, activeColor,
63
63
  display: 'flex',
64
64
  alignItems: 'center',
65
65
  justifyContent: 'center',
66
- transition: 'all 0.2s',
66
+ transition: 'all 0.2s'
67
67
  }, children: index + 1 }, index))) }));
68
68
  }
69
69
  function useSliderWidth(ref) {
@@ -80,7 +80,7 @@ function useSliderWidth(ref) {
80
80
  }, [ref]);
81
81
  return width;
82
82
  }
83
- export function SliderComponent({ component, editionMode = false, }) {
83
+ export function SliderComponent({ component, editionMode = false }) {
84
84
  const properties = component.properties || {};
85
85
  const slides = orderBySort(component.elements);
86
86
  const n = slides.length;
@@ -99,9 +99,7 @@ export function SliderComponent({ component, editionMode = false, }) {
99
99
  const [animate, setAnimate] = useState(false);
100
100
  const [dragging, setDragging] = useState(false);
101
101
  const dragRef = useRef(null);
102
- const currentIndex = loop
103
- ? ((Math.round(index) % n) + n) % n
104
- : Math.min(Math.max(0, Math.round(index)), maxIndex);
102
+ const currentIndex = loop ? ((Math.round(index) % n) + n) % n : Math.min(Math.max(0, Math.round(index)), maxIndex);
105
103
  useEffect(() => {
106
104
  if (editionMode || !resolved.autoplay || n <= 1)
107
105
  return;
@@ -186,6 +184,6 @@ export function SliderComponent({ component, editionMode = false, }) {
186
184
  transition: animate && !dragging ? 'transform 0.3s ease' : 'none',
187
185
  cursor: dragging ? 'grabbing' : n > 1 ? 'grab' : 'default',
188
186
  touchAction: 'pan-y',
189
- userSelect: 'none',
187
+ userSelect: 'none'
190
188
  }, onPointerDown: onPointerDown, onPointerMove: onPointerMove, onPointerUp: endDrag, onPointerCancel: endDrag, onTransitionEnd: handleTransitionEnd, children: trackSlides.map((element, i) => (_jsx("div", { style: { width: slideWidth, flexShrink: 0, overflow: 'hidden' }, children: buildSlide(element, fixedHeight, sharedImageStyles, useSharedImages) }, `${element.id}-${i}`))) }) }), showArrows && (_jsxs(_Fragment, { children: [_jsx(ArrowButton, { side: "left", size: chrome.arrowSize, background: chrome.arrowBackground, color: chrome.arrowColor, onClick: () => goTo(index - 1) }), _jsx(ArrowButton, { side: "right", size: chrome.arrowSize, background: chrome.arrowBackground, color: chrome.arrowColor, onClick: () => goTo(index + 1) })] })), showDots && (_jsx(Dots, { count: n, current: currentIndex, size: chrome.dotSize, activeBackground: chrome.dotActiveBackground, background: chrome.dotBackground, activeColor: chrome.dotActiveColor, color: chrome.dotColor, onGoTo: goToDot }))] }));
191
189
  }
@@ -1,6 +1,5 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { Row, Col } from 'react-bootstrap';
3
- import { FaFacebookF, FaInstagram, FaTiktok, FaWhatsapp, FaYoutube, FaXTwitter, FaLinkedin, FaThreads, FaLink, } from 'react-icons/fa6';
2
+ import { FaFacebookF, FaInstagram, FaTiktok, FaWhatsapp, FaYoutube, FaXTwitter, FaLinkedin, FaThreads, FaLink } from 'react-icons/fa6';
4
3
  const SOCIAL_ICONS = {
5
4
  facebook: FaFacebookF,
6
5
  instagram: FaInstagram,
@@ -12,7 +11,7 @@ const SOCIAL_ICONS = {
12
11
  linkedin: FaLinkedin,
13
12
  threads: FaThreads,
14
13
  linktree: FaLink,
15
- kwai: FaLink,
14
+ kwai: FaLink
16
15
  };
17
16
  export function SocialIconsComponent({ social, color }) {
18
17
  const entries = Object.entries(social || {})
@@ -20,5 +19,5 @@ export function SocialIconsComponent({ social, color }) {
20
19
  .map(([id, value]) => ({ id, url: (value === null || value === void 0 ? void 0 : value.path) || '', Icon: SOCIAL_ICONS[id] || FaLink }));
21
20
  if (entries.length === 0)
22
21
  return null;
23
- return (_jsx(Row, { children: entries.map(({ id, url, Icon }) => (_jsx(Col, { className: "text-center social-icons", style: { color }, children: _jsx("a", { href: url, target: "_blank", rel: "noopener noreferrer", "aria-label": id, children: _jsx(Icon, {}) }) }, id))) }));
22
+ return (_jsx("div", { className: "pb-social-icons", style: { color }, children: entries.map(({ id, url, Icon }) => (_jsx("a", { className: "pb-social-icon", href: url, target: "_blank", rel: "noopener noreferrer", "aria-label": id, children: _jsx(Icon, {}) }, id))) }));
24
23
  }
@@ -1,12 +1,13 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { memo, useMemo } from 'react';
3
- import { Row, Container } from 'react-bootstrap';
3
+ import { PbContainer } from '../ui/PbContainer.js';
4
+ import { PbRow } from '../ui/PbRow.js';
4
5
  import { ElementFactory } from '../factories/ElementFactory.js';
5
6
  import { orderBySort } from '../utils/orderBySort.js';
6
7
  import { resolveImageElement } from '../utils/imageCustomization.js';
7
8
  const elementFactory = new ElementFactory();
8
9
  const TextComponent = memo(function TextComponent({ component }) {
9
10
  const elements = useMemo(() => orderBySort(component.elements).map((element) => resolveImageElement(component, element)), [component.elements, component.properties]);
10
- return (_jsx(Container, { "data-pb-component": component.id, style: component.styles, children: _jsx(Row, { id: "element-row", children: elements.map((element) => elementFactory.build(element)) }) }));
11
+ return (_jsx(PbContainer, { "data-pb-component": component.id, style: component.styles, children: _jsx(PbRow, { id: "element-row", children: elements.map((element) => elementFactory.build(element)) }) }));
11
12
  });
12
13
  export { TextComponent };
@@ -0,0 +1,4 @@
1
+ import type { ComponentType } from '../types/ComponentType.js';
2
+ export declare function VideoComponent({ component }: {
3
+ readonly component: ComponentType;
4
+ }): import("react").JSX.Element;
@@ -0,0 +1,34 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useMemo } from 'react';
3
+ import { getBoolean } from '../utils/propertyUtils.js';
4
+ function toEmbed(src) {
5
+ const value = src.trim();
6
+ if (!value)
7
+ return null;
8
+ const youtube = value.match(/(?:youtube\.com\/(?:watch\?v=|embed\/|shorts\/)|youtu\.be\/)([A-Za-z0-9_-]{6,})/);
9
+ if (youtube)
10
+ return { kind: 'iframe', src: `https://www.youtube.com/embed/${youtube[1]}` };
11
+ const vimeo = value.match(/vimeo\.com\/(?:video\/)?(\d+)/);
12
+ if (vimeo)
13
+ return { kind: 'iframe', src: `https://player.vimeo.com/video/${vimeo[1]}` };
14
+ return { kind: 'native', src: value };
15
+ }
16
+ export function VideoComponent({ component }) {
17
+ const { src = '', height = '400px', placeholderBackgroundColor = '#e0e0e0', placeholderTextColor = '#666' } = component.properties;
18
+ const fullBleed = getBoolean(component.properties, 'fullBleed', false);
19
+ const video = useMemo(() => toEmbed(src), [src]);
20
+ const content = (video === null || video === void 0 ? void 0 : video.kind) === 'iframe' ? (_jsx("iframe", { title: "V\u00EDdeo", src: video.src, width: "100%", height: height, style: { border: 0, borderRadius: '4px' }, allow: "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture", allowFullScreen: true, loading: "lazy" })) : (video === null || video === void 0 ? void 0 : video.kind) === 'native' ? (_jsx("video", { controls: true, src: video.src, style: { width: '100%', height, borderRadius: '4px', display: 'block' } })) : (_jsx("div", { style: {
21
+ width: '100%',
22
+ height,
23
+ backgroundColor: placeholderBackgroundColor,
24
+ display: 'flex',
25
+ alignItems: 'center',
26
+ justifyContent: 'center',
27
+ borderRadius: '4px',
28
+ color: placeholderTextColor
29
+ }, children: "V\u00EDdeo n\u00E3o configurado" }));
30
+ if (fullBleed) {
31
+ return (_jsx("div", { "data-pb-component": component.id, style: Object.assign(Object.assign({}, component.styles), { width: 'calc(100% + var(--pb-gutter, 1.5rem))', marginLeft: 'calc(var(--pb-gutter, 1.5rem) * -0.5)', marginRight: 'calc(var(--pb-gutter, 1.5rem) * -0.5)' }), children: content }));
32
+ }
33
+ return (_jsx("div", { "data-pb-component": component.id, style: component.styles, children: content }));
34
+ }
@@ -14,5 +14,6 @@ export declare const ComponentTypeEnum: {
14
14
  readonly Map: "map";
15
15
  readonly List: "list";
16
16
  readonly Buttons: "buttons";
17
+ readonly Icon: "icon";
17
18
  };
18
19
  export type ComponentTypeSlug = (typeof ComponentTypeEnum)[keyof typeof ComponentTypeEnum];
@@ -14,4 +14,5 @@ export const ComponentTypeEnum = {
14
14
  Map: 'map',
15
15
  List: 'list',
16
16
  Buttons: 'buttons',
17
+ Icon: 'icon'
17
18
  };
@@ -0,0 +1,8 @@
1
+ /**
2
+ * CSS base do site público (sem Bootstrap).
3
+ *
4
+ * Classes utilitárias e de componentes usadas pelo `lib-pixelbuild`. Todos os
5
+ * valores de destaque usam `var(--pb-*)` com fallback, então o design system
6
+ * (Etapa 1) sobrescreve os tokens sem tocar nestes estilos.
7
+ */
8
+ export declare const baseCss = "\n/* \u2500\u2500\u2500 Reset e tipografia base \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pb-root, .pb-root *, .pb-root *::before, .pb-root *::after {\n box-sizing: border-box;\n}\n.pb-root {\n margin: 0;\n font-family: var(--pb-font-family, 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif);\n font-size: var(--pb-font-size-base, 16px);\n line-height: var(--pb-line-height, 1.6);\n color: var(--pb-color-text, #1f2937);\n background-color: var(--pb-color-background, #ffffff);\n -webkit-font-smoothing: antialiased;\n text-rendering: optimizeLegibility;\n}\n.pb-root h1, .pb-root h2, .pb-root h3, .pb-root h4, .pb-root h5, .pb-root h6 {\n margin: 0 0 0.5em;\n font-weight: var(--pb-font-weight-bold, 700);\n line-height: 1.2;\n color: var(--pb-color-heading, #111827);\n}\n.pb-root img {\n max-width: 100%;\n height: auto;\n}\n.pb-root a {\n color: var(--pb-color-primary, #f58220);\n text-decoration: none;\n}\n.pb-root a:hover {\n text-decoration: underline;\n}\n\n/* \u2500\u2500\u2500 Layout: container / grade \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pb-container {\n width: 100%;\n margin-inline: auto;\n padding-inline: var(--pb-gutter, 1.5rem);\n}\n.pb-container-fluid {\n max-width: none !important;\n padding-inline: var(--pb-gutter, 1.5rem);\n}\n@media (min-width: 576px) {\n .pb-container { max-width: 540px; }\n}\n@media (min-width: 768px) {\n .pb-container { max-width: 720px; }\n}\n@media (min-width: 992px) {\n .pb-container { max-width: 960px; }\n}\n@media (min-width: 1200px) {\n .pb-container { max-width: 1140px; }\n}\n@media (min-width: 1400px) {\n .pb-container { max-width: 1320px; }\n}\n\n.pb-row {\n display: grid;\n grid-template-columns: repeat(12, minmax(0, 1fr));\n gap: var(--pb-gutter, 1.5rem);\n}\n.pb-col {\n min-width: 0;\n}\n\n/* \u2500\u2500\u2500 Bot\u00F5es \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pb-button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.5em;\n padding: 0.5em 1.25em;\n font-family: inherit;\n font-size: 1rem;\n font-weight: var(--pb-font-weight-bold, 700);\n line-height: 1.5;\n text-align: center;\n text-decoration: none;\n border: 1px solid transparent;\n border-radius: var(--pb-radius-md, 8px);\n cursor: pointer;\n transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease, box-shadow 0.2s ease;\n}\n.pb-button:hover { text-decoration: none; }\n.pb-button:disabled {\n opacity: 0.55;\n cursor: not-allowed;\n}\n\n.pb-button-primary {\n background-color: var(--pb-color-primary, #f58220);\n border-color: var(--pb-color-primary, #f58220);\n color: #ffffff;\n}\n.pb-button-primary:hover:not(:disabled) {\n background-color: color-mix(in srgb, var(--pb-color-primary, #f58220) 88%, #000);\n border-color: color-mix(in srgb, var(--pb-color-primary, #f58220) 88%, #000);\n}\n.pb-button-secondary {\n background-color: var(--pb-color-secondary, #64748b);\n border-color: var(--pb-color-secondary, #64748b);\n color: #ffffff;\n}\n.pb-button-success {\n background-color: var(--pb-color-success, #16a34a);\n border-color: var(--pb-color-success, #16a34a);\n color: #ffffff;\n}\n.pb-button-danger {\n background-color: var(--pb-color-danger, #dc2626);\n border-color: var(--pb-color-danger, #dc2626);\n color: #ffffff;\n}\n.pb-button-warning {\n background-color: var(--pb-color-warning, #f59e0b);\n border-color: var(--pb-color-warning, #f59e0b);\n color: #1f2937;\n}\n.pb-button-info {\n background-color: var(--pb-color-info, #0ea5e9);\n border-color: var(--pb-color-info, #0ea5e9);\n color: #ffffff;\n}\n.pb-button-light {\n background-color: var(--pb-color-light, #f8fafc);\n border-color: var(--pb-color-border, #e5e7eb);\n color: var(--pb-color-text, #1f2937);\n}\n.pb-button-dark {\n background-color: var(--pb-color-dark, #0f172a);\n border-color: var(--pb-color-dark, #0f172a);\n color: #ffffff;\n}\n.pb-button-outline-primary {\n background-color: transparent;\n border-color: var(--pb-color-primary, #f58220);\n color: var(--pb-color-primary, #f58220);\n}\n.pb-button-outline-primary:hover:not(:disabled) {\n background-color: var(--pb-color-primary, #f58220);\n color: #ffffff;\n}\n.pb-button-outline-secondary {\n background-color: transparent;\n border-color: var(--pb-color-secondary, #64748b);\n color: var(--pb-color-secondary, #64748b);\n}\n.pb-button-outline-secondary:hover:not(:disabled) {\n background-color: var(--pb-color-secondary, #64748b);\n color: #ffffff;\n}\n.pb-button-link {\n background-color: transparent;\n border-color: transparent;\n color: var(--pb-color-primary, #f58220);\n padding-inline: 0.5em;\n}\n.pb-button-sm {\n padding: 0.375em 0.875em;\n font-size: 0.875rem;\n border-radius: var(--pb-radius-sm, 4px);\n}\n.pb-button-lg {\n padding: 0.625em 1.5em;\n font-size: 1.125rem;\n border-radius: var(--pb-radius-lg, 12px);\n}\n\n/* \u2500\u2500\u2500 Spinner \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pb-spinner {\n display: inline-block;\n width: 1.5rem;\n height: 1.5rem;\n border: 0.2em solid currentColor;\n border-right-color: transparent;\n border-radius: 50%;\n animation: pb-spin 0.75s linear infinite;\n vertical-align: -0.25em;\n}\n.pb-spinner-sm {\n width: 1rem;\n height: 1rem;\n border-width: 0.18em;\n}\n@keyframes pb-spin {\n to { transform: rotate(360deg); }\n}\n\n/* \u2500\u2500\u2500 Alertas \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pb-alert {\n padding: var(--pb-space-md, 16px) var(--pb-space-lg, 24px);\n border: 1px solid;\n border-radius: var(--pb-radius-md, 8px);\n margin-bottom: var(--pb-space-md, 16px);\n}\n.pb-alert-title {\n font-weight: var(--pb-font-weight-bold, 700);\n margin-bottom: 0.25em;\n}\n.pb-alert-primary {\n background-color: color-mix(in srgb, var(--pb-color-primary, #f58220) 10%, #fff);\n border-color: color-mix(in srgb, var(--pb-color-primary, #f58220) 35%, #fff);\n color: var(--pb-color-text, #1f2937);\n}\n.pb-alert-info {\n background-color: color-mix(in srgb, var(--pb-color-info, #0ea5e9) 10%, #fff);\n border-color: color-mix(in srgb, var(--pb-color-info, #0ea5e9) 35%, #fff);\n color: var(--pb-color-text, #1f2937);\n}\n.pb-alert-success {\n background-color: color-mix(in srgb, var(--pb-color-success, #16a34a) 10%, #fff);\n border-color: color-mix(in srgb, var(--pb-color-success, #16a34a) 35%, #fff);\n color: var(--pb-color-text, #1f2937);\n}\n.pb-alert-warning {\n background-color: color-mix(in srgb, var(--pb-color-warning, #f59e0b) 12%, #fff);\n border-color: color-mix(in srgb, var(--pb-color-warning, #f59e0b) 35%, #fff);\n color: var(--pb-color-text, #1f2937);\n}\n.pb-alert-danger {\n background-color: color-mix(in srgb, var(--pb-color-danger, #dc2626) 10%, #fff);\n border-color: color-mix(in srgb, var(--pb-color-danger, #dc2626) 35%, #fff);\n color: var(--pb-color-text, #1f2937);\n}\n.pb-alert-secondary {\n background-color: var(--pb-color-light, #f8fafc);\n border-color: var(--pb-color-border, #e5e7eb);\n color: var(--pb-color-text, #1f2937);\n}\n\n/* \u2500\u2500\u2500 Formul\u00E1rios \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pb-form-group {\n margin-bottom: var(--pb-space-md, 16px);\n}\n.pb-form-label {\n display: block;\n margin-bottom: 0.375rem;\n font-weight: var(--pb-font-weight-bold, 700);\n color: var(--pb-color-text, #1f2937);\n}\n.pb-form-control,\n.pb-form-select,\n.pb-form-textarea {\n display: block;\n width: 100%;\n padding: 0.5em 0.75em;\n font-family: inherit;\n font-size: 1rem;\n line-height: 1.5;\n color: var(--pb-color-text, #1f2937);\n background-color: var(--pb-color-surface, #ffffff);\n border: 1px solid var(--pb-color-border, #e5e7eb);\n border-radius: var(--pb-radius-sm, 4px);\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\n}\n.pb-form-control:focus,\n.pb-form-select:focus,\n.pb-form-textarea:focus {\n outline: none;\n border-color: var(--pb-color-primary, #f58220);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--pb-color-primary, #f58220) 20%, transparent);\n}\n.pb-form-control-invalid,\n.pb-form-select-invalid,\n.pb-form-textarea-invalid {\n border-color: var(--pb-color-danger, #dc2626);\n}\n.pb-invalid-feedback {\n display: block;\n margin-top: 0.375rem;\n font-size: 0.875rem;\n color: var(--pb-color-danger, #dc2626);\n}\n.pb-form-check {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n margin-bottom: 0.5rem;\n}\n.pb-form-check-input {\n width: 1.1em;\n height: 1.1em;\n accent-color: var(--pb-color-primary, #f58220);\n flex-shrink: 0;\n}\n.pb-form-check-label {\n font-weight: normal;\n margin-bottom: 0;\n}\n\n/* \u2500\u2500\u2500 Header \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pb-header {\n width: 100%;\n}\n.pb-header-inner {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--pb-space-md, 16px);\n flex-wrap: wrap;\n padding-block: var(--pb-space-sm, 8px);\n}\n.pb-brand {\n display: inline-flex;\n align-items: center;\n text-decoration: none;\n}\n.pb-brand img {\n max-height: 56px;\n width: auto;\n}\n.pb-nav {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n flex-wrap: wrap;\n}\n.pb-nav-link {\n display: inline-block;\n padding: 0.5rem 0.75rem;\n color: inherit;\n text-decoration: none;\n font-weight: 500;\n border-bottom: 2px solid transparent;\n transition: color 0.2s ease, border-color 0.2s ease;\n}\n.pb-nav-link:hover {\n text-decoration: none;\n opacity: 0.85;\n}\n.pb-nav-link-active {\n border-bottom-color: currentColor;\n}\n.pb-nav-toggle {\n display: none;\n padding: 0.375rem 0.625rem;\n font-size: 1.25rem;\n line-height: 1;\n background: transparent;\n border: 1px solid var(--pb-color-border, #e5e7eb);\n border-radius: var(--pb-radius-sm, 4px);\n cursor: pointer;\n color: inherit;\n}\n@media (max-width: 991.98px) {\n .pb-nav-toggle { display: inline-flex; align-items: center; }\n .pb-nav { display: none; }\n .pb-nav-open { display: flex; flex-direction: column; width: 100%; }\n}\n\n/* \u2500\u2500\u2500 Footer \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pb-footer {\n width: 100%;\n padding-block: var(--pb-space-xl, 32px);\n color: var(--pb-color-text, #1f2937);\n}\n.pb-footer-divider {\n border: none;\n border-top: 1px solid var(--pb-color-border, #e5e7eb);\n margin: var(--pb-space-lg, 24px) 0;\n}\n.pb-social-icons {\n display: flex;\n justify-content: center;\n gap: var(--pb-space-sm, 8px);\n flex-wrap: wrap;\n}\n.pb-social-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n font-size: 1.5rem;\n color: inherit;\n text-decoration: none;\n}\n.pb-social-icon:hover {\n text-decoration: none;\n opacity: 0.8;\n}\n\n/* \u2500\u2500\u2500 Loading \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pb-loading {\n min-height: 100vh;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: var(--pb-space-sm, 8px);\n font-weight: 600;\n letter-spacing: 0.08em;\n}\n\n/* \u2500\u2500\u2500 Utilit\u00E1rios de alinhamento \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pb-text-center { text-align: center; }\n.pb-mb-0 { margin-bottom: 0; }\n";