@stackoverflow/stacks 1.1.0 → 1.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 (40) hide show
  1. package/dist/controllers/s-expandable-control.d.ts +1 -1
  2. package/dist/controllers/s-tooltip.d.ts +16 -1
  3. package/dist/css/stacks.css +887 -708
  4. package/dist/css/stacks.min.css +1 -1
  5. package/dist/js/stacks.js +174 -91
  6. package/dist/js/stacks.min.js +1 -1
  7. package/lib/css/atomic/misc.less +1 -1
  8. package/lib/css/atomic/typography.less +0 -6
  9. package/lib/css/atomic/width-height.less +1 -1
  10. package/lib/css/components/activity-indicator.less +18 -17
  11. package/lib/css/components/avatars.less +51 -131
  12. package/lib/css/components/badges.less +47 -0
  13. package/lib/css/components/breadcrumbs.less +4 -4
  14. package/lib/css/components/buttons.less +38 -54
  15. package/lib/css/components/empty-states.less +15 -0
  16. package/lib/css/components/{collapsible.less → expandable.less} +0 -0
  17. package/lib/css/components/inputs.less +44 -110
  18. package/lib/css/components/labels.less +98 -0
  19. package/lib/css/components/notices.less +190 -163
  20. package/lib/css/components/post-summary.less +34 -99
  21. package/lib/css/components/progress-bars.less +1 -1
  22. package/lib/css/components/prose.less +4 -4
  23. package/lib/css/components/spinner.less +39 -1
  24. package/lib/css/components/tables.less +1 -5
  25. package/lib/css/components/topbar.less +4 -1
  26. package/lib/css/components/uploader.less +70 -84
  27. package/lib/css/exports/constants-colors.less +63 -49
  28. package/lib/css/stacks-dynamic.less +0 -1
  29. package/lib/css/stacks-static.less +3 -2
  30. package/lib/ts/controllers/s-expandable-control.ts +23 -19
  31. package/lib/ts/controllers/s-modal.ts +16 -16
  32. package/lib/ts/controllers/s-navigation-tablist.ts +13 -13
  33. package/lib/ts/controllers/s-popover.ts +26 -18
  34. package/lib/ts/controllers/s-table.ts +31 -29
  35. package/lib/ts/controllers/s-tooltip.ts +62 -23
  36. package/lib/ts/controllers/s-uploader.ts +26 -12
  37. package/lib/ts/stacks.ts +8 -4
  38. package/package.json +25 -25
  39. package/lib/css/components/banners.less +0 -80
  40. package/lib/css/components/blank-states.less +0 -26
