jbx 2.9.0 → 2.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +57 -11
  2. package/dist/JBX.d.ts +19 -0
  3. package/dist/JBX.d.ts.map +1 -0
  4. package/dist/JBX.js +19 -0
  5. package/dist/JBX.js.map +1 -0
  6. package/dist/classList.d.ts +2 -0
  7. package/dist/classList.d.ts.map +1 -0
  8. package/dist/classList.js +11 -0
  9. package/dist/classList.js.map +1 -0
  10. package/dist/components/Layout.d.ts +12 -0
  11. package/dist/components/Layout.d.ts.map +1 -0
  12. package/dist/components/Layout.js +17 -0
  13. package/dist/components/Layout.js.map +1 -0
  14. package/dist/components/MoreExperiments.d.ts +7 -0
  15. package/dist/components/MoreExperiments.d.ts.map +1 -0
  16. package/dist/components/MoreExperiments.js +59 -0
  17. package/dist/components/MoreExperiments.js.map +1 -0
  18. package/dist/generated/css.d.ts +2 -0
  19. package/dist/generated/css.d.ts.map +1 -0
  20. package/dist/generated/css.js +3 -0
  21. package/dist/generated/css.js.map +1 -0
  22. package/dist/index.d.ts +6 -148
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +6 -2792
  25. package/dist/index.js.map +1 -0
  26. package/dist/main.css +2 -2
  27. package/dist/primitives.d.ts +139 -0
  28. package/dist/primitives.d.ts.map +1 -0
  29. package/dist/primitives.js +102 -0
  30. package/dist/primitives.js.map +1 -0
  31. package/dist/spacing.d.ts +22 -0
  32. package/dist/spacing.d.ts.map +1 -0
  33. package/dist/spacing.js +27 -0
  34. package/dist/spacing.js.map +1 -0
  35. package/package.json +45 -28
  36. package/src/JBX.tsx +24 -0
  37. package/src/classList.tsx +9 -0
  38. package/src/components/Layout.tsx +31 -0
  39. package/src/components/MoreExperiments.tsx +74 -0
  40. package/src/generated/css.ts +2 -0
  41. package/src/index.tsx +6 -0
  42. package/src/primitives.tsx +247 -0
  43. package/src/spacing.ts +43 -0
  44. package/src/style.css +369 -0
