diff --git a/.changeset/thin-buttons-appear.md b/.changeset/thin-buttons-appear.md new file mode 100644 index 000000000..a0a86429e --- /dev/null +++ b/.changeset/thin-buttons-appear.md @@ -0,0 +1,5 @@ +--- +'@guardian/source': minor +--- + +generate CSS/SCSS files for typography, palette, breakpoints diff --git a/libs/@guardian/source/package.json b/libs/@guardian/source/package.json index 3b25d3029..b609f4049 100644 --- a/libs/@guardian/source/package.json +++ b/libs/@guardian/source/package.json @@ -10,6 +10,9 @@ "import": "./dist/foundations.js", "require": "./dist/foundations.cjs" }, + "./foundations/breakpoints.scss": "./dist/foundations/__generated__/breakpoints.scss", + "./foundations/palette.css": "./dist/foundations/__generated__/palette.css", + "./foundations/typography.css": "./dist/foundations/__generated__/typography.css", "./react-components": { "types": "./dist/react-components.d.ts", "import": "./dist/react-components.js", @@ -67,10 +70,13 @@ "jest": "30.0.5", "lightningcss": "1.30.0", "mkdirp": "3.0.1", + "postcss": "8.5.6", + "postcss-scss": "4.0.9", "prettier": "3.3.3", "react": "18.2.0", "react-dom": "18.2.0", "rollup": "4.50.1", + "rollup-plugin-copy": "3.5.0", "storybook": "8.6.4", "ts-jest": "29.4.0", "tslib": "2.6.2", diff --git a/libs/@guardian/source/rollup.config.js b/libs/@guardian/source/rollup.config.js index 2c673c1e7..54fd7e0b5 100644 --- a/libs/@guardian/source/rollup.config.js +++ b/libs/@guardian/source/rollup.config.js @@ -1,3 +1,4 @@ +import copy from 'rollup-plugin-copy'; import config from '../../../configs/rollup/rollup.config.js'; export default config({ @@ -5,4 +6,14 @@ export default config({ foundations: 'src/foundations/index.ts', 'react-components': 'src/react-components/index.ts', }, + plugins: [ + copy({ + targets: [ + { + src: 'src/foundations/__generated__/*.{scss,css}', + dest: 'dist/foundations/__generated__', + }, + ], + }), + ], }); diff --git a/libs/@guardian/source/src/design-tokens/cobalt-plugins/breakpoints/scss.js b/libs/@guardian/source/src/design-tokens/cobalt-plugins/breakpoints/scss.js new file mode 100644 index 000000000..bb8ba42d0 --- /dev/null +++ b/libs/@guardian/source/src/design-tokens/cobalt-plugins/breakpoints/scss.js @@ -0,0 +1,59 @@ +/* eslint-disable import/no-default-export -- cobalt plugins do this */ + +// @ts-check + +import { defaultTransformer } from '@cobalt-ui/plugin-js'; +import { set } from '@cobalt-ui/utils'; +import { template } from '../../lib/template.js'; + +/** + * @param {{ filename: string; }} options + * @returns {import('@cobalt-ui/core').Plugin} + */ +export default function pluginBreakpointsScss(options) { + return { + name: 'plugin-breakpoints-scss', + + config(/* config */) {}, + async build({ tokens /*, rawSchema, metadata */ }) { + const TOKEN_GROUP = 'breakpoint'; + + const breakpointTokens = tokens.filter((token) => + token.id.startsWith(TOKEN_GROUP), + ); + + /** + * @type {Object.} + */ + const transformedTokens = {}; + + // we can re-use the default transformer from `@cobalt-ui/plugin-js` + for (const token of breakpointTokens) { + set(transformedTokens, token.id, defaultTransformer(token)); + } + + const breakpointPairs = []; + + for (const breakpoints of Object.values(transformedTokens)) { + for (const [name, value] of Object.entries(breakpoints)) { + breakpointPairs.push({ name, value }); + } + } + + breakpointPairs.sort((a, b) => parseFloat(a.value) - parseFloat(b.value)); + + const breakpointEntries = breakpointPairs.map( + ({ name, value }) => `\t${name}: ${value},`, + ); + + const scssSource = `$breakpoints: (\n${breakpointEntries.join('\n')}\n);`; + + return [ + { + filename: options.filename, + contents: template(import.meta.filename, scssSource), + }, + ]; + }, + }; +} diff --git a/libs/@guardian/source/src/design-tokens/cobalt-plugins/breakpoints.js b/libs/@guardian/source/src/design-tokens/cobalt-plugins/breakpoints/typescript.js similarity index 89% rename from libs/@guardian/source/src/design-tokens/cobalt-plugins/breakpoints.js rename to libs/@guardian/source/src/design-tokens/cobalt-plugins/breakpoints/typescript.js index 18cebb977..a4fe757a9 100644 --- a/libs/@guardian/source/src/design-tokens/cobalt-plugins/breakpoints.js +++ b/libs/@guardian/source/src/design-tokens/cobalt-plugins/breakpoints/typescript.js @@ -4,9 +4,9 @@ import { defaultTransformer, serializeJS } from '@cobalt-ui/plugin-js'; import { set } from '@cobalt-ui/utils'; -import { pxStringToNumber } from '../lib/convert-value.js'; -import { getCommentId } from '../lib/get-comment-id.js'; -import { template } from '../lib/template.js'; +import { pxStringToNumber } from '../../lib/convert-value.js'; +import { getCommentId } from '../../lib/get-comment-id.js'; +import { template } from '../../lib/template.js'; /** * @param {{ filename: string; }} options @@ -14,7 +14,7 @@ import { template } from '../lib/template.js'; */ export default function pluginBreakpoints(options) { return { - name: 'plugin-breakpoints', + name: 'plugin-breakpoints-typescript', config(/* config */) {}, async build({ tokens, rawSchema /*, metadata */ }) { diff --git a/libs/@guardian/source/src/design-tokens/cobalt-plugins/palette/css.js b/libs/@guardian/source/src/design-tokens/cobalt-plugins/palette/css.js new file mode 100644 index 000000000..b1750afb8 --- /dev/null +++ b/libs/@guardian/source/src/design-tokens/cobalt-plugins/palette/css.js @@ -0,0 +1,66 @@ +/* eslint-disable import/no-default-export -- cobalt plugins do this */ + +// @ts-check + +import { defaultTransformer } from '@cobalt-ui/plugin-js'; +import { set } from '@cobalt-ui/utils'; +import { camelToKebab } from '../../lib/case.js'; +import { template } from '../../lib/template.js'; + +/** + * @param {string[]} variableDecls eg. ["--src-brand-100: #001536;", "--src-brand-300: #041F4A;"] + * + * NOTE: we don't bother with proper indentation here, prettier will sort that out at build + */ +const cssTemplate = (variableDecls) => `:root { ${variableDecls.join('\n')} } +`; + +/** + * @param {{ filename: string; }} options + * @returns {import('@cobalt-ui/core').Plugin} + */ +export default function pluginPaletteCss(options) { + return { + name: 'plugin-palette-css', + + config(/* config */) {}, + async build({ tokens /*, rawSchema, metadata */ }) { + const TOKEN_GROUP = 'palette'; + + /** @type {Object.} */ + const transformedTokens = {}; + + const paletteTokens = tokens.filter((token) => + token.id.startsWith(TOKEN_GROUP), + ); + + // we can re-use the default transformer from `@cobalt-ui/plugin-js` + for (const token of paletteTokens) { + set(transformedTokens, token.id, defaultTransformer(token)); + } + + const cssVariablesDecls = []; + + for (const tokens of Object.values(transformedTokens)) { + // eg. [ "brand", { "100": "#001536", "300": "#041F4A", ... } ] + for (const [category, shades] of Object.entries(tokens)) { + // eg. [ "100", "#001536" ] + for (const [shade, color] of Object.entries(shades)) { + const varName = `--src-${camelToKebab(category)}-${shade}`; + cssVariablesDecls.push(`\t${varName}: ${color};`); + } + } + } + + return [ + { + filename: options.filename, + contents: template( + import.meta.filename, + cssTemplate(cssVariablesDecls), + ), + }, + ]; + }, + }; +} diff --git a/libs/@guardian/source/src/design-tokens/cobalt-plugins/palette.js b/libs/@guardian/source/src/design-tokens/cobalt-plugins/palette/typescript.js similarity index 91% rename from libs/@guardian/source/src/design-tokens/cobalt-plugins/palette.js rename to libs/@guardian/source/src/design-tokens/cobalt-plugins/palette/typescript.js index afa252edf..74c08acfd 100644 --- a/libs/@guardian/source/src/design-tokens/cobalt-plugins/palette.js +++ b/libs/@guardian/source/src/design-tokens/cobalt-plugins/palette/typescript.js @@ -4,8 +4,8 @@ import { defaultTransformer, serializeJS } from '@cobalt-ui/plugin-js'; import { set } from '@cobalt-ui/utils'; -import { getCommentId } from '../lib/get-comment-id.js'; -import { template } from '../lib/template.js'; +import { getCommentId } from '../../lib/get-comment-id.js'; +import { template } from '../../lib/template.js'; /** * @param {{ filename: string; }} options @@ -13,7 +13,7 @@ import { template } from '../lib/template.js'; */ export default function pluginPalette(options) { return { - name: 'plugin-palette', + name: 'plugin-palette-typescript', config(/* config */) {}, async build({ tokens, rawSchema /*, metadata */ }) { diff --git a/libs/@guardian/source/src/design-tokens/cobalt-plugins/typography/common.js b/libs/@guardian/source/src/design-tokens/cobalt-plugins/typography/common.js new file mode 100644 index 000000000..12512ab7a --- /dev/null +++ b/libs/@guardian/source/src/design-tokens/cobalt-plugins/typography/common.js @@ -0,0 +1,19 @@ +/** @param {string} fontSize */ +export const textDecorationThickness = (fontSize) => { + switch (fontSize) { + case '20px': + case '24px': + case '28px': + return '3px'; + case '34px': + return '4px'; + case '42px': + return '5px'; + case '50px': + case '64px': + case '70px': + return '6px'; + default: + return '2px'; + } +}; diff --git a/libs/@guardian/source/src/design-tokens/cobalt-plugins/typography/css.js b/libs/@guardian/source/src/design-tokens/cobalt-plugins/typography/css.js new file mode 100644 index 000000000..b67263d05 --- /dev/null +++ b/libs/@guardian/source/src/design-tokens/cobalt-plugins/typography/css.js @@ -0,0 +1,85 @@ +/* eslint-disable import/no-default-export -- cobalt plugins do this */ + +// @ts-check + +import { defaultTransformer } from '@cobalt-ui/plugin-js'; +import { set } from '@cobalt-ui/utils'; +import { camelToKebab } from '../../lib/case.js'; +import { fontArrayToString, pxStringToRem } from '../../lib/convert-value.js'; +import { template } from '../../lib/template.js'; +import { textDecorationThickness } from './common.js'; + +/** + * @typedef {Object} TypographyPreset + * @property {string[]} fontFamily + * @property {string} fontSize + * @property {number} lineHeight + * @property {number} fontWeight + * @property {string} fontStyle + */ + +const GROUP_PREFIX = 'typographyPresets.'; + +/** + * Converts eg. "headlineBold24" to "src-headline-bold-24" + * + * @param {string} presetName + */ +const classNameFromPreset = (presetName) => { + return `.src-${camelToKebab(presetName).replace(/(\d+)$/, '-$1')}`; +}; + +/** + * + * @param {string} preset + * @param {TypographyPreset} properties + */ +const presetClass = (preset, properties) => `${classNameFromPreset(preset)} { + font-family: ${fontArrayToString(properties.fontFamily)}; + font-size: ${pxStringToRem(properties.fontSize)}; + line-height: ${properties.lineHeight}; + font-weight: ${properties.fontWeight}; + font-style: ${properties.fontStyle}; + --source-text-decoration-thickness: ${textDecorationThickness(properties.fontSize)}; +}`; + +/** + * @param {{ filename: string; }} options + * @returns {import('@cobalt-ui/core').Plugin} + */ +export default function pluginTypographyCss(options) { + return { + name: 'plugin-typography-css', + + config(/* config */) {}, + async build({ tokens /* metadata, rawSchema */ }) { + /** @type {Object.} */ + const transformedTokens = {}; + + const typographyTokens = tokens.filter((token) => + token.id.startsWith(GROUP_PREFIX), + ); + + // we can re-use the default transformer from `@cobalt-ui/plugin-js` + for (const token of typographyTokens) { + set(transformedTokens, token.id, defaultTransformer(token)); + } + + /** @type {Object.} */ + const typographyPresets = transformedTokens.typographyPresets; + + const cssClasses = Object.entries(typographyPresets) + .map(([preset, properties]) => presetClass(preset, properties)) + .join('\n\n'); + + const cssSource = cssClasses; + + return [ + { + filename: options.filename, + contents: template(import.meta.filename, cssSource), + }, + ]; + }, + }; +} diff --git a/libs/@guardian/source/src/design-tokens/cobalt-plugins/typography.js b/libs/@guardian/source/src/design-tokens/cobalt-plugins/typography/typescript.js similarity index 82% rename from libs/@guardian/source/src/design-tokens/cobalt-plugins/typography.js rename to libs/@guardian/source/src/design-tokens/cobalt-plugins/typography/typescript.js index a8eb3f859..165cdfee0 100644 --- a/libs/@guardian/source/src/design-tokens/cobalt-plugins/typography.js +++ b/libs/@guardian/source/src/design-tokens/cobalt-plugins/typography/typescript.js @@ -4,31 +4,10 @@ import { defaultTransformer } from '@cobalt-ui/plugin-js'; import { set } from '@cobalt-ui/utils'; -import { fontArrayToString, pxStringToRem } from '../lib/convert-value.js'; -import { getCommentId } from '../lib/get-comment-id.js'; -import { template } from '../lib/template.js'; - -const GROUP_PREFIX = 'typographyPresets.'; - -/** @param {string} fontSize */ -const textDecorationThickness = (fontSize) => { - switch (fontSize) { - case '20px': - case '24px': - case '28px': - return '3px'; - case '34px': - return '4px'; - case '42px': - return '5px'; - case '50px': - case '64px': - case '70px': - return '6px'; - default: - return '2px'; - } -}; +import { fontArrayToString, pxStringToRem } from '../../lib/convert-value.js'; +import { getCommentId } from '../../lib/get-comment-id.js'; +import { template } from '../../lib/template.js'; +import { textDecorationThickness } from './common.js'; /** * @typedef {Object} TypographyPreset @@ -39,6 +18,8 @@ const textDecorationThickness = (fontSize) => { * @property {string} fontStyle */ +const GROUP_PREFIX = 'typographyPresets.'; + /** * * @param {string} preset @@ -69,7 +50,7 @@ export const ${preset}Object = { */ export default function pluginBreakpoints(options) { return { - name: 'plugin-typography', + name: 'plugin-typography-typescript', config(/* config */) {}, async build({ tokens /* metadata, rawSchema */ }) { diff --git a/libs/@guardian/source/src/design-tokens/lib/case.js b/libs/@guardian/source/src/design-tokens/lib/case.js new file mode 100644 index 000000000..25d1b7a2b --- /dev/null +++ b/libs/@guardian/source/src/design-tokens/lib/case.js @@ -0,0 +1,6 @@ +/** + * Convert camelCase to kebab-case + * @param {string} str + */ +export const camelToKebab = (str) => + str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase(); diff --git a/libs/@guardian/source/src/design-tokens/tokens.config.js b/libs/@guardian/source/src/design-tokens/tokens.config.js index cb2260db8..2e682f674 100644 --- a/libs/@guardian/source/src/design-tokens/tokens.config.js +++ b/libs/@guardian/source/src/design-tokens/tokens.config.js @@ -8,11 +8,14 @@ // @ts-check import pluginCSS, { defaultNameGenerator } from '@cobalt-ui/plugin-css'; -import breakpoints from './cobalt-plugins/breakpoints.js'; -import palette from './cobalt-plugins/palette.js'; +import breakpointsScss from './cobalt-plugins/breakpoints/scss.js'; +import breakpoints from './cobalt-plugins/breakpoints/typescript.js'; +import paletteCss from './cobalt-plugins/palette/css.js'; +import palette from './cobalt-plugins/palette/typescript.js'; import size from './cobalt-plugins/size.js'; import space from './cobalt-plugins/space.js'; -import typography from './cobalt-plugins/typography.js'; +import typographyCss from './cobalt-plugins/typography/css.js'; +import typography from './cobalt-plugins/typography/typescript.js'; /** * @param {string} variableId @@ -37,10 +40,17 @@ export default { outDir: '../foundations/__generated__', plugins: [ palette({ filename: 'palette.ts' }), + paletteCss({ filename: 'palette.css' }), + breakpoints({ filename: 'breakpoints.ts' }), + breakpointsScss({ filename: 'breakpoints.scss' }), + typography({ filename: 'typography.ts' }), + typographyCss({ filename: 'typography.css' }), + space({ filename: 'space.ts' }), size({ filename: 'size.ts' }), + pluginCSS({ p3: false, generateName: prefixCustomProperty, diff --git a/libs/@guardian/source/src/foundations/__generated__/breakpoints.scss b/libs/@guardian/source/src/foundations/__generated__/breakpoints.scss new file mode 100644 index 000000000..f1d4f4e0a --- /dev/null +++ b/libs/@guardian/source/src/foundations/__generated__/breakpoints.scss @@ -0,0 +1,18 @@ +/* +* DO NOT EDIT THIS FILE DIRECTLY! +* +* It was auto-generated by design-tokens/plugins/scss.js. +* +* Update design-tokens/tokens.json and (re)build @guardian/source instead. +*/ + +$breakpoints: ( + mobile: 320px, + mobileMedium: 375px, + mobileLandscape: 480px, + phablet: 660px, + tablet: 740px, + desktop: 980px, + leftCol: 1140px, + wide: 1300px, +); diff --git a/libs/@guardian/source/src/foundations/__generated__/breakpoints.ts b/libs/@guardian/source/src/foundations/__generated__/breakpoints.ts index 560fb5a39..e32e219de 100644 --- a/libs/@guardian/source/src/foundations/__generated__/breakpoints.ts +++ b/libs/@guardian/source/src/foundations/__generated__/breakpoints.ts @@ -1,7 +1,7 @@ /* * DO NOT EDIT THIS FILE DIRECTLY! * - * It was auto-generated by design-tokens/plugins/breakpoints.js. + * It was auto-generated by design-tokens/plugins/typescript.js. * * Update design-tokens/tokens.json and (re)build @guardian/source instead. */ diff --git a/libs/@guardian/source/src/foundations/__generated__/palette.css b/libs/@guardian/source/src/foundations/__generated__/palette.css new file mode 100644 index 000000000..69549cae1 --- /dev/null +++ b/libs/@guardian/source/src/foundations/__generated__/palette.css @@ -0,0 +1,104 @@ +/* +* DO NOT EDIT THIS FILE DIRECTLY! +* +* It was auto-generated by design-tokens/plugins/css.js. +* +* Update design-tokens/tokens.json and (re)build @guardian/source instead. +*/ + +:root { + --src-brand-100: #001536; + --src-brand-300: #041f4a; + --src-brand-400: #052962; + --src-brand-500: #0077b6; + --src-brand-600: #506991; + --src-brand-800: #c1d8fc; + --src-brand-alt-200: #f3c100; + --src-brand-alt-300: #ffd900; + --src-brand-alt-400: #ffe500; + --src-culture-50: #2b2625; + --src-culture-100: #3e3323; + --src-culture-200: #574835; + --src-culture-300: #6b5840; + --src-culture-350: #866d50; + --src-culture-400: #866d50; + --src-culture-450: #a1845c; + --src-culture-500: #eacca0; + --src-culture-600: #e7d4b9; + --src-culture-700: #efe8dd; + --src-culture-800: #fbf6ef; + --src-error-400: #c70000; + --src-error-500: #ff9081; + --src-focus-400: #0077b6; + --src-labs-100: #09615b; + --src-labs-200: #0c7a73; + --src-labs-300: #65a897; + --src-labs-400: #69d1ca; + --src-labs-500: #a8e3df; + --src-labs-600: #dcf4f3; + --src-labs-700: #f3fbfb; + --src-lifestyle-100: #510043; + --src-lifestyle-200: #650054; + --src-lifestyle-300: #7d0068; + --src-lifestyle-400: #bb3b80; + --src-lifestyle-450: #f37abc; + --src-lifestyle-500: #ffabdb; + --src-lifestyle-600: #fec8d3; + --src-lifestyle-800: #fef1f8; + --src-neutral-0: #000000; + --src-neutral-7: #121212; + --src-neutral-10: #1a1a1a; + --src-neutral-20: #333333; + --src-neutral-38: #545454; + --src-neutral-46: #707070; + --src-neutral-60: #999999; + --src-neutral-73: #bababa; + --src-neutral-86: #dcdcdc; + --src-neutral-93: #ededed; + --src-neutral-97: #f6f6f6; + --src-neutral-100: #ffffff; + --src-news-100: #660505; + --src-news-200: #8b0000; + --src-news-300: #ab0613; + --src-news-400: #c70000; + --src-news-500: #ff5943; + --src-news-550: #ff9081; + --src-news-600: #ffbac8; + --src-news-700: #ffd8d1; + --src-news-800: #fff4f2; + --src-notification-blue-400: #0190f7; + --src-opinion-100: #672005; + --src-opinion-200: #8d2700; + --src-opinion-300: #c74600; + --src-opinion-400: #c74600; + --src-opinion-450: #e05e00; + --src-opinion-500: #ff7f0f; + --src-opinion-550: #ff9941; + --src-opinion-600: #f9b376; + --src-opinion-700: #ffe7d4; + --src-opinion-800: #fef9f5; + --src-special-report-100: #222527; + --src-special-report-200: #303538; + --src-special-report-300: #3f464a; + --src-special-report-400: #595c5f; + --src-special-report-450: #9da0a2; + --src-special-report-500: #abc2c9; + --src-special-report-700: #e4e5e8; + --src-special-report-800: #eff1f2; + --src-special-report-alt-100: #2b2b2a; + --src-special-report-alt-200: #b9300a; + --src-special-report-alt-300: #ff663d; + --src-special-report-alt-700: #ebe6e1; + --src-special-report-alt-800: #f5f0eb; + --src-sport-100: #003c60; + --src-sport-200: #004e7c; + --src-sport-300: #005689; + --src-sport-400: #0077b6; + --src-sport-500: #00b2ff; + --src-sport-600: #90dcff; + --src-sport-700: #d8f1ff; + --src-sport-800: #f1f8fc; + --src-success-300: #185e36; + --src-success-400: #22874d; + --src-success-500: #58d08b; +} diff --git a/libs/@guardian/source/src/foundations/__generated__/palette.ts b/libs/@guardian/source/src/foundations/__generated__/palette.ts index 14ddd4408..73dcc2028 100644 --- a/libs/@guardian/source/src/foundations/__generated__/palette.ts +++ b/libs/@guardian/source/src/foundations/__generated__/palette.ts @@ -1,7 +1,7 @@ /* * DO NOT EDIT THIS FILE DIRECTLY! * - * It was auto-generated by design-tokens/plugins/palette.js. + * It was auto-generated by design-tokens/plugins/typescript.js. * * Update design-tokens/tokens.json and (re)build @guardian/source instead. */ diff --git a/libs/@guardian/source/src/foundations/__generated__/typography.css b/libs/@guardian/source/src/foundations/__generated__/typography.css new file mode 100644 index 000000000..9cf6d65fb --- /dev/null +++ b/libs/@guardian/source/src/foundations/__generated__/typography.css @@ -0,0 +1,924 @@ +/* +* DO NOT EDIT THIS FILE DIRECTLY! +* +* It was auto-generated by design-tokens/plugins/css.js. +* +* Update design-tokens/tokens.json and (re)build @guardian/source instead. +*/ + +.src-article-15 { + font-family: GuardianTextEgyptian, 'Guardian Text Egyptian Web', Georgia, + serif; + font-size: 0.9375rem; + line-height: 1.4; + font-weight: 400; + font-style: normal; + --source-text-decoration-thickness: 2px; +} + +.src-article-17 { + font-family: GuardianTextEgyptian, 'Guardian Text Egyptian Web', Georgia, + serif; + font-size: 1.0625rem; + line-height: 1.4; + font-weight: 400; + font-style: normal; + --source-text-decoration-thickness: 2px; +} + +.src-article-bold-15 { + font-family: GuardianTextEgyptian, 'Guardian Text Egyptian Web', Georgia, + serif; + font-size: 0.9375rem; + line-height: 1.4; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 2px; +} + +.src-article-bold-17 { + font-family: GuardianTextEgyptian, 'Guardian Text Egyptian Web', Georgia, + serif; + font-size: 1.0625rem; + line-height: 1.4; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 2px; +} + +.src-article-bold-italic-15 { + font-family: GuardianTextEgyptian, 'Guardian Text Egyptian Web', Georgia, + serif; + font-size: 0.9375rem; + line-height: 1.4; + font-weight: 700; + font-style: italic; + --source-text-decoration-thickness: 2px; +} + +.src-article-bold-italic-17 { + font-family: GuardianTextEgyptian, 'Guardian Text Egyptian Web', Georgia, + serif; + font-size: 1.0625rem; + line-height: 1.4; + font-weight: 700; + font-style: italic; + --source-text-decoration-thickness: 2px; +} + +.src-article-italic-15 { + font-family: GuardianTextEgyptian, 'Guardian Text Egyptian Web', Georgia, + serif; + font-size: 0.9375rem; + line-height: 1.4; + font-weight: 400; + font-style: italic; + --source-text-decoration-thickness: 2px; +} + +.src-article-italic-17 { + font-family: GuardianTextEgyptian, 'Guardian Text Egyptian Web', Georgia, + serif; + font-size: 1.0625rem; + line-height: 1.4; + font-weight: 400; + font-style: italic; + --source-text-decoration-thickness: 2px; +} + +.src-headline-bold-14 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 0.875rem; + line-height: 1.15; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 2px; +} + +.src-headline-bold-15 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 0.9375rem; + line-height: 1.15; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 2px; +} + +.src-headline-bold-17 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 1.0625rem; + line-height: 1.15; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 2px; +} + +.src-headline-bold-20 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 1.25rem; + line-height: 1.15; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 3px; +} + +.src-headline-bold-24 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 1.5rem; + line-height: 1.15; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 3px; +} + +.src-headline-bold-28 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 1.75rem; + line-height: 1.15; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 3px; +} + +.src-headline-bold-34 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 2.125rem; + line-height: 1.15; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 4px; +} + +.src-headline-bold-42 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 2.625rem; + line-height: 1.15; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 5px; +} + +.src-headline-bold-50 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 3.125rem; + line-height: 1.15; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 6px; +} + +.src-headline-bold-64 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 4rem; + line-height: 1.15; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 6px; +} + +.src-headline-light-14 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 0.875rem; + line-height: 1.15; + font-weight: 300; + font-style: normal; + --source-text-decoration-thickness: 2px; +} + +.src-headline-light-15 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 0.9375rem; + line-height: 1.15; + font-weight: 300; + font-style: normal; + --source-text-decoration-thickness: 2px; +} + +.src-headline-light-17 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 1.0625rem; + line-height: 1.15; + font-weight: 300; + font-style: normal; + --source-text-decoration-thickness: 2px; +} + +.src-headline-light-20 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 1.25rem; + line-height: 1.15; + font-weight: 300; + font-style: normal; + --source-text-decoration-thickness: 3px; +} + +.src-headline-light-24 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 1.5rem; + line-height: 1.15; + font-weight: 300; + font-style: normal; + --source-text-decoration-thickness: 3px; +} + +.src-headline-light-28 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 1.75rem; + line-height: 1.15; + font-weight: 300; + font-style: normal; + --source-text-decoration-thickness: 3px; +} + +.src-headline-light-34 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 2.125rem; + line-height: 1.15; + font-weight: 300; + font-style: normal; + --source-text-decoration-thickness: 4px; +} + +.src-headline-light-42 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 2.625rem; + line-height: 1.15; + font-weight: 300; + font-style: normal; + --source-text-decoration-thickness: 5px; +} + +.src-headline-light-50 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 3.125rem; + line-height: 1.15; + font-weight: 300; + font-style: normal; + --source-text-decoration-thickness: 6px; +} + +.src-headline-light-64 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 4rem; + line-height: 1.15; + font-weight: 300; + font-style: normal; + --source-text-decoration-thickness: 6px; +} + +.src-headline-light-italic-14 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 0.875rem; + line-height: 1.15; + font-weight: 300; + font-style: italic; + --source-text-decoration-thickness: 2px; +} + +.src-headline-light-italic-15 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 0.9375rem; + line-height: 1.15; + font-weight: 300; + font-style: italic; + --source-text-decoration-thickness: 2px; +} + +.src-headline-light-italic-17 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 1.0625rem; + line-height: 1.15; + font-weight: 300; + font-style: italic; + --source-text-decoration-thickness: 2px; +} + +.src-headline-light-italic-20 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 1.25rem; + line-height: 1.15; + font-weight: 300; + font-style: italic; + --source-text-decoration-thickness: 3px; +} + +.src-headline-light-italic-24 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 1.5rem; + line-height: 1.15; + font-weight: 300; + font-style: italic; + --source-text-decoration-thickness: 3px; +} + +.src-headline-light-italic-28 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 1.75rem; + line-height: 1.15; + font-weight: 300; + font-style: italic; + --source-text-decoration-thickness: 3px; +} + +.src-headline-light-italic-34 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 2.125rem; + line-height: 1.15; + font-weight: 300; + font-style: italic; + --source-text-decoration-thickness: 4px; +} + +.src-headline-light-italic-42 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 2.625rem; + line-height: 1.15; + font-weight: 300; + font-style: italic; + --source-text-decoration-thickness: 5px; +} + +.src-headline-light-italic-50 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 3.125rem; + line-height: 1.15; + font-weight: 300; + font-style: italic; + --source-text-decoration-thickness: 6px; +} + +.src-headline-light-italic-64 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 4rem; + line-height: 1.15; + font-weight: 300; + font-style: italic; + --source-text-decoration-thickness: 6px; +} + +.src-headline-medium-14 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 0.875rem; + line-height: 1.15; + font-weight: 500; + font-style: normal; + --source-text-decoration-thickness: 2px; +} + +.src-headline-medium-15 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 0.9375rem; + line-height: 1.15; + font-weight: 500; + font-style: normal; + --source-text-decoration-thickness: 2px; +} + +.src-headline-medium-17 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 1.0625rem; + line-height: 1.15; + font-weight: 500; + font-style: normal; + --source-text-decoration-thickness: 2px; +} + +.src-headline-medium-20 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 1.25rem; + line-height: 1.15; + font-weight: 500; + font-style: normal; + --source-text-decoration-thickness: 3px; +} + +.src-headline-medium-24 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 1.5rem; + line-height: 1.15; + font-weight: 500; + font-style: normal; + --source-text-decoration-thickness: 3px; +} + +.src-headline-medium-28 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 1.75rem; + line-height: 1.15; + font-weight: 500; + font-style: normal; + --source-text-decoration-thickness: 3px; +} + +.src-headline-medium-34 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 2.125rem; + line-height: 1.15; + font-weight: 500; + font-style: normal; + --source-text-decoration-thickness: 4px; +} + +.src-headline-medium-42 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 2.625rem; + line-height: 1.15; + font-weight: 500; + font-style: normal; + --source-text-decoration-thickness: 5px; +} + +.src-headline-medium-50 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 3.125rem; + line-height: 1.15; + font-weight: 500; + font-style: normal; + --source-text-decoration-thickness: 6px; +} + +.src-headline-medium-64 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 4rem; + line-height: 1.15; + font-weight: 500; + font-style: normal; + --source-text-decoration-thickness: 6px; +} + +.src-headline-medium-italic-14 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 0.875rem; + line-height: 1.15; + font-weight: 500; + font-style: italic; + --source-text-decoration-thickness: 2px; +} + +.src-headline-medium-italic-15 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 0.9375rem; + line-height: 1.15; + font-weight: 500; + font-style: italic; + --source-text-decoration-thickness: 2px; +} + +.src-headline-medium-italic-17 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 1.0625rem; + line-height: 1.15; + font-weight: 500; + font-style: italic; + --source-text-decoration-thickness: 2px; +} + +.src-headline-medium-italic-20 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 1.25rem; + line-height: 1.15; + font-weight: 500; + font-style: italic; + --source-text-decoration-thickness: 3px; +} + +.src-headline-medium-italic-24 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 1.5rem; + line-height: 1.15; + font-weight: 500; + font-style: italic; + --source-text-decoration-thickness: 3px; +} + +.src-headline-medium-italic-28 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 1.75rem; + line-height: 1.15; + font-weight: 500; + font-style: italic; + --source-text-decoration-thickness: 3px; +} + +.src-headline-medium-italic-34 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 2.125rem; + line-height: 1.15; + font-weight: 500; + font-style: italic; + --source-text-decoration-thickness: 4px; +} + +.src-headline-medium-italic-42 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 2.625rem; + line-height: 1.15; + font-weight: 500; + font-style: italic; + --source-text-decoration-thickness: 5px; +} + +.src-headline-medium-italic-50 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 3.125rem; + line-height: 1.15; + font-weight: 500; + font-style: italic; + --source-text-decoration-thickness: 6px; +} + +.src-headline-medium-italic-64 { + font-family: 'GH Guardian Headline', 'Guardian Egyptian Web', Georgia, serif; + font-size: 4rem; + line-height: 1.15; + font-weight: 500; + font-style: italic; + --source-text-decoration-thickness: 6px; +} + +.src-text-egyptian-14 { + font-family: GuardianTextEgyptian, 'Guardian Text Egyptian Web', Georgia, + serif; + font-size: 0.875rem; + line-height: 1.3; + font-weight: 400; + font-style: normal; + --source-text-decoration-thickness: 2px; +} + +.src-text-egyptian-15 { + font-family: GuardianTextEgyptian, 'Guardian Text Egyptian Web', Georgia, + serif; + font-size: 0.9375rem; + line-height: 1.3; + font-weight: 400; + font-style: normal; + --source-text-decoration-thickness: 2px; +} + +.src-text-egyptian-17 { + font-family: GuardianTextEgyptian, 'Guardian Text Egyptian Web', Georgia, + serif; + font-size: 1.0625rem; + line-height: 1.3; + font-weight: 400; + font-style: normal; + --source-text-decoration-thickness: 2px; +} + +.src-text-egyptian-bold-14 { + font-family: GuardianTextEgyptian, 'Guardian Text Egyptian Web', Georgia, + serif; + font-size: 0.875rem; + line-height: 1.3; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 2px; +} + +.src-text-egyptian-bold-15 { + font-family: GuardianTextEgyptian, 'Guardian Text Egyptian Web', Georgia, + serif; + font-size: 0.9375rem; + line-height: 1.3; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 2px; +} + +.src-text-egyptian-bold-17 { + font-family: GuardianTextEgyptian, 'Guardian Text Egyptian Web', Georgia, + serif; + font-size: 1.0625rem; + line-height: 1.3; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 2px; +} + +.src-text-egyptian-bold-italic-14 { + font-family: GuardianTextEgyptian, 'Guardian Text Egyptian Web', Georgia, + serif; + font-size: 0.875rem; + line-height: 1.3; + font-weight: 700; + font-style: italic; + --source-text-decoration-thickness: 2px; +} + +.src-text-egyptian-bold-italic-15 { + font-family: GuardianTextEgyptian, 'Guardian Text Egyptian Web', Georgia, + serif; + font-size: 0.9375rem; + line-height: 1.3; + font-weight: 700; + font-style: italic; + --source-text-decoration-thickness: 2px; +} + +.src-text-egyptian-bold-italic-17 { + font-family: GuardianTextEgyptian, 'Guardian Text Egyptian Web', Georgia, + serif; + font-size: 1.0625rem; + line-height: 1.3; + font-weight: 700; + font-style: italic; + --source-text-decoration-thickness: 2px; +} + +.src-text-egyptian-italic-14 { + font-family: GuardianTextEgyptian, 'Guardian Text Egyptian Web', Georgia, + serif; + font-size: 0.875rem; + line-height: 1.3; + font-weight: 400; + font-style: italic; + --source-text-decoration-thickness: 2px; +} + +.src-text-egyptian-italic-15 { + font-family: GuardianTextEgyptian, 'Guardian Text Egyptian Web', Georgia, + serif; + font-size: 0.9375rem; + line-height: 1.3; + font-weight: 400; + font-style: italic; + --source-text-decoration-thickness: 2px; +} + +.src-text-egyptian-italic-17 { + font-family: GuardianTextEgyptian, 'Guardian Text Egyptian Web', Georgia, + serif; + font-size: 1.0625rem; + line-height: 1.3; + font-weight: 400; + font-style: italic; + --source-text-decoration-thickness: 2px; +} + +.src-text-sans-12 { + font-family: GuardianTextSans, 'Guardian Text Sans Web', 'Helvetica Neue', + Helvetica, Arial, 'Lucida Grande', sans-serif; + font-size: 0.75rem; + line-height: 1.3; + font-weight: 400; + font-style: normal; + --source-text-decoration-thickness: 2px; +} + +.src-text-sans-14 { + font-family: GuardianTextSans, 'Guardian Text Sans Web', 'Helvetica Neue', + Helvetica, Arial, 'Lucida Grande', sans-serif; + font-size: 0.875rem; + line-height: 1.3; + font-weight: 400; + font-style: normal; + --source-text-decoration-thickness: 2px; +} + +.src-text-sans-15 { + font-family: GuardianTextSans, 'Guardian Text Sans Web', 'Helvetica Neue', + Helvetica, Arial, 'Lucida Grande', sans-serif; + font-size: 0.9375rem; + line-height: 1.3; + font-weight: 400; + font-style: normal; + --source-text-decoration-thickness: 2px; +} + +.src-text-sans-17 { + font-family: GuardianTextSans, 'Guardian Text Sans Web', 'Helvetica Neue', + Helvetica, Arial, 'Lucida Grande', sans-serif; + font-size: 1.0625rem; + line-height: 1.3; + font-weight: 400; + font-style: normal; + --source-text-decoration-thickness: 2px; +} + +.src-text-sans-20 { + font-family: GuardianTextSans, 'Guardian Text Sans Web', 'Helvetica Neue', + Helvetica, Arial, 'Lucida Grande', sans-serif; + font-size: 1.25rem; + line-height: 1.3; + font-weight: 400; + font-style: normal; + --source-text-decoration-thickness: 3px; +} + +.src-text-sans-24 { + font-family: GuardianTextSans, 'Guardian Text Sans Web', 'Helvetica Neue', + Helvetica, Arial, 'Lucida Grande', sans-serif; + font-size: 1.5rem; + line-height: 1.3; + font-weight: 400; + font-style: normal; + --source-text-decoration-thickness: 3px; +} + +.src-text-sans-28 { + font-family: GuardianTextSans, 'Guardian Text Sans Web', 'Helvetica Neue', + Helvetica, Arial, 'Lucida Grande', sans-serif; + font-size: 1.75rem; + line-height: 1.3; + font-weight: 400; + font-style: normal; + --source-text-decoration-thickness: 3px; +} + +.src-text-sans-34 { + font-family: GuardianTextSans, 'Guardian Text Sans Web', 'Helvetica Neue', + Helvetica, Arial, 'Lucida Grande', sans-serif; + font-size: 2.125rem; + line-height: 1.3; + font-weight: 400; + font-style: normal; + --source-text-decoration-thickness: 4px; +} + +.src-text-sans-bold-12 { + font-family: GuardianTextSans, 'Guardian Text Sans Web', 'Helvetica Neue', + Helvetica, Arial, 'Lucida Grande', sans-serif; + font-size: 0.75rem; + line-height: 1.3; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 2px; +} + +.src-text-sans-bold-14 { + font-family: GuardianTextSans, 'Guardian Text Sans Web', 'Helvetica Neue', + Helvetica, Arial, 'Lucida Grande', sans-serif; + font-size: 0.875rem; + line-height: 1.3; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 2px; +} + +.src-text-sans-bold-15 { + font-family: GuardianTextSans, 'Guardian Text Sans Web', 'Helvetica Neue', + Helvetica, Arial, 'Lucida Grande', sans-serif; + font-size: 0.9375rem; + line-height: 1.3; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 2px; +} + +.src-text-sans-bold-17 { + font-family: GuardianTextSans, 'Guardian Text Sans Web', 'Helvetica Neue', + Helvetica, Arial, 'Lucida Grande', sans-serif; + font-size: 1.0625rem; + line-height: 1.3; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 2px; +} + +.src-text-sans-bold-20 { + font-family: GuardianTextSans, 'Guardian Text Sans Web', 'Helvetica Neue', + Helvetica, Arial, 'Lucida Grande', sans-serif; + font-size: 1.25rem; + line-height: 1.3; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 3px; +} + +.src-text-sans-bold-24 { + font-family: GuardianTextSans, 'Guardian Text Sans Web', 'Helvetica Neue', + Helvetica, Arial, 'Lucida Grande', sans-serif; + font-size: 1.5rem; + line-height: 1.3; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 3px; +} + +.src-text-sans-bold-28 { + font-family: GuardianTextSans, 'Guardian Text Sans Web', 'Helvetica Neue', + Helvetica, Arial, 'Lucida Grande', sans-serif; + font-size: 1.75rem; + line-height: 1.3; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 3px; +} + +.src-text-sans-bold-34 { + font-family: GuardianTextSans, 'Guardian Text Sans Web', 'Helvetica Neue', + Helvetica, Arial, 'Lucida Grande', sans-serif; + font-size: 2.125rem; + line-height: 1.3; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 4px; +} + +.src-text-sans-italic-12 { + font-family: GuardianTextSans, 'Guardian Text Sans Web', 'Helvetica Neue', + Helvetica, Arial, 'Lucida Grande', sans-serif; + font-size: 0.75rem; + line-height: 1.3; + font-weight: 400; + font-style: italic; + --source-text-decoration-thickness: 2px; +} + +.src-text-sans-italic-14 { + font-family: GuardianTextSans, 'Guardian Text Sans Web', 'Helvetica Neue', + Helvetica, Arial, 'Lucida Grande', sans-serif; + font-size: 0.875rem; + line-height: 1.3; + font-weight: 400; + font-style: italic; + --source-text-decoration-thickness: 2px; +} + +.src-text-sans-italic-15 { + font-family: GuardianTextSans, 'Guardian Text Sans Web', 'Helvetica Neue', + Helvetica, Arial, 'Lucida Grande', sans-serif; + font-size: 0.9375rem; + line-height: 1.3; + font-weight: 400; + font-style: italic; + --source-text-decoration-thickness: 2px; +} + +.src-text-sans-italic-17 { + font-family: GuardianTextSans, 'Guardian Text Sans Web', 'Helvetica Neue', + Helvetica, Arial, 'Lucida Grande', sans-serif; + font-size: 1.0625rem; + line-height: 1.3; + font-weight: 400; + font-style: italic; + --source-text-decoration-thickness: 2px; +} + +.src-text-sans-italic-20 { + font-family: GuardianTextSans, 'Guardian Text Sans Web', 'Helvetica Neue', + Helvetica, Arial, 'Lucida Grande', sans-serif; + font-size: 1.25rem; + line-height: 1.3; + font-weight: 400; + font-style: italic; + --source-text-decoration-thickness: 3px; +} + +.src-text-sans-italic-24 { + font-family: GuardianTextSans, 'Guardian Text Sans Web', 'Helvetica Neue', + Helvetica, Arial, 'Lucida Grande', sans-serif; + font-size: 1.5rem; + line-height: 1.3; + font-weight: 400; + font-style: italic; + --source-text-decoration-thickness: 3px; +} + +.src-text-sans-italic-28 { + font-family: GuardianTextSans, 'Guardian Text Sans Web', 'Helvetica Neue', + Helvetica, Arial, 'Lucida Grande', sans-serif; + font-size: 1.75rem; + line-height: 1.3; + font-weight: 400; + font-style: italic; + --source-text-decoration-thickness: 3px; +} + +.src-text-sans-italic-34 { + font-family: GuardianTextSans, 'Guardian Text Sans Web', 'Helvetica Neue', + Helvetica, Arial, 'Lucida Grande', sans-serif; + font-size: 2.125rem; + line-height: 1.3; + font-weight: 400; + font-style: italic; + --source-text-decoration-thickness: 4px; +} + +.src-titlepiece-42 { + font-family: 'GT Guardian Titlepiece', Georgia, serif; + font-size: 2.625rem; + line-height: 1.15; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 5px; +} + +.src-titlepiece-50 { + font-family: 'GT Guardian Titlepiece', Georgia, serif; + font-size: 3.125rem; + line-height: 1.15; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 6px; +} + +.src-titlepiece-70 { + font-family: 'GT Guardian Titlepiece', Georgia, serif; + font-size: 4.375rem; + line-height: 1.15; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 6px; +} diff --git a/libs/@guardian/source/src/foundations/__generated__/typography.ts b/libs/@guardian/source/src/foundations/__generated__/typography.ts index 32054707b..543972be6 100644 --- a/libs/@guardian/source/src/foundations/__generated__/typography.ts +++ b/libs/@guardian/source/src/foundations/__generated__/typography.ts @@ -1,7 +1,7 @@ /* * DO NOT EDIT THIS FILE DIRECTLY! * - * It was auto-generated by design-tokens/plugins/typography.js. + * It was auto-generated by design-tokens/plugins/typescript.js. * * Update design-tokens/tokens.json and (re)build @guardian/source instead. */ diff --git a/libs/@guardian/source/src/foundations/tokens.test.ts b/libs/@guardian/source/src/foundations/tokens.test.ts index cf228ce83..758c38f87 100644 --- a/libs/@guardian/source/src/foundations/tokens.test.ts +++ b/libs/@guardian/source/src/foundations/tokens.test.ts @@ -1,3 +1,6 @@ +import { readFileSync } from 'fs'; +import { join } from 'path'; +import postcss from 'postcss'; import { background, border, @@ -26,6 +29,17 @@ import { } from './size/size'; import { remSpace, space } from './space/space'; +function kebabToCamel(name: string) { + return name + .toLowerCase() + .split('-') + .filter((word) => word.length > 0) + .map((word, index) => + index === 0 ? word : word.charAt(0).toUpperCase() + word.slice(1), + ) + .join(''); +} + describe('Transition tokens', () => { it('should match expected output', () => { expect(transitions).toEqual({ @@ -36,7 +50,7 @@ describe('Transition tokens', () => { }); }); -describe('Breakpoint tokens', () => { +describe('Breakpoint tokens object output', () => { it('should match expected output', () => { expect(breakpoints).toEqual({ desktop: 980, @@ -51,134 +65,180 @@ describe('Breakpoint tokens', () => { }); }); +describe.only('Breakpoint tokens mixin output', () => { + it.only('should generate correct SCSS breakpoints with mq mixin', () => { + const cssPath = join(__dirname, '__generated__/breakpoints.scss'); + const cssContent = readFileSync(cssPath, 'utf-8'); + + const expectedRegex = new RegExp( + '\\$breakpoints:\\s*\\(' + + '\\s*mobile:\\s*320px,' + + '\\s*mobileMedium:\\s*375px,' + + '\\s*mobileLandscape:\\s*480px,' + + '\\s*phablet:\\s*660px,' + + '\\s*tablet:\\s*740px,' + + '\\s*desktop:\\s*980px,' + + '\\s*leftCol:\\s*1140px,' + + '\\s*wide:\\s*1300px,' + + '\\s*\\);', + ); + + expect(cssContent).toMatch(expectedRegex); + }); +}); + describe('Palette tokens', () => { + const expectedPalette = { + brand: { + '100': '#001536', + '300': '#041F4A', + '400': '#052962', + '500': '#0077B6', + '600': '#506991', + '800': '#C1D8FC', + }, + brandAlt: { + '200': '#F3C100', + '300': '#FFD900', + '400': '#FFE500', + }, + culture: { + '100': '#3E3323', + '200': '#574835', + '300': '#6B5840', + '350': '#866D50', + '400': '#866D50', + '450': '#A1845C', + '50': '#2B2625', + '500': '#EACCA0', + '600': '#E7D4B9', + '700': '#EFE8DD', + '800': '#FBF6EF', + }, + error: { + '400': '#C70000', + '500': '#FF9081', + }, + focus: { + '400': '#0077B6', + }, + labs: { + '100': '#09615B', + '200': '#0C7A73', + '300': '#65A897', + '400': '#69D1CA', + '500': '#A8E3DF', + '600': '#DCF4F3', + '700': '#F3FBFB', + }, + lifestyle: { + '100': '#510043', + '200': '#650054', + '300': '#7D0068', + '400': '#BB3B80', + '450': '#F37ABC', + '500': '#FFABDB', + '600': '#FEC8D3', + '800': '#FEF1F8', + }, + neutral: { + '0': '#000000', + '10': '#1A1A1A', + '100': '#FFFFFF', + '20': '#333333', + '38': '#545454', + '46': '#707070', + '60': '#999999', + '7': '#121212', + '73': '#BABABA', + '86': '#DCDCDC', + '93': '#EDEDED', + '97': '#F6F6F6', + }, + news: { + '100': '#660505', + '200': '#8B0000', + '300': '#AB0613', + '400': '#C70000', + '500': '#FF5943', + '550': '#FF9081', + '600': '#FFBAC8', + '700': '#FFD8D1', + '800': '#FFF4F2', + }, + notificationBlue: { + '400': '#0190F7', + }, + opinion: { + '100': '#672005', + '200': '#8D2700', + '300': '#C74600', + '400': '#C74600', + '450': '#E05E00', + '500': '#FF7F0F', + '550': '#FF9941', + '600': '#F9B376', + '700': '#FFE7D4', + '800': '#FEF9F5', + }, + specialReport: { + '100': '#222527', + '200': '#303538', + '300': '#3F464A', + '400': '#595C5F', + '450': '#9DA0A2', + '500': '#ABC2C9', + '700': '#E4E5E8', + '800': '#EFF1F2', + }, + specialReportAlt: { + '100': '#2B2B2A', + '200': '#B9300A', + '300': '#FF663D', + '700': '#EBE6E1', + '800': '#F5F0EB', + }, + sport: { + '100': '#003C60', + '200': '#004E7C', + '300': '#005689', + '400': '#0077B6', + '500': '#00B2FF', + '600': '#90DCFF', + '700': '#D8F1FF', + '800': '#F1F8FC', + }, + success: { + '300': '#185E36', + '400': '#22874D', + '500': '#58D08B', + }, + }; + it('should match expected output', () => { - expect(palette).toEqual({ - brand: { - '100': '#001536', - '300': '#041F4A', - '400': '#052962', - '500': '#0077B6', - '600': '#506991', - '800': '#C1D8FC', - }, - brandAlt: { - '200': '#F3C100', - '300': '#FFD900', - '400': '#FFE500', - }, - culture: { - '100': '#3E3323', - '200': '#574835', - '300': '#6B5840', - '350': '#866D50', - '400': '#866D50', - '450': '#A1845C', - '50': '#2B2625', - '500': '#EACCA0', - '600': '#E7D4B9', - '700': '#EFE8DD', - '800': '#FBF6EF', - }, - error: { - '400': '#C70000', - '500': '#FF9081', - }, - focus: { - '400': '#0077B6', - }, - labs: { - '100': '#09615B', - '200': '#0C7A73', - '300': '#65A897', - '400': '#69D1CA', - '500': '#A8E3DF', - '600': '#DCF4F3', - '700': '#F3FBFB', - }, - lifestyle: { - '100': '#510043', - '200': '#650054', - '300': '#7D0068', - '400': '#BB3B80', - '450': '#F37ABC', - '500': '#FFABDB', - '600': '#FEC8D3', - '800': '#FEF1F8', - }, - neutral: { - '0': '#000000', - '10': '#1A1A1A', - '100': '#FFFFFF', - '20': '#333333', - '38': '#545454', - '46': '#707070', - '60': '#999999', - '7': '#121212', - '73': '#BABABA', - '86': '#DCDCDC', - '93': '#EDEDED', - '97': '#F6F6F6', - }, - news: { - '100': '#660505', - '200': '#8B0000', - '300': '#AB0613', - '400': '#C70000', - '500': '#FF5943', - '550': '#FF9081', - '600': '#FFBAC8', - '700': '#FFD8D1', - '800': '#FFF4F2', - }, - notificationBlue: { - '400': '#0190F7', - }, - opinion: { - '100': '#672005', - '200': '#8D2700', - '300': '#C74600', - '400': '#C74600', - '450': '#E05E00', - '500': '#FF7F0F', - '550': '#FF9941', - '600': '#F9B376', - '700': '#FFE7D4', - '800': '#FEF9F5', - }, - specialReport: { - '100': '#222527', - '200': '#303538', - '300': '#3F464A', - '400': '#595C5F', - '450': '#9DA0A2', - '500': '#ABC2C9', - '700': '#E4E5E8', - '800': '#EFF1F2', - }, - specialReportAlt: { - '100': '#2B2B2A', - '200': '#B9300A', - '300': '#FF663D', - '700': '#EBE6E1', - '800': '#F5F0EB', - }, - sport: { - '100': '#003C60', - '200': '#004E7C', - '300': '#005689', - '400': '#0077B6', - '500': '#00B2FF', - '600': '#90DCFF', - '700': '#D8F1FF', - '800': '#F1F8FC', - }, - success: { - '300': '#185E36', - '400': '#22874D', - '500': '#58D08B', - }, + expect(palette).toEqual(expectedPalette); + }); + + it('should generate correct CSS variables', () => { + const cssPath = join(__dirname, '__generated__/palette.css'); + const cssContent = readFileSync(cssPath, 'utf-8'); + const root = postcss.parse(cssContent); + + const reconstructedPalette = {} as Record>; + + root.walkDecls((decl) => { + // Match eg. "brand-alt" and "300" from --src-brand-alt-300 + const match = decl.prop.match(/^--src-([a-z-]+)-(\d+)$/); + + if (match?.[1] && match[2]) { + const [, colorName, shade] = match; + const camelColorName = kebabToCamel(colorName); + reconstructedPalette[camelColorName] ??= {}; + reconstructedPalette[camelColorName][shade] = decl.value.toUpperCase(); + } }); + + expect(reconstructedPalette).toEqual(expectedPalette); }); }); @@ -2060,9 +2120,996 @@ describe('Typography preset object output', () => { }); }); -/** - * Deprecated tokens - */ +describe('Typography preset CSS classes output', () => { + it('should match expected output', () => { + const cssPath = join(__dirname, '__generated__/typography.css'); + const cssContent = readFileSync(cssPath, 'utf-8'); + const root = postcss.parse(cssContent); + + const findRule = (className: string) => { + const rule = root.nodes.find( + (node) => node.type === 'rule' && node.selector === `.${className}`, + ); + + if (!rule) { + throw new Error(`rule with class name .${className} not found`); + } + + return rule.toString(); + }; + + expect(findRule('src-article-15')).toMatchCSS( + `.src-article-15 { + font-family: GuardianTextEgyptian, "Guardian Text Egyptian Web", Georgia, serif; + font-size: 0.9375rem; + line-height: 1.4; + font-weight: 400; + font-style: normal; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-article-17')).toMatchCSS( + `.src-article-17 { + font-family: GuardianTextEgyptian, "Guardian Text Egyptian Web", Georgia, serif; + font-size: 1.0625rem; + line-height: 1.4; + font-weight: 400; + font-style: normal; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-article-bold-15')).toMatchCSS( + `.src-article-bold-15 { + font-family: GuardianTextEgyptian, "Guardian Text Egyptian Web", Georgia, serif; + font-size: 0.9375rem; + line-height: 1.4; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-article-bold-17')).toMatchCSS( + `.src-article-bold-17 { + font-family: GuardianTextEgyptian, "Guardian Text Egyptian Web", Georgia, serif; + font-size: 1.0625rem; + line-height: 1.4; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-article-bold-italic-15')).toMatchCSS( + `.src-article-bold-italic-15 { + font-family: GuardianTextEgyptian, "Guardian Text Egyptian Web", Georgia, serif; + font-size: 0.9375rem; + line-height: 1.4; + font-weight: 700; + font-style: italic; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-article-bold-italic-17')).toMatchCSS( + `.src-article-bold-italic-17 { + font-family: GuardianTextEgyptian, "Guardian Text Egyptian Web", Georgia, serif; + font-size: 1.0625rem; + line-height: 1.4; + font-weight: 700; + font-style: italic; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-article-italic-15')).toMatchCSS( + `.src-article-italic-15 { + font-family: GuardianTextEgyptian, "Guardian Text Egyptian Web", Georgia, serif; + font-size: 0.9375rem; + line-height: 1.4; + font-weight: 400; + font-style: italic; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-article-italic-17')).toMatchCSS( + `.src-article-italic-17 { + font-family: GuardianTextEgyptian, "Guardian Text Egyptian Web", Georgia, serif; + font-size: 1.0625rem; + line-height: 1.4; + font-weight: 400; + font-style: italic; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-headline-bold-14')).toMatchCSS( + `.src-headline-bold-14 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 0.875rem; + line-height: 1.15; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-headline-bold-15')).toMatchCSS( + `.src-headline-bold-15 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 0.9375rem; + line-height: 1.15; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-headline-bold-17')).toMatchCSS( + `.src-headline-bold-17 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 1.0625rem; + line-height: 1.15; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-headline-bold-20')).toMatchCSS( + `.src-headline-bold-20 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 1.25rem; + line-height: 1.15; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 3px; + }`, + ); + expect(findRule('src-headline-bold-24')).toMatchCSS( + `.src-headline-bold-24 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 1.5rem; + line-height: 1.15; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 3px; + }`, + ); + expect(findRule('src-headline-bold-28')).toMatchCSS( + `.src-headline-bold-28 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 1.75rem; + line-height: 1.15; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 3px; + }`, + ); + expect(findRule('src-headline-bold-34')).toMatchCSS( + `.src-headline-bold-34 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 2.125rem; + line-height: 1.15; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 4px; + }`, + ); + expect(findRule('src-headline-bold-42')).toMatchCSS( + `.src-headline-bold-42 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 2.625rem; + line-height: 1.15; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 5px; + }`, + ); + expect(findRule('src-headline-bold-50')).toMatchCSS( + `.src-headline-bold-50 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 3.125rem; + line-height: 1.15; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 6px; + }`, + ); + expect(findRule('src-headline-bold-64')).toMatchCSS( + `.src-headline-bold-64 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 4rem; + line-height: 1.15; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 6px; + }`, + ); + expect(findRule('src-headline-light-14')).toMatchCSS( + `.src-headline-light-14 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 0.875rem; + line-height: 1.15; + font-weight: 300; + font-style: normal; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-headline-light-15')).toMatchCSS( + `.src-headline-light-15 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 0.9375rem; + line-height: 1.15; + font-weight: 300; + font-style: normal; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-headline-light-17')).toMatchCSS( + `.src-headline-light-17 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 1.0625rem; + line-height: 1.15; + font-weight: 300; + font-style: normal; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-headline-light-20')).toMatchCSS( + `.src-headline-light-20 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 1.25rem; + line-height: 1.15; + font-weight: 300; + font-style: normal; + --source-text-decoration-thickness: 3px; + }`, + ); + expect(findRule('src-headline-light-24')).toMatchCSS( + `.src-headline-light-24 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 1.5rem; + line-height: 1.15; + font-weight: 300; + font-style: normal; + --source-text-decoration-thickness: 3px; + }`, + ); + expect(findRule('src-headline-light-28')).toMatchCSS( + `.src-headline-light-28 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 1.75rem; + line-height: 1.15; + font-weight: 300; + font-style: normal; + --source-text-decoration-thickness: 3px; + }`, + ); + expect(findRule('src-headline-light-34')).toMatchCSS( + `.src-headline-light-34 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 2.125rem; + line-height: 1.15; + font-weight: 300; + font-style: normal; + --source-text-decoration-thickness: 4px; + }`, + ); + expect(findRule('src-headline-light-42')).toMatchCSS( + `.src-headline-light-42 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 2.625rem; + line-height: 1.15; + font-weight: 300; + font-style: normal; + --source-text-decoration-thickness: 5px; + }`, + ); + expect(findRule('src-headline-light-50')).toMatchCSS( + `.src-headline-light-50 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 3.125rem; + line-height: 1.15; + font-weight: 300; + font-style: normal; + --source-text-decoration-thickness: 6px; + }`, + ); + expect(findRule('src-headline-light-64')).toMatchCSS( + `.src-headline-light-64 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 4rem; + line-height: 1.15; + font-weight: 300; + font-style: normal; + --source-text-decoration-thickness: 6px; + }`, + ); + expect(findRule('src-headline-light-italic-14')).toMatchCSS( + `.src-headline-light-italic-14 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 0.875rem; + line-height: 1.15; + font-weight: 300; + font-style: italic; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-headline-light-italic-15')).toMatchCSS( + `.src-headline-light-italic-15 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 0.9375rem; + line-height: 1.15; + font-weight: 300; + font-style: italic; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-headline-light-italic-17')).toMatchCSS( + `.src-headline-light-italic-17 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 1.0625rem; + line-height: 1.15; + font-weight: 300; + font-style: italic; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-headline-light-italic-20')).toMatchCSS( + `.src-headline-light-italic-20 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 1.25rem; + line-height: 1.15; + font-weight: 300; + font-style: italic; + --source-text-decoration-thickness: 3px; + }`, + ); + expect(findRule('src-headline-light-italic-24')).toMatchCSS( + `.src-headline-light-italic-24 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 1.5rem; + line-height: 1.15; + font-weight: 300; + font-style: italic; + --source-text-decoration-thickness: 3px; + }`, + ); + expect(findRule('src-headline-light-italic-28')).toMatchCSS( + `.src-headline-light-italic-28 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 1.75rem; + line-height: 1.15; + font-weight: 300; + font-style: italic; + --source-text-decoration-thickness: 3px; + }`, + ); + expect(findRule('src-headline-light-italic-34')).toMatchCSS( + `.src-headline-light-italic-34 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 2.125rem; + line-height: 1.15; + font-weight: 300; + font-style: italic; + --source-text-decoration-thickness: 4px; + }`, + ); + expect(findRule('src-headline-light-italic-42')).toMatchCSS( + `.src-headline-light-italic-42 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 2.625rem; + line-height: 1.15; + font-weight: 300; + font-style: italic; + --source-text-decoration-thickness: 5px; + }`, + ); + expect(findRule('src-headline-light-italic-50')).toMatchCSS( + `.src-headline-light-italic-50 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 3.125rem; + line-height: 1.15; + font-weight: 300; + font-style: italic; + --source-text-decoration-thickness: 6px; + }`, + ); + expect(findRule('src-headline-light-italic-64')).toMatchCSS( + `.src-headline-light-italic-64 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 4rem; + line-height: 1.15; + font-weight: 300; + font-style: italic; + --source-text-decoration-thickness: 6px; + }`, + ); + expect(findRule('src-headline-medium-14')).toMatchCSS( + `.src-headline-medium-14 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 0.875rem; + line-height: 1.15; + font-weight: 500; + font-style: normal; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-headline-medium-15')).toMatchCSS( + `.src-headline-medium-15 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 0.9375rem; + line-height: 1.15; + font-weight: 500; + font-style: normal; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-headline-medium-17')).toMatchCSS( + `.src-headline-medium-17 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 1.0625rem; + line-height: 1.15; + font-weight: 500; + font-style: normal; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-headline-medium-20')).toMatchCSS( + `.src-headline-medium-20 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 1.25rem; + line-height: 1.15; + font-weight: 500; + font-style: normal; + --source-text-decoration-thickness: 3px; + }`, + ); + expect(findRule('src-headline-medium-24')).toMatchCSS( + `.src-headline-medium-24 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 1.5rem; + line-height: 1.15; + font-weight: 500; + font-style: normal; + --source-text-decoration-thickness: 3px; + }`, + ); + expect(findRule('src-headline-medium-28')).toMatchCSS( + `.src-headline-medium-28 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 1.75rem; + line-height: 1.15; + font-weight: 500; + font-style: normal; + --source-text-decoration-thickness: 3px; + }`, + ); + expect(findRule('src-headline-medium-34')).toMatchCSS( + `.src-headline-medium-34 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 2.125rem; + line-height: 1.15; + font-weight: 500; + font-style: normal; + --source-text-decoration-thickness: 4px; + }`, + ); + expect(findRule('src-headline-medium-42')).toMatchCSS( + `.src-headline-medium-42 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 2.625rem; + line-height: 1.15; + font-weight: 500; + font-style: normal; + --source-text-decoration-thickness: 5px; + }`, + ); + expect(findRule('src-headline-medium-50')).toMatchCSS( + `.src-headline-medium-50 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 3.125rem; + line-height: 1.15; + font-weight: 500; + font-style: normal; + --source-text-decoration-thickness: 6px; + }`, + ); + expect(findRule('src-headline-medium-64')).toMatchCSS( + `.src-headline-medium-64 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 4rem; + line-height: 1.15; + font-weight: 500; + font-style: normal; + --source-text-decoration-thickness: 6px; + }`, + ); + expect(findRule('src-headline-medium-italic-14')).toMatchCSS( + `.src-headline-medium-italic-14 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 0.875rem; + line-height: 1.15; + font-weight: 500; + font-style: italic; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-headline-medium-italic-15')).toMatchCSS( + `.src-headline-medium-italic-15 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 0.9375rem; + line-height: 1.15; + font-weight: 500; + font-style: italic; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-headline-medium-italic-17')).toMatchCSS( + `.src-headline-medium-italic-17 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 1.0625rem; + line-height: 1.15; + font-weight: 500; + font-style: italic; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-headline-medium-italic-20')).toMatchCSS( + `.src-headline-medium-italic-20 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 1.25rem; + line-height: 1.15; + font-weight: 500; + font-style: italic; + --source-text-decoration-thickness: 3px; + }`, + ); + expect(findRule('src-headline-medium-italic-24')).toMatchCSS( + `.src-headline-medium-italic-24 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 1.5rem; + line-height: 1.15; + font-weight: 500; + font-style: italic; + --source-text-decoration-thickness: 3px; + }`, + ); + expect(findRule('src-headline-medium-italic-28')).toMatchCSS( + `.src-headline-medium-italic-28 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 1.75rem; + line-height: 1.15; + font-weight: 500; + font-style: italic; + --source-text-decoration-thickness: 3px; + }`, + ); + expect(findRule('src-headline-medium-italic-34')).toMatchCSS( + `.src-headline-medium-italic-34 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 2.125rem; + line-height: 1.15; + font-weight: 500; + font-style: italic; + --source-text-decoration-thickness: 4px; + }`, + ); + expect(findRule('src-headline-medium-italic-42')).toMatchCSS( + `.src-headline-medium-italic-42 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 2.625rem; + line-height: 1.15; + font-weight: 500; + font-style: italic; + --source-text-decoration-thickness: 5px; + }`, + ); + expect(findRule('src-headline-medium-italic-50')).toMatchCSS( + `.src-headline-medium-italic-50 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 3.125rem; + line-height: 1.15; + font-weight: 500; + font-style: italic; + --source-text-decoration-thickness: 6px; + }`, + ); + expect(findRule('src-headline-medium-italic-64')).toMatchCSS( + `.src-headline-medium-italic-64 { + font-family: "GH Guardian Headline", "Guardian Egyptian Web", Georgia, serif; + font-size: 4rem; + line-height: 1.15; + font-weight: 500; + font-style: italic; + --source-text-decoration-thickness: 6px; + }`, + ); + expect(findRule('src-text-egyptian-14')).toMatchCSS( + `.src-text-egyptian-14 { + font-family: GuardianTextEgyptian, "Guardian Text Egyptian Web", Georgia, serif; + font-size: 0.875rem; + line-height: 1.3; + font-weight: 400; + font-style: normal; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-text-egyptian-15')).toMatchCSS( + `.src-text-egyptian-15 { + font-family: GuardianTextEgyptian, "Guardian Text Egyptian Web", Georgia, serif; + font-size: 0.9375rem; + line-height: 1.3; + font-weight: 400; + font-style: normal; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-text-egyptian-17')).toMatchCSS( + `.src-text-egyptian-17 { + font-family: GuardianTextEgyptian, "Guardian Text Egyptian Web", Georgia, serif; + font-size: 1.0625rem; + line-height: 1.3; + font-weight: 400; + font-style: normal; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-text-egyptian-bold-14')).toMatchCSS( + `.src-text-egyptian-bold-14 { + font-family: GuardianTextEgyptian, "Guardian Text Egyptian Web", Georgia, serif; + font-size: 0.875rem; + line-height: 1.3; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-text-egyptian-bold-15')).toMatchCSS( + `.src-text-egyptian-bold-15 { + font-family: GuardianTextEgyptian, "Guardian Text Egyptian Web", Georgia, serif; + font-size: 0.9375rem; + line-height: 1.3; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-text-egyptian-bold-17')).toMatchCSS( + `.src-text-egyptian-bold-17 { + font-family: GuardianTextEgyptian, "Guardian Text Egyptian Web", Georgia, serif; + font-size: 1.0625rem; + line-height: 1.3; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-text-egyptian-bold-italic-14')).toMatchCSS( + `.src-text-egyptian-bold-italic-14 { + font-family: GuardianTextEgyptian, "Guardian Text Egyptian Web", Georgia, serif; + font-size: 0.875rem; + line-height: 1.3; + font-weight: 700; + font-style: italic; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-text-egyptian-bold-italic-15')).toMatchCSS( + `.src-text-egyptian-bold-italic-15 { + font-family: GuardianTextEgyptian, "Guardian Text Egyptian Web", Georgia, serif; + font-size: 0.9375rem; + line-height: 1.3; + font-weight: 700; + font-style: italic; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-text-egyptian-bold-italic-17')).toMatchCSS( + `.src-text-egyptian-bold-italic-17 { + font-family: GuardianTextEgyptian, "Guardian Text Egyptian Web", Georgia, serif; + font-size: 1.0625rem; + line-height: 1.3; + font-weight: 700; + font-style: italic; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-text-egyptian-italic-14')).toMatchCSS( + `.src-text-egyptian-italic-14 { + font-family: GuardianTextEgyptian, "Guardian Text Egyptian Web", Georgia, serif; + font-size: 0.875rem; + line-height: 1.3; + font-weight: 400; + font-style: italic; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-text-egyptian-italic-15')).toMatchCSS( + `.src-text-egyptian-italic-15 { + font-family: GuardianTextEgyptian, "Guardian Text Egyptian Web", Georgia, serif; + font-size: 0.9375rem; + line-height: 1.3; + font-weight: 400; + font-style: italic; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-text-egyptian-italic-17')).toMatchCSS( + `.src-text-egyptian-italic-17 { + font-family: GuardianTextEgyptian, "Guardian Text Egyptian Web", Georgia, serif; + font-size: 1.0625rem; + line-height: 1.3; + font-weight: 400; + font-style: italic; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-text-sans-12')).toMatchCSS( + `.src-text-sans-12 { + font-family: GuardianTextSans, "Guardian Text Sans Web", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; + font-size: 0.75rem; + line-height: 1.3; + font-weight: 400; + font-style: normal; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-text-sans-14')).toMatchCSS( + `.src-text-sans-14 { + font-family: GuardianTextSans, "Guardian Text Sans Web", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; + font-size: 0.875rem; + line-height: 1.3; + font-weight: 400; + font-style: normal; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-text-sans-15')).toMatchCSS( + `.src-text-sans-15 { + font-family: GuardianTextSans, "Guardian Text Sans Web", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; + font-size: 0.9375rem; + line-height: 1.3; + font-weight: 400; + font-style: normal; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-text-sans-17')).toMatchCSS( + `.src-text-sans-17 { + font-family: GuardianTextSans, "Guardian Text Sans Web", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; + font-size: 1.0625rem; + line-height: 1.3; + font-weight: 400; + font-style: normal; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-text-sans-20')).toMatchCSS( + `.src-text-sans-20 { + font-family: GuardianTextSans, "Guardian Text Sans Web", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; + font-size: 1.25rem; + line-height: 1.3; + font-weight: 400; + font-style: normal; + --source-text-decoration-thickness: 3px; + }`, + ); + expect(findRule('src-text-sans-24')).toMatchCSS( + `.src-text-sans-24 { + font-family: GuardianTextSans, "Guardian Text Sans Web", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; + font-size: 1.5rem; + line-height: 1.3; + font-weight: 400; + font-style: normal; + --source-text-decoration-thickness: 3px; + }`, + ); + expect(findRule('src-text-sans-28')).toMatchCSS( + `.src-text-sans-28 { + font-family: GuardianTextSans, "Guardian Text Sans Web", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; + font-size: 1.75rem; + line-height: 1.3; + font-weight: 400; + font-style: normal; + --source-text-decoration-thickness: 3px; + }`, + ); + expect(findRule('src-text-sans-34')).toMatchCSS( + `.src-text-sans-34 { + font-family: GuardianTextSans, "Guardian Text Sans Web", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; + font-size: 2.125rem; + line-height: 1.3; + font-weight: 400; + font-style: normal; + --source-text-decoration-thickness: 4px; + }`, + ); + expect(findRule('src-text-sans-bold-12')).toMatchCSS( + `.src-text-sans-bold-12 { + font-family: GuardianTextSans, "Guardian Text Sans Web", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; + font-size: 0.75rem; + line-height: 1.3; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-text-sans-bold-14')).toMatchCSS( + `.src-text-sans-bold-14 { + font-family: GuardianTextSans, "Guardian Text Sans Web", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; + font-size: 0.875rem; + line-height: 1.3; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-text-sans-bold-15')).toMatchCSS( + `.src-text-sans-bold-15 { + font-family: GuardianTextSans, "Guardian Text Sans Web", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; + font-size: 0.9375rem; + line-height: 1.3; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-text-sans-bold-17')).toMatchCSS( + `.src-text-sans-bold-17 { + font-family: GuardianTextSans, "Guardian Text Sans Web", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; + font-size: 1.0625rem; + line-height: 1.3; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-text-sans-bold-20')).toMatchCSS( + `.src-text-sans-bold-20 { + font-family: GuardianTextSans, "Guardian Text Sans Web", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; + font-size: 1.25rem; + line-height: 1.3; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 3px; + }`, + ); + expect(findRule('src-text-sans-bold-24')).toMatchCSS( + `.src-text-sans-bold-24 { + font-family: GuardianTextSans, "Guardian Text Sans Web", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; + font-size: 1.5rem; + line-height: 1.3; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 3px; + }`, + ); + expect(findRule('src-text-sans-bold-28')).toMatchCSS( + `.src-text-sans-bold-28 { + font-family: GuardianTextSans, "Guardian Text Sans Web", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; + font-size: 1.75rem; + line-height: 1.3; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 3px; + }`, + ); + expect(findRule('src-text-sans-bold-34')).toMatchCSS( + `.src-text-sans-bold-34 { + font-family: GuardianTextSans, "Guardian Text Sans Web", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; + font-size: 2.125rem; + line-height: 1.3; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 4px; + }`, + ); + expect(findRule('src-text-sans-italic-12')).toMatchCSS( + `.src-text-sans-italic-12 { + font-family: GuardianTextSans, "Guardian Text Sans Web", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; + font-size: 0.75rem; + line-height: 1.3; + font-weight: 400; + font-style: italic; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-text-sans-italic-14')).toMatchCSS( + `.src-text-sans-italic-14 { + font-family: GuardianTextSans, "Guardian Text Sans Web", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; + font-size: 0.875rem; + line-height: 1.3; + font-weight: 400; + font-style: italic; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-text-sans-italic-15')).toMatchCSS( + `.src-text-sans-italic-15 { + font-family: GuardianTextSans, "Guardian Text Sans Web", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; + font-size: 0.9375rem; + line-height: 1.3; + font-weight: 400; + font-style: italic; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-text-sans-italic-17')).toMatchCSS( + `.src-text-sans-italic-17 { + font-family: GuardianTextSans, "Guardian Text Sans Web", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; + font-size: 1.0625rem; + line-height: 1.3; + font-weight: 400; + font-style: italic; + --source-text-decoration-thickness: 2px; + }`, + ); + expect(findRule('src-text-sans-italic-20')).toMatchCSS( + `.src-text-sans-italic-20 { + font-family: GuardianTextSans, "Guardian Text Sans Web", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; + font-size: 1.25rem; + line-height: 1.3; + font-weight: 400; + font-style: italic; + --source-text-decoration-thickness: 3px; + }`, + ); + expect(findRule('src-text-sans-italic-24')).toMatchCSS( + `.src-text-sans-italic-24 { + font-family: GuardianTextSans, "Guardian Text Sans Web", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; + font-size: 1.5rem; + line-height: 1.3; + font-weight: 400; + font-style: italic; + --source-text-decoration-thickness: 3px; + }`, + ); + expect(findRule('src-text-sans-italic-28')).toMatchCSS( + `.src-text-sans-italic-28 { + font-family: GuardianTextSans, "Guardian Text Sans Web", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; + font-size: 1.75rem; + line-height: 1.3; + font-weight: 400; + font-style: italic; + --source-text-decoration-thickness: 3px; + }`, + ); + expect(findRule('src-text-sans-italic-34')).toMatchCSS( + `.src-text-sans-italic-34 { + font-family: GuardianTextSans, "Guardian Text Sans Web", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; + font-size: 2.125rem; + line-height: 1.3; + font-weight: 400; + font-style: italic; + --source-text-decoration-thickness: 4px; + }`, + ); + expect(findRule('src-titlepiece-42')).toMatchCSS( + `.src-titlepiece-42 { + font-family: "GT Guardian Titlepiece", Georgia, serif; + font-size: 2.625rem; + line-height: 1.15; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 5px; + }`, + ); + expect(findRule('src-titlepiece-50')).toMatchCSS( + `.src-titlepiece-50 { + font-family: "GT Guardian Titlepiece", Georgia, serif; + font-size: 3.125rem; + line-height: 1.15; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 6px; + }`, + ); + expect(findRule('src-titlepiece-70')).toMatchCSS( + `.src-titlepiece-70 { + font-family: "GT Guardian Titlepiece", Georgia, serif; + font-size: 4.375rem; + line-height: 1.15; + font-weight: 700; + font-style: normal; + --source-text-decoration-thickness: 6px; + }`, + ); + }); +}); describe('Palette theme tokens (deprecated)', () => { it('should match expected output', () => { diff --git a/package.json b/package.json index d38fa12f5..5f3f3e21e 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,9 @@ "react-dom" ] }, + "overrides": { + "@types/glob": "^8.1.0" + }, "patchedDependencies": { "jsdom@26.1.0": "patches/jsdom@26.1.0.patch" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 93a28e3ad..8578fd98e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,6 +4,9 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +overrides: + '@types/glob': ^8.1.0 + patchedDependencies: jsdom@26.1.0: hash: bld754pt2rccrfojs6tbcgt5kq @@ -695,6 +698,12 @@ importers: mkdirp: specifier: 3.0.1 version: 3.0.1 + postcss: + specifier: 8.5.6 + version: 8.5.6 + postcss-scss: + specifier: 4.0.9 + version: 4.0.9(postcss@8.5.6) prettier: specifier: 3.3.3 version: 3.3.3 @@ -707,6 +716,9 @@ importers: rollup: specifier: 4.50.1 version: 4.50.1 + rollup-plugin-copy: + specifier: 3.5.0 + version: 3.5.0 storybook: specifier: 8.6.4 version: 8.6.4(prettier@3.3.3) @@ -4289,6 +4301,19 @@ packages: '@types/node': 22.10.0 dev: true + /@types/fs-extra@8.1.5: + resolution: {integrity: sha512-0dzKcwO+S8s2kuF5Z9oUWatQJj5Uq/iqphEtE3GQJVRRYm/tD1LglU2UnXi2A8jLq5umkGouOXOR9y0n613ZwQ==} + dependencies: + '@types/node': 22.10.0 + dev: true + + /@types/glob@8.1.0: + resolution: {integrity: sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==} + dependencies: + '@types/minimatch': 5.1.2 + '@types/node': 22.10.0 + dev: true + /@types/hast@3.0.4: resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} dependencies: @@ -4340,6 +4365,10 @@ packages: resolution: {integrity: sha512-iJt33IQnVRkqeqC7PzBHPTC6fDlRNRW8vjrgqtScAhrmMwe8c4Eo7+fUGTa+XdWrpEgpyKWMYmi2dIwMAYRzPw==} dev: true + /@types/minimatch@5.1.2: + resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==} + dev: true + /@types/ms@2.1.0: resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} dev: true @@ -5598,6 +5627,10 @@ packages: dev: true optional: true + /colorette@1.4.0: + resolution: {integrity: sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==} + dev: true + /colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} @@ -7134,6 +7167,20 @@ packages: gopd: 1.2.0 dev: false + /globby@10.0.1: + resolution: {integrity: sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A==} + engines: {node: '>=8'} + dependencies: + '@types/glob': 8.1.0 + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.2 + glob: 7.2.3 + ignore: 5.3.2 + merge2: 1.4.1 + slash: 3.0.0 + dev: true + /globby@11.1.0: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} engines: {node: '>=10'} @@ -7654,6 +7701,11 @@ packages: engines: {node: '>=12'} dev: true + /is-plain-object@3.0.1: + resolution: {integrity: sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==} + engines: {node: '>=0.10.0'} + dev: true + /is-potential-custom-element-name@1.0.1: resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} dev: true @@ -9705,6 +9757,15 @@ packages: resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} + /postcss-scss@4.0.9(postcss@8.5.6): + resolution: {integrity: sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.4.29 + dependencies: + postcss: 8.5.6 + dev: true + /postcss@8.5.6: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} @@ -10235,6 +10296,17 @@ packages: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} dev: true + /rollup-plugin-copy@3.5.0: + resolution: {integrity: sha512-wI8D5dvYovRMx/YYKtUNt3Yxaw4ORC9xo6Gt9t22kveWz1enG9QrhVlagzwrxSC455xD1dHMKhIJkbsQ7d48BA==} + engines: {node: '>=8.3'} + dependencies: + '@types/fs-extra': 8.1.5 + colorette: 1.4.0 + fs-extra: 8.1.0 + globby: 10.0.1 + is-plain-object: 3.0.1 + dev: true + /rollup-plugin-dts@6.2.1(rollup@4.50.1)(typescript@5.5.2): resolution: {integrity: sha512-sR3CxYUl7i2CHa0O7bA45mCrgADyAQ0tVtGSqi3yvH28M+eg1+g5d7kQ9hLvEz5dorK3XVsH5L2jwHLQf72DzA==} engines: {node: '>=16'}