@@ -10,10 +10,12 @@ export class TooltipController extends BasePopoverController {
10
10
 
11
11
  protected popoverSelectorAttribute = "aria-describedby";
12
12
 
13
- private boundScheduleShow!: any;
14
- private boundHide!: any;
15
- private boundHideIfWithin!: any;
16
- private activeTimeout!: any;
13
+ private boundScheduleShow!: () => void;
14
+ private boundHide!: () => void;
15
+ private boundHideIfWithin!: () => void;
16
+ private boundHideOnEscapeKeyEvent!: () => void;
17
+ private boundClearActiveTimeout!: () => void;
18
+ private activeTimeout!: number;
17
19
 
18
20
  /**
19
21
  * Binds mouseover and mouseout events in addition to BasePopoverController.connect
@@ -27,12 +29,14 @@ export class TooltipController extends BasePopoverController {
27
29
  if (window.matchMedia("(hover: hover)").matches) {
28
30
  this.bindMouseEvents();
29
31
  }
32
+ this.bindKeyboardEvents();
30
33
  }
31
34
 
32
35
  /**
33
36
  * Unbinds mouse events in addition to BasePopoverController.disconnect
34
37
  */
35
38
  disconnect() {
39
+ this.unbindKeyboardEvents();
36
40
  this.unbindMouseEvents();
37
41
  super.disconnect();
38
42
  }
@@ -43,7 +47,7 @@ export class TooltipController extends BasePopoverController {
43
47
  */
44
48
  show(dispatcher: Event|Element|null = null) {
45
49
  // check and see if this controller coexists with a popover
46
- var controller = Stacks.application.getControllerForElementAndIdentifier(this.element, "s-popover");
50
+ const controller = Stacks.application.getControllerForElementAndIdentifier(this.element, "s-popover");
47
51
 
48
52
  // if the controller exists and already has a visible popover, don't show the tooltip
49
53
  if (controller && (<PopoverController>controller).isVisible) {
@@ -64,11 +68,16 @@ export class TooltipController extends BasePopoverController {
64
68
  /**
65
69
  * Cancels the scheduled tooltip popover display and hides it if already displayed
66
70
  */
67
- hide(dispatcher: Event | Element | null = null) {
71
+ scheduleHide(dispatcher: Event | Element | null = null) {
68
72
  window.clearTimeout(this.activeTimeout);
69
- this.activeTimeout = null;
73
+ this.activeTimeout = window.setTimeout(() => super.hide(dispatcher), 100);
74
+ }
70
75
 
71
- super.hide(dispatcher);
76
+ /**
77
+ * Cancels the activeTimeout
78
+ */
79
+ clearActiveTimeout() {
80
+ clearTimeout(this.activeTimeout);
72
81
  }
73
82
 
74
83
  /**
@@ -76,13 +85,14 @@ export class TooltipController extends BasePopoverController {
76
85
  */
77
86
  applyTitleAttributes() {
78
87
 
79
- var content: Node;
88
+ let content: Node;
80
89
 
81
- var htmlTitle = this.data.get("html-title");
90
+ const htmlTitle = this.data.get("html-title");
82
91
  if (htmlTitle) {
92
+ // eslint-disable-next-line no-unsanitized/method
83
93
  content = document.createRange().createContextualFragment(htmlTitle);
84
94
  } else {
85
- var plainTitle = this.element.getAttribute("title");
95
+ const plainTitle = this.element.getAttribute("title");
86
96
  if (plainTitle) {
87
97
  content = document.createTextNode(plainTitle);
88
98
  } else {
@@ -93,21 +103,20 @@ export class TooltipController extends BasePopoverController {
93
103
  this.data.delete("html-title");
94
104
  this.element.removeAttribute("title");
95
105
 
96
- var popoverId = this.element.getAttribute("aria-describedby");
106
+ let popoverId = this.element.getAttribute("aria-describedby");
97
107
  if (!popoverId) {
98
108
  popoverId = TooltipController.generateId();
99
109
  this.element.setAttribute("aria-describedby", popoverId);
100
110
  }
101
111
 
102
- var popover = document.getElementById(popoverId);
112
+ let popover = document.getElementById(popoverId);
103
113
  if (!popover) {
104
114
  popover = document.createElement("div");
105
115
  popover.id = popoverId;
106
- popover.className = "s-popover s-popover__tooltip pe-none";
107
- popover.setAttribute("aria-hidden", "true");
116
+ popover.className = "s-popover s-popover__tooltip";
108
117
  popover.setAttribute("role", "tooltip");
109
118
 
110
- var parentNode = this.element.parentNode;
119
+ const parentNode = this.element.parentNode;
111
120
  if (parentNode) {
112
121
  // insertBefore inserts at end if element.nextSibling is null.
113
122
  parentNode.insertBefore(popover, this.element.nextSibling);
@@ -165,21 +174,49 @@ export class TooltipController extends BasePopoverController {
165
174
  */
166
175
  private hideIfWithin(event: Event) {
167
176
  if ((<Element>event.target!).contains(this.referenceElement)) {
168
- this.hide();
177
+ this.scheduleHide();
178
+ }
179
+ }
180
+
181
+ private hideOnEscapeKeyEvent(event: KeyboardEvent) {
182
+ if (event.key === "Escape") {
183
+ this.scheduleHide();
169
184
  }
170
185
  }
186
+ /**
187
+ * Binds mouse events to show/hide on reference element hover
188
+ */
189
+ private bindKeyboardEvents() {
190
+ this.boundScheduleShow = this.boundScheduleShow || this.scheduleShow.bind(this);
191
+ this.boundHide = this.boundHide || this.scheduleHide.bind(this);
192
+ this.boundHideOnEscapeKeyEvent = this.boundHideOnEscapeKeyEvent || this.hideOnEscapeKeyEvent.bind(this);
193
+
194
+ this.referenceElement.addEventListener("focus", this.boundScheduleShow);
195
+ this.referenceElement.addEventListener("blur", this.boundHide);
196
+ document.addEventListener("keyup", this.boundHideOnEscapeKeyEvent);
197
+ }
198
+ /**
199
+ * Unbinds all mouse events
200
+ */
201
+ private unbindKeyboardEvents() {
202
+ this.referenceElement.removeEventListener("focus", this.boundScheduleShow);
203
+ this.referenceElement.removeEventListener("blur", this.boundHide);
204
+ document.removeEventListener("keyup", this.boundHideOnEscapeKeyEvent);
205
+ }
206
+
171
207
 
172
208
  /**
173
209
  * Binds mouse events to show/hide on reference element hover
174
210
  */
175
211
  private bindMouseEvents() {
176
212
  this.boundScheduleShow = this.boundScheduleShow || this.scheduleShow.bind(this);
177
- this.boundHide = this.boundHide || this.hide.bind(this);
213
+ this.boundHide = this.boundHide || this.scheduleHide.bind(this);
214
+ this.boundClearActiveTimeout = this.boundClearActiveTimeout || this.clearActiveTimeout.bind(this);
178
215
 
179
216
  this.referenceElement.addEventListener("mouseover", this.boundScheduleShow);
180
217
  this.referenceElement.addEventListener("mouseout", this.boundHide);
181
- this.referenceElement.addEventListener("focus", this.boundScheduleShow);
182
- this.referenceElement.addEventListener("blur", this.boundHide);
218
+ this.popoverElement.addEventListener("mouseover", this.boundClearActiveTimeout);
219
+ this.popoverElement.addEventListener("mouseout", this.boundHide);
183
220
  }
184
221
 
185
222
  /**
@@ -190,6 +227,8 @@ export class TooltipController extends BasePopoverController {
190
227
  this.referenceElement.removeEventListener("mouseout", this.boundHide);
191
228
  this.referenceElement.removeEventListener("focus", this.boundScheduleShow);
192
229
  this.referenceElement.removeEventListener("blur", this.boundHide);
230
+ this.popoverElement.removeEventListener("mouseover", this.boundClearActiveTimeout);
231
+ this.popoverElement.removeEventListener("mouseout", this.boundHide);
193
232
  }
194
233
 
195
234
  /**
@@ -231,16 +270,16 @@ export function setTooltipText(element: Element, text: string, options?: Tooltip
231
270
  * @param options Options for rendering the tooltip.
232
271
  */
233
272
  function applyOptionsAndTitleAttributes(element: Element, options?: TooltipOptions) {
234
-
235
273
  if (options && options.placement) {
236
274
  element.setAttribute("data-s-tooltip-placement", options.placement);
237
275
  }
238
276
 
239
- var controller = <TooltipController>Stacks.application.getControllerForElementAndIdentifier(element, "s-tooltip");
277
+ const controller = <TooltipController>Stacks.application.getControllerForElementAndIdentifier(element, "s-tooltip");
240
278
 
241
279
  if (controller) {
242
280
  controller.applyTitleAttributes();
243
281
  } else {
244
- element.setAttribute("data-controller", element.getAttribute("data-controller") + " s-tooltip");
282
+ const dataController = element.getAttribute("data-controller");
283
+ element.setAttribute("data-controller", `${dataController ? dataController : ""} s-tooltip`);
245
284
  }
246
285
  }
@@ -12,8 +12,8 @@ export class UploaderController extends Stacks.StacksController {
12
12
  private previewsTarget!: HTMLElement;
13
13
  private uploaderTarget!: HTMLElement;
14
14
 
15
- private boundDragEnter!: any;
16
- private boundDragLeave!: any;
15
+ private boundDragEnter!: () => void;
16
+ private boundDragLeave!: () => void;
17
17
 
18
18
  private static readonly FILE_DISPLAY_LIMIT = 10;
19
19
  private static readonly MAX_FILE_SIZE = 1024 * 1024 * 10; // 10 MB
@@ -50,7 +50,7 @@ export class UploaderController extends Stacks.StacksController {
50
50
  const hasMultipleFiles = res.length > 1;
51
51
 
52
52
  if (hasMultipleFiles) {
53
- let headingElement = document.createElement("div");
53
+ const headingElement = document.createElement("div");
54
54
  headingElement.classList.add("s-uploader--previews-heading");
55
55
  headingElement.innerText = res.length < count ?
56
56
  `Showing ${res.length} of ${count} files` : `${count} items`;
@@ -61,7 +61,9 @@ export class UploaderController extends Stacks.StacksController {
61
61
  }
62
62
  res.forEach((file) => this.addFilePreview(file));
63
63
  this.handleUploaderActive(true);
64
- });
64
+ })
65
+ // TODO consider rendering an error message
66
+ .catch(() => null);
65
67
  }
66
68
 
67
69
  /**
@@ -84,13 +86,25 @@ export class UploaderController extends Stacks.StacksController {
84
86
  const enableElements = scope.findAllElements('[data-s-uploader-enable-on-input]');
85
87
 
86
88
  if (shouldPreview) {
87
- hideElements.map(el => el.classList.add("d-none"));
88
- showElements.map(el => el.classList.remove("d-none"));
89
- enableElements.map(el => el.removeAttribute("disabled"));
89
+ hideElements.forEach(el => {
90
+ el.classList.add("d-none");
91
+ });
92
+ showElements.forEach(el => {
93
+ el.classList.remove("d-none");
94
+ });
95
+ enableElements.forEach(el => {
96
+ el.removeAttribute("disabled");
97
+ });
90
98
  } else {
91
- hideElements.map(el => el.classList.remove("d-none"));
92
- showElements.map(el => el.classList.add("d-none"));
93
- enableElements.map(el => el.setAttribute("disabled", "true"))
99
+ hideElements.forEach(el => {
100
+ el.classList.remove("d-none");
101
+ });
102
+ showElements.forEach(el => {
103
+ el.classList.add("d-none");
104
+ });
105
+ enableElements.forEach(el => {
106
+ el.setAttribute("disabled", "true");
107
+ });
94
108
  this.handleUploaderActive(false);
95
109
  }
96
110
  }
@@ -104,7 +118,7 @@ export class UploaderController extends Stacks.StacksController {
104
118
  return;
105
119
  }
106
120
 
107
- let previewElement = document.createElement("div");
121
+ const previewElement = document.createElement("div");
108
122
  let thumbElement;
109
123
 
110
124
  if (file.type.match('image/*') && file.data) {
@@ -137,7 +151,7 @@ export class UploaderController extends Stacks.StacksController {
137
151
  * @returns an object containing a FilePreview object
138
152
  */
139
153
  private fileToDataURL(file: File): Promise<FilePreview> {
140
- var reader = new FileReader();
154
+ const reader = new FileReader();
141
155
  const { name, size, type } = file;
142
156
 
143
157
  if (size < UploaderController.MAX_FILE_SIZE && type.indexOf("image") > -1) {
package/lib/ts/stacks.ts CHANGED
@@ -9,7 +9,7 @@ export class StacksApplication extends Stimulus.Application {
9
9
  const definitions = Array.isArray(head) ? head : [head, ...rest];
10
10
 
11
11
  for (const definition of definitions) {
12
- var hasPrefix = /^s-/.test(definition.identifier);
12
+ const hasPrefix = /^s-/.test(definition.identifier);
13
13
  if (StacksApplication._initializing && !hasPrefix) {
14
14
  throw "Stacks-created Stimulus controller names must start with \"s-\".";
15
15
  }
@@ -23,6 +23,7 @@ export class StacksApplication extends Stimulus.Application {
23
23
 
24
24
  static start(element?: Element, schema?: Stimulus.Schema): StacksApplication {
25
25
  const application = new StacksApplication(element, schema);
26
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
26
27
  application.start();
27
28
  return application;
28
29
  }
@@ -46,13 +47,14 @@ export class StacksController extends Stimulus.Controller {
46
47
  };
47
48
  protected triggerEvent<T>(eventName: string, detail?: T, optionalElement?: Element) {
48
49
  const namespacedName = this.identifier + ":" + eventName;
49
- var event : CustomEvent<T>;
50
+ let event : CustomEvent<T>;
50
51
  try {
51
52
  event = new CustomEvent(namespacedName, {bubbles: true, cancelable: true, detail: detail});
52
53
  } catch (ex) {
53
54
  // Internet Explorer
55
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
54
56
  event = document.createEvent("CustomEvent");
55
- event.initCustomEvent(namespacedName, true, true, detail!);
57
+ event.initCustomEvent(namespacedName, true, true, detail);
56
58
  }
57
59
  (optionalElement || this.element).dispatchEvent(event);
58
60
  return event;
@@ -66,11 +68,13 @@ export interface ControllerDefinition {
66
68
  targets?: string[];
67
69
  }
68
70
  export function createController(controllerDefinition: ControllerDefinition): typeof StacksController {
71
+ // eslint-disable-next-line no-prototype-builtins
69
72
  const Controller = controllerDefinition.hasOwnProperty("targets")
70
73
  ? class Controller extends StacksController { static targets = controllerDefinition.targets! }
71
74
  : class Controller extends StacksController {};
72
75
 
73
- for (var prop in controllerDefinition) {
76
+ for (const prop in controllerDefinition) {
77
+ // eslint-disable-next-line no-prototype-builtins
74
78
  if (prop !== "targets" && controllerDefinition.hasOwnProperty(prop)) {
75
79
  Object.defineProperty(
76
80
  Controller.prototype,
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "type": "git",
6
6
  "url": "https://github.com/StackExchange/Stacks.git"
7
7
  },
8
- "version": "1.1.0",
8
+ "version": "1.3.1",
9
9
  "files": [
10
10
  "dist",
11
11
  "lib"
@@ -30,42 +30,42 @@
30
30
  },
31
31
  "license": "MIT",
32
32
  "dependencies": {
33
- "@popperjs/core": "^2.11.5",
33
+ "@popperjs/core": "^2.11.6",
34
34
  "stimulus": "^2.0.0"
35
35
  },
36
36
  "devDependencies": {
37
- "@11ty/eleventy": "^1.0.1",
38
- "@highlightjs/cdn-assets": "^11.5.1",
39
- "@stackoverflow/stacks-editor": "^0.4.2",
40
- "@stackoverflow/stacks-icons": "^2.27.0",
41
- "@typescript-eslint/eslint-plugin": "^5.22.0",
42
- "@typescript-eslint/parser": "^5.22.0",
43
- "backstopjs": "^6.0.4",
44
- "concurrently": "^7.1.0",
37
+ "@11ty/eleventy": "^1.0.2",
38
+ "@highlightjs/cdn-assets": "^11.6.0",
39
+ "@stackoverflow/stacks-editor": "^0.7.0",
40
+ "@stackoverflow/stacks-icons": "^3.0.2",
41
+ "@typescript-eslint/eslint-plugin": "^5.35.1",
42
+ "@typescript-eslint/parser": "^5.35.1",
43
+ "backstopjs": "^6.1.1",
44
+ "concurrently": "^7.3.0",
45
45
  "css-loader": "^6.7.1",
46
- "cssnano": "^5.1.7",
46
+ "cssnano": "^5.1.13",
47
47
  "docsearch.js": "^2.6.3",
48
48
  "eleventy-plugin-highlightjs": "^1.1.0",
49
49
  "eleventy-plugin-nesting-toc": "^1.3.0",
50
- "eslint": "^8.15.0",
50
+ "eslint": "^8.23.0",
51
51
  "eslint-config-prettier": "^8.5.0",
52
52
  "eslint-plugin-no-unsanitized": "^4.0.1",
53
- "jquery": "^3.6.0",
54
- "less-loader": "^10.2.0",
53
+ "jquery": "^3.6.1",
54
+ "less-loader": "^11.0.0",
55
55
  "list.js": "^2.3.1",
56
56
  "markdown-it": "^13.0.1",
57
- "mini-css-extract-plugin": "^2.6.0",
57
+ "mini-css-extract-plugin": "^2.6.1",
58
58
  "postcss-less": "^6.0.0",
59
- "postcss-loader": "^6.2.1",
60
- "prettier": "^2.6.2",
61
- "stylelint": "^14.8.2",
62
- "stylelint-config-recommended": "^7.0.0",
63
- "stylelint-config-standard": "^25.0.0",
64
- "terser-webpack-plugin": "^5.3.1",
65
- "ts-loader": "^9.3.0",
66
- "typescript": "^4.6.4",
67
- "webpack": "^5.72.0",
68
- "webpack-cli": "^4.9.2",
59
+ "postcss-loader": "^7.0.1",
60
+ "prettier": "^2.7.1",
61
+ "stylelint": "^14.11.0",
62
+ "stylelint-config-recommended": "^9.0.0",
63
+ "stylelint-config-standard": "^28.0.0",
64
+ "terser-webpack-plugin": "^5.3.5",
65
+ "ts-loader": "^9.3.1",
66
+ "typescript": "^4.8.2",
67
+ "webpack": "^5.74.0",
68
+ "webpack-cli": "^4.10.0",
69
69
  "webpack-merge": "^5.8.0"
70
70
  },
71
71
  "browserslist": [
@@ -1,80 +0,0 @@
1
- //
2
- // STACK OVERFLOW
3
- // BANNERS
4
- //
5
- // This CSS comes from Stacks, our CSS & Pattern library for rapidly building
6
- // Stack Overflow. For documentation of all these classes and how to contribute,
7
- // visit https://stackoverflow.design/
8
- //
9
- // TABLE OF CONTENTS
10
- // • SYSTEM BANNERS
11
- //
12
- // ============================================================================
13
- // When we use .s-banner, we need to adjust the padding-top on
14
- // the body tag. This class correctly adjusts the body padding ONLY if
15
- // the notice is one line. If it wraps to multiple lines, more classes or
16
- // (ideally) JS will need to be used to determine the notice's height
17
- // at the time of render. The padding value is determined like so:
18
- //
19
- // 50px (top bar) + 44px (notice height) - 1px (bottom border)
20
- //
21
- // The borders subtraction are necessary to neatly tuck everything together.
22
- // ----------------------------------------------------------------------------
23
- .s-banner__body-pt {
24
- padding-top: 93px;
25
- }
26
-
27
- // ============================================================================
28
- // $ SYSTEM BANNERS
29
- // ----------------------------------------------------------------------------
30
- .s-banner {
31
- position: fixed;
32
- z-index: calc(var(--zi-navigation-fixed) - 1); // Tuck below topbar
33
- top: 0;
34
- right: 0;
35
- left: 0;
36
- width: 100%;
37
- padding: var(--su12);
38
- border-top: 1px solid transparent;
39
- border-bottom: 1px solid transparent;
40
- border-radius: 0;
41
- box-shadow: none;
42
- color: var(--fc-medium);
43
- font-size: var(--fs-body1);
44
-
45
- // If you want to hide and reveal the banner
46
- &[aria-hidden="true"] {
47
- visibility: hidden;
48
- opacity: 0;
49
- -webkit-transform: translate3d(0, -50px, 0);
50
- transform: translate3d(0, -50px, 0);
51
- }
52
-
53
- &[aria-hidden="false"] {
54
- visibility: visible;
55
- opacity: 1;
56
- -webkit-transform: translate3d(0, 49px, 0);
57
- transform: translate3d(0, 49px, 0);
58
- }
59
-
60
- // If you want to put the banner above the topbar
61
- &.is-pinned {
62
- z-index: calc(var(--zi-navigation-fixed) + 1);
63
- -webkit-transform: translate3d(0, 0, 0);
64
- transform: translate3d(0, 0, 0);
65
- }
66
-
67
- // If it's a really important banner
68
- &.s-banner__important {
69
- border-color: transparent;
70
- color: var(--white);
71
- }
72
- }
73
-
74
- // -- When we want to keep hero content capped
75
- .s-banner--container {
76
- position: relative;
77
- width: 100%;
78
- max-width: calc(var(--s-step) * 10);
79
- margin: 0 auto;
80
- }
@@ -1,26 +0,0 @@
1
- //
2
- // STACK OVERFLOW
3
- // EMPTY STATES
4
- //
5
- // This CSS comes from Stacks, our CSS & Pattern library for rapidly building
6
- // Stack Overflow. For documentation of all these classes and how to contribute,
7
- // visit https://stackoverflow.design/
8
- //
9
- // ============================================================================
10
- // $ BASE STYLE
11
- // ----------------------------------------------------------------------------
12
- .s-empty-state {
13
- color: var(--fc-light);
14
- text-align: center;
15
- margin-left: auto;
16
- margin-right: auto;
17
-
18
- p {
19
- font-size: var(--fs-body1);
20
- margin-bottom: var(--su12);
21
-
22
- strong {
23
- color: var(--fc-dark);
24
- }
25
- }
26
- }