@@ -0,0 +1,247 @@
1
+ import React, { createElement, ReactNode, CSSProperties } from 'react';
2
+ import { space, spacingPropsToStyle, BASE_RADIUS, SPACING_PROPS, SpacingProps } from './spacing.js';
3
+
4
+ type DivProps = React.HTMLAttributes<HTMLDivElement>;
5
+
6
+ type ComponentConfig = {
7
+ /** Tag to render. Defaults to `div`. */
8
+ element?: string;
9
+ /** Extra props always passed to the element. */
10
+ props?: Record<string, unknown>;
11
+ /**
12
+ * Props the style function consumes. They are used to compute the style and
13
+ * then kept off the DOM, so `<Inline gap={1} />` doesn't emit `gap="1"`.
14
+ */
15
+ styleProps?: readonly string[];
16
+ };
17
+
18
+ type StyleSource<T> = CSSProperties | ((props: T) => CSSProperties);
19
+
20
+ export function Component<T>(
21
+ className: string,
22
+ styleSrc: StyleSource<T> = {},
23
+ config: ComponentConfig = {}
24
+ ): (props: T & { children?: ReactNode; style?: CSSProperties }) => React.JSX.Element {
25
+ const { element = `div`, props: otherProps, styleProps } = config;
26
+
27
+ return function MakeComponent({
28
+ children,
29
+ style,
30
+ ...props
31
+ }: T & {
32
+ children?: ReactNode;
33
+ style?: CSSProperties;
34
+ }) {
35
+ const calculatedStyle =
36
+ typeof styleSrc === 'function' ? styleSrc(props as unknown as T) : styleSrc;
37
+
38
+ const elementProps = styleProps
39
+ ? Object.fromEntries(Object.entries(props).filter(([key]) => !styleProps.includes(key)))
40
+ : props;
41
+
42
+ return createElement(
43
+ element,
44
+ {
45
+ className,
46
+ // The caller's `style` wins over the computed one.
47
+ style: { ...calculatedStyle, ...style },
48
+ ...otherProps,
49
+ ...elementProps
50
+ },
51
+ children
52
+ );
53
+ };
54
+ }
55
+
56
+ export const Container = Component<DivProps>(`jbx-container`);
57
+
58
+ export const Text = Component<DivProps>(`jbx-text`);
59
+
60
+ export const SmallText = Component<DivProps>(`jbx-small-text`);
61
+
62
+ export const Button = Component<React.ButtonHTMLAttributes<HTMLButtonElement>>(
63
+ `jbx-button`,
64
+ {},
65
+ { element: 'button' }
66
+ );
67
+
68
+ export const Input = Component<React.InputHTMLAttributes<HTMLInputElement>>(
69
+ `jbx-input`,
70
+ {},
71
+ { element: 'input' }
72
+ );
73
+
74
+ export const Range = Component<React.InputHTMLAttributes<HTMLInputElement>>(
75
+ `jbx-range`,
76
+ {},
77
+ {
78
+ element: 'input',
79
+ props: {
80
+ type: 'range'
81
+ }
82
+ }
83
+ );
84
+
85
+ type HeadingProps = React.HTMLAttributes<HTMLHeadingElement>;
86
+ export const HeaderH1 = Component<HeadingProps>(`jbx-h${1}`, {}, { element: 'h1' });
87
+ export const HeaderH2 = Component<HeadingProps>(`jbx-h${2}`, {}, { element: 'h2' });
88
+ export const HeaderH3 = Component<HeadingProps>(`jbx-h${3}`, {}, { element: 'h3' });
89
+ export const HeaderH4 = Component<HeadingProps>(`jbx-h${4}`, {}, { element: 'h4' });
90
+ export const HR = Component<React.HTMLAttributes<HTMLHRElement>>(`jbx-hr`, {}, { element: 'hr' });
91
+
92
+ export const MainHeader = Component<HeadingProps>(`jbx-main-h1`, {}, { element: 'h1' });
93
+
94
+ export const A = Component<React.AnchorHTMLAttributes<HTMLAnchorElement> & { href: string }>(
95
+ `jbx-a`,
96
+ {},
97
+ { element: 'a' }
98
+ );
99
+
100
+ type SpaceProps = DivProps & { inline?: boolean; h?: number; w?: number };
101
+ export const Space = Component<SpaceProps>(
102
+ `jbx-space`,
103
+ ({ inline, h, w }) => ({
104
+ display: inline ? 'inline-block' : 'block',
105
+ height: h === undefined ? undefined : space(h),
106
+ width: w === undefined ? undefined : space(w)
107
+ }),
108
+ { styleProps: ['inline', 'h', 'w'] }
109
+ );
110
+
111
+ type InlineProps = DivProps & SpacingProps & { wrap?: boolean };
112
+ export const Inline = Component<InlineProps>(
113
+ `jbx-inline`,
114
+ ({ wrap = true, ...spacing }) => ({
115
+ ...spacingPropsToStyle(spacing),
116
+ flexWrap: wrap ? 'wrap' : 'nowrap'
117
+ }),
118
+ { styleProps: [...SPACING_PROPS, 'wrap'] }
119
+ );
120
+
121
+ type StackProps = DivProps & SpacingProps;
122
+ export const Stack = Component<StackProps>(`jbx-stack`, (props) => spacingPropsToStyle(props), {
123
+ styleProps: SPACING_PROPS
124
+ });
125
+
126
+ export const Dropzone = Component<DivProps>(`jbx-dropzone`);
127
+
128
+ export const Ul = Component<React.HTMLAttributes<HTMLUListElement>>(
129
+ `jbx-ul`,
130
+ {
131
+ margin: 0,
132
+ padding: `0 0 0 ${space(0.25)}`
133
+ },
134
+ { element: 'ul' }
135
+ );
136
+
137
+ export const Li = Component<React.LiHTMLAttributes<HTMLLIElement>>(
138
+ `jbx-li`,
139
+ {
140
+ margin: `0 0 0 ${space(1)}`,
141
+ padding: `${space(0.25)} 0`
142
+ },
143
+ { element: 'li' }
144
+ );
145
+
146
+ export const Tabs = Component<DivProps>(`jbx-tabs`);
147
+
148
+ type TabProps = DivProps & { info?: boolean; active?: boolean };
149
+ export const Tab = Component<TabProps>(
150
+ `jbx-tabs--tab`,
151
+ ({ info, active }) => ({
152
+ userSelect: 'none',
153
+ cursor: 'pointer',
154
+ backgroundColor: active ? '#000' : info ? '#fff' : '#ecf0f1',
155
+ color: active ? '#fff' : '#000',
156
+ padding: space(0.5),
157
+ paddingLeft: info ? 0 : space(0.5)
158
+ }),
159
+ { styleProps: ['info', 'active'] }
160
+ );
161
+
162
+ export const CodeSnippet = Component<React.HTMLAttributes<HTMLPreElement>>(
163
+ `jbx-code-snippet`,
164
+ {},
165
+ { element: 'pre' }
166
+ );
167
+
168
+ export const CodeTextarea = Component<React.TextareaHTMLAttributes<HTMLTextAreaElement>>(
169
+ `jbx-code-area`,
170
+ {},
171
+ { element: 'textarea' }
172
+ );
173
+
174
+ export const CheckboxHidden = Component<DivProps & { isChecked?: boolean }>(
175
+ `jbx-checkbox-hidden`,
176
+ ({ isChecked }) => ({
177
+ height: `calc(${space(2)} - 4px)`,
178
+ width: `calc(${space(2)} - 4px)`,
179
+ paddingTop: 2,
180
+ paddingLeft: 2,
181
+ backgroundColor: isChecked ? 'var(--accent-color)' : 'white',
182
+ borderRadius: BASE_RADIUS,
183
+ boxShadow: isChecked
184
+ ? 'inset rgba(0, 0, 0, 0.07) 0 0 0 1px'
185
+ : 'inset rgba(0, 0, 0, 0.33) 0 0 0 1.5px',
186
+ cursor: 'pointer'
187
+ }),
188
+ { styleProps: ['isChecked'] }
189
+ );
190
+
191
+ export function Checkbox({
192
+ label,
193
+ checked,
194
+ onChange
195
+ }: {
196
+ label: string;
197
+ checked: boolean;
198
+ onChange?: (value: boolean) => void;
199
+ }) {
200
+ function toggle() {
201
+ if (onChange) onChange(!checked);
202
+ }
203
+
204
+ return (
205
+ <Inline
206
+ role="checkbox"
207
+ aria-checked={checked}
208
+ tabIndex={0}
209
+ onClick={toggle}
210
+ onKeyDown={(event) => {
211
+ if (event.key === ' ' || event.key === 'Enter') {
212
+ event.preventDefault();
213
+ toggle();
214
+ }
215
+ }}
216
+ style={{ alignItems: 'center', cursor: 'pointer' }}
217
+ >
218
+ <CheckboxHidden isChecked={checked}>
219
+ <svg
220
+ xmlns="http://www.w3.org/2000/svg"
221
+ fill="none"
222
+ stroke="currentColor"
223
+ strokeLinecap="round"
224
+ strokeLinejoin="round"
225
+ strokeWidth="2"
226
+ className="feather feather-check"
227
+ viewBox="0 0 24 24"
228
+ color={checked ? 'white' : '#ddd'}
229
+ style={{ height: `calc(${space(2)} - 8px)`, width: `calc(${space(2)} - 8px)` }}
230
+ >
231
+ <path d="M20 6L9 17 4 12" />
232
+ </svg>
233
+ </CheckboxHidden>
234
+ <Space w={0.5} />
235
+ <Text style={{ userSelect: 'none' }}>{label}</Text>
236
+ </Inline>
237
+ );
238
+ }
239
+
240
+ export function Bullet({ value }: { value: number }) {
241
+ return (
242
+ <div className="jbx-bullet-container">
243
+ <div className="jbx-bullet">{value}</div>
244
+ </div>
245
+ );
246
+ }
247
+
package/src/spacing.ts ADDED
@@ -0,0 +1,43 @@
1
+ import type { CSSProperties } from 'react';
2
+
3
+ /**
4
+ * One spacing unit, as a css value rather than a number, so javascript-driven
5
+ * spacing tracks the responsive `--size` variable in style.css the same way
6
+ * the stylesheet does.
7
+ */
8
+ export function space(n: number): string {
9
+ return `calc(var(--size) * ${n})`;
10
+ }
11
+
12
+ export const BASE_RADIUS = `calc(var(--size) / 3)`;
13
+
14
+ export type SpacingProps = {
15
+ /** Vertical margin, in spacing units. */
16
+ v?: number;
17
+ /** Horizontal margin, in spacing units. */
18
+ h?: number;
19
+ /** Gap between children, in spacing units. */
20
+ gap?: number;
21
+ /** Padding, in spacing units. An array is joined like the css shorthand. */
22
+ padding?: number | number[];
23
+ };
24
+
25
+ /** Keys `spacingPropsToStyle` consumes, so they can be kept off the DOM. */
26
+ export const SPACING_PROPS = ['v', 'h', 'gap', 'padding'] as const;
27
+
28
+ export function spacingPropsToStyle({ v, h, gap, padding }: SpacingProps): CSSProperties {
29
+ return {
30
+ marginLeft: h === undefined ? undefined : space(h),
31
+ marginRight: h === undefined ? undefined : space(h),
32
+ marginTop: v === undefined ? undefined : space(v),
33
+ marginBottom: v === undefined ? undefined : space(v),
34
+ gap: gap === undefined ? undefined : space(gap),
35
+ padding:
36
+ padding === undefined
37
+ ? undefined
38
+ : [padding]
39
+ .flat()
40
+ .map((value) => space(value))
41
+ .join(' ')
42
+ };
43
+ }
package/src/style.css ADDED
@@ -0,0 +1,369 @@
1
+ html {
2
+ box-sizing: border-box;
3
+ }
4
+ *,
5
+ *:before,
6
+ *:after {
7
+ box-sizing: inherit;
8
+ }
9
+
10
+ :root {
11
+ --size: 16px;
12
+ --font-size: 16px;
13
+ --font-size-small: 17px;
14
+ --radius-small: 2px;
15
+ }
16
+
17
+ @media screen and (max-width: 1200px) {
18
+ :root {
19
+ --font-size: 18px;
20
+ --font-size-small: 16px;
21
+ --size: 14px;
22
+ }
23
+ }
24
+
25
+ @media screen and (max-width: 600px) {
26
+ :root {
27
+ --font-size: 16px;
28
+ --font-size-small: 14px;
29
+ }
30
+ }
31
+
32
+ * {
33
+ padding: 0;
34
+ margin: 0;
35
+ position: relative;
36
+ }
37
+
38
+ body {
39
+ touch-action: pan-y;
40
+ }
41
+
42
+ body,
43
+ input,
44
+ textarea {
45
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
46
+ }
47
+
48
+ body {
49
+ background: #fcfcfd;
50
+ color: #000;
51
+ }
52
+
53
+ h1,
54
+ h2,
55
+ h3,
56
+ h4 {
57
+ line-height: 1;
58
+ padding: 0;
59
+ font-variation-settings: 'wght' 600;
60
+ font-weight: 600;
61
+ color: var(--base-font-color-bright);
62
+ }
63
+ h1 {
64
+ font-variation-settings: 'wdth' 107, 'wght' 650;
65
+ font-weight: 650;
66
+ }
67
+
68
+ strong,
69
+ b {
70
+ font-weight: 500;
71
+ }
72
+
73
+ .jbx-main-h1 {
74
+ display: inline-block;
75
+ background-color: var(--accent-color);
76
+ font-size: calc(var(--font-size) * 2);
77
+ padding: 8px;
78
+ }
79
+
80
+ .jbx-h1 {
81
+ font-size: calc(var(--font-size) * 2);
82
+ font-weight: 700;
83
+ }
84
+ .jbx-h2 {
85
+ font-size: calc(var(--font-size) * 1.25);
86
+ }
87
+ .jbx-h3 {
88
+ font-size: calc(var(--font-size) * 1.125);
89
+ }
90
+ .jbx-h4 {
91
+ font-size: var(--font-size-small);
92
+ text-transform: uppercase;
93
+ }
94
+
95
+ /* base text */
96
+ html,
97
+ body,
98
+ .jbx-button,
99
+ .jbx-input {
100
+ font-size: var(--font-size);
101
+ line-height: 1;
102
+ }
103
+
104
+ .jbx-code-snippet {
105
+ border-radius: var(--size);
106
+ font-family: monaco, monospace;
107
+ border: none;
108
+ width: 100%;
109
+ font-size: calc(var(--size) - 3px);
110
+ line-height: 1.33;
111
+ padding: var(--size) calc(var(--size) * 1.2);
112
+ background: #ecf0f1;
113
+ color: #34495e;
114
+ resize: none;
115
+ }
116
+ .jbx-code-snippet:focus {
117
+ outline: none;
118
+ }
119
+
120
+ .jbx-code-area {
121
+ border-radius: var(--size);
122
+ font-family: monaco, monospace;
123
+ border: none;
124
+ width: 100%;
125
+ font-size: calc(var(--size) - 3px);
126
+ line-height: 1.33;
127
+ padding: var(--size) calc(var(--size) * 1.2);
128
+ background: #ecf0f1;
129
+ color: #34495e;
130
+ resize: none;
131
+ min-height: 120px;
132
+ }
133
+ .jbx-code-area:focus {
134
+ outline: none;
135
+ }
136
+
137
+ .jbx-button {
138
+ color: #000;
139
+ border-radius: var(--radius-small);
140
+ appearance: none;
141
+ user-select: none;
142
+ cursor: pointer;
143
+ display: inline-block;
144
+ background-color: #eee;
145
+ box-shadow: 3px 3px 0 #ccc;
146
+ padding: 0 calc(var(--size) / 2);
147
+ border: none;
148
+ height: calc(var(--size) * 2.5);
149
+ transition: top 0.1s, left 0.1s, box-shadow 0.05s;
150
+ }
151
+ .jbx-button:active {
152
+ top: 1px;
153
+ left: 1px;
154
+ box-shadow: 1px 1px 0 #ccc;
155
+ }
156
+
157
+ /* LINKS */
158
+ .jbx-a {
159
+ cursor: pointer;
160
+ color: #000;
161
+ box-shadow: #0002 0 2px 0;
162
+ font-weight: 500;
163
+ text-decoration: none;
164
+ }
165
+ .jbx-a::after {
166
+ content: '↗';
167
+ color: #0004;
168
+ font-size: var(--font-size-small);
169
+ position: relative;
170
+ top: -1px;
171
+ right: -1px;
172
+ transition: top 0.3s, right 0.3s, color 0.3s;
173
+ }
174
+ .jbx-a:hover,
175
+ .jbx-block-link:hover .jbx-a {
176
+ box-shadow: var(--accent-color) 0 2px 0;
177
+ }
178
+ .jbx-a:hover::after,
179
+ .jbx-block-link:hover .jbx-a::after {
180
+ top: -3px;
181
+ right: -3px;
182
+ color: var(--accent-color);
183
+ }
184
+
185
+ .jbx-block-link {
186
+ min-width: 300px;
187
+ flex: 1;
188
+ text-decoration: none;
189
+ color: #000;
190
+ display: inline-block;
191
+ padding: var(--size);
192
+ }
193
+ a.jbx-a::before,
194
+ .jbx-block-link::before {
195
+ content: '';
196
+ display: block;
197
+ position: absolute;
198
+ background-color: #ecf0f1;
199
+ z-index: -1;
200
+ transition: transform 0.2s, opacity 0.2s;
201
+ transform: scale(0.98) translatey(4px);
202
+ opacity: 0;
203
+ top: -4px;
204
+ left: -6px;
205
+ right: -6px;
206
+ bottom: -4px;
207
+ }
208
+ .jbx-block-link::before {
209
+ border-radius: 16px;
210
+ }
211
+ a.jbx-a::before {
212
+ border-radius: 8px;
213
+ }
214
+ a.jbx-a:hover::before,
215
+ .jbx-block-link:hover::before {
216
+ transform: scale(1) translatey(0);
217
+ opacity: 1;
218
+ }
219
+
220
+ .jbx-a {
221
+ display: inline-block;
222
+ }
223
+
224
+ /* /LINKS */
225
+
226
+ .jbx-small-text {
227
+ font-size: var(--font-size-small);
228
+ }
229
+
230
+ .jbx-container {
231
+ max-width: 1080px;
232
+ margin: 0 auto;
233
+ padding: calc(var(--size) * 2.5) calc(var(--size) * 1.5) calc(var(--size) * 4);
234
+ }
235
+
236
+ .jbx-box {
237
+ flex: 1;
238
+ }
239
+
240
+ .jbx-inline {
241
+ flex: 1;
242
+ display: flex;
243
+ flex-wrap: wrap;
244
+ flex-direction: row;
245
+ }
246
+
247
+ .jbx-stack {
248
+ flex: 1;
249
+ display: flex;
250
+ flex-wrap: wrap;
251
+ flex-direction: column;
252
+ }
253
+
254
+ .jbx-text {
255
+ line-height: 1.4;
256
+ }
257
+
258
+ .jbx-input {
259
+ color: #777;
260
+ -webkit-text-fill-color: #777;
261
+ opacity: 1;
262
+ flex: 1;
263
+ display: block;
264
+ appearance: none;
265
+ border: none;
266
+ border-radius: var(--radius-small);
267
+ height: calc(var(--size) * 2.5);
268
+ background-color: #eee;
269
+ padding: 0 calc(var(--size) * 0.5);
270
+ box-shadow: inset rgba(0, 0, 0, 0.04) 3px 3px 0, inset rgba(0, 0, 0, 0.03) 0.5px 0.5px 0;
271
+ }
272
+
273
+ .jbx-dropzone {
274
+ height: 120px;
275
+ flex: 1;
276
+ display: flex;
277
+ text-align: center;
278
+ align-items: center;
279
+ align-content: center;
280
+ justify-content: center;
281
+ flex-direction: column;
282
+ border: 2px dashed #000;
283
+ color: #000;
284
+ padding: 0;
285
+ cursor: pointer;
286
+ }
287
+ .jbx-dropzone:hover {
288
+ border-color: #999;
289
+ }
290
+ .jbx-dropzone span {
291
+ width: 100%;
292
+ cursor: pointer;
293
+ }
294
+ .jbx-dropzone input {
295
+ position: absolute;
296
+ top: 0;
297
+ left: 0;
298
+ height: 100%;
299
+ width: 100%;
300
+ opacity: 0;
301
+ cursor: pointer;
302
+ }
303
+
304
+ .jbx-range {
305
+ flex: 1;
306
+ width: 100%;
307
+ appearance: none;
308
+ background-color: #bdc3c780;
309
+ height: var(--size);
310
+ border-radius: 0;
311
+ border-radius: var(--radius-small);
312
+ }
313
+
314
+ .jbx-range::-webkit-slider-thumb {
315
+ -webkit-appearance: none;
316
+ appearance: none;
317
+ box-shadow: none;
318
+ border-radius: 0;
319
+ height: calc(var(--size) * 2);
320
+ width: var(--size);
321
+ background-color: #000;
322
+ border: none;
323
+ border-radius: var(--radius-small);
324
+ }
325
+ .jbx-range::-moz-range-thumb {
326
+ appearance: none;
327
+ box-shadow: none;
328
+ border-radius: 0;
329
+ height: calc(var(--size) * 2);
330
+ width: var(--size);
331
+ background-color: #000;
332
+ border: none;
333
+ border-radius: var(--radius-small);
334
+ }
335
+ .jbx-range::-webkit-slider-runnable-track {
336
+ appearance: none;
337
+ }
338
+ .jbx-range:focus {
339
+ outline: none;
340
+ }
341
+
342
+ .jbx-bullet-container {
343
+ display: inline-block;
344
+ margin: -8px 4px -8px 0;
345
+ }
346
+
347
+ .jbx-bullet {
348
+ border: 1px solid #0001;
349
+ color: #000;
350
+ background-color: #0001;
351
+ text-align: center;
352
+ display: flex;
353
+ align-items: center;
354
+ justify-content: center;
355
+ font-size: calc(var(--font-size-small) - 3px);
356
+ height: calc(var(--size) * 1.25);
357
+ width: calc(var(--size) * 1.25);
358
+ border-radius: 100%;
359
+ top: -2px;
360
+ margin-right: 2px;
361
+ }
362
+
363
+ .jbx-hr {
364
+ margin: calc(var(--size) * 2) auto;
365
+ width: 38.2%;
366
+ border-radius: 0;
367
+ border: none;
368
+ border-top: 2px solid #ecf0f1;
369
+ }