diff --git a/CHANGELOG.md b/CHANGELOG.md index 44584056dfd8..fb44a74c7ef8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Simplify the `sans` font-family stack ([#11748](https://github.com/tailwindlabs/tailwindcss/pull/11748)) - Disable the tap highlight overlay on iOS ([#12299](https://github.com/tailwindlabs/tailwindcss/pull/12299)) +- Improve relative precedence of `rtl`, `ltr`, `forced-colors`, and `dark` variants ([#12584](https://github.com/tailwindlabs/tailwindcss/pull/12584)) - [Oxide] Deprecate `--no-autoprefixer` flag in the CLI ([#11280](https://github.com/tailwindlabs/tailwindcss/pull/11280)) - [Oxide] Make the Rust based parser the default ([#11394](https://github.com/tailwindlabs/tailwindcss/pull/11394)) diff --git a/src/corePlugins.js b/src/corePlugins.js index b4ef04216c03..6b2f88ffcf82 100644 --- a/src/corePlugins.js +++ b/src/corePlugins.js @@ -206,8 +206,8 @@ export let variantPlugins = { }, directionVariants: ({ addVariant }) => { - addVariant('ltr', ':is([dir="ltr"] &)') - addVariant('rtl', ':is([dir="rtl"] &)') + addVariant('ltr', ':is(:where([dir="ltr"]) &)') + addVariant('rtl', ':is(:where([dir="rtl"]) &)') }, reducedMotionVariants: ({ addVariant }) => { @@ -228,7 +228,7 @@ export let variantPlugins = { } if (mode === 'class') { - addVariant('dark', `:is(${className} &)`) + addVariant('dark', `:is(:where(${className}) &)`) } else if (mode === 'media') { addVariant('dark', '@media (prefers-color-scheme: dark)') } diff --git a/src/lib/setupContextUtils.js b/src/lib/setupContextUtils.js index 6920eb4dbf78..e677399b8b8e 100644 --- a/src/lib/setupContextUtils.js +++ b/src/lib/setupContextUtils.js @@ -755,14 +755,14 @@ function resolvePlugins(context, root) { ] let afterVariants = [ variantPlugins['supportsVariants'], - variantPlugins['directionVariants'], variantPlugins['reducedMotionVariants'], variantPlugins['prefersContrastVariants'], - variantPlugins['darkVariants'], - variantPlugins['forcedColorsVariants'], variantPlugins['printVariant'], variantPlugins['screenVariants'], variantPlugins['orientationVariants'], + variantPlugins['directionVariants'], + variantPlugins['darkVariants'], + variantPlugins['forcedColorsVariants'], ] return [...corePluginList, ...beforeVariants, ...userPlugins, ...afterVariants, ...layerPlugins] diff --git a/tests/apply-important-selector.test.js b/tests/apply-important-selector.test.js index 22c1dd88f761..28c364566864 100644 --- a/tests/apply-important-selector.test.js +++ b/tests/apply-important-selector.test.js @@ -1,25 +1,25 @@ import { applyImportantSelector } from '../src/util/applyImportantSelector' it.each` - before | after - ${'.foo'} | ${'#app :is(.foo)'} - ${'.foo .bar'} | ${'#app :is(.foo .bar)'} - ${'.foo:hover'} | ${'#app :is(.foo:hover)'} - ${'.foo .bar:hover'} | ${'#app :is(.foo .bar:hover)'} - ${'.foo::before'} | ${'#app :is(.foo)::before'} - ${'.foo::before'} | ${'#app :is(.foo)::before'} - ${'.foo::file-selector-button'} | ${'#app :is(.foo)::file-selector-button'} - ${'.foo::-webkit-progress-bar'} | ${'#app :is(.foo)::-webkit-progress-bar'} - ${'.foo:hover::before'} | ${'#app :is(.foo:hover)::before'} - ${':is(.dark :is([dir="rtl"] .foo::before))'} | ${'#app :is(.dark :is([dir="rtl"] .foo))::before'} - ${':is(.dark .foo) .bar'} | ${'#app :is(:is(.dark .foo) .bar)'} - ${':is(.foo) :is(.bar)'} | ${'#app :is(:is(.foo) :is(.bar))'} - ${':is(.foo)::before'} | ${'#app :is(.foo)::before'} - ${'.foo:before'} | ${'#app :is(.foo):before'} - ${'.foo::some-unknown-pseudo'} | ${'#app :is(.foo)::some-unknown-pseudo'} - ${'.foo::some-unknown-pseudo:hover'} | ${'#app :is(.foo)::some-unknown-pseudo:hover'} - ${'.foo:focus::some-unknown-pseudo:hover'} | ${'#app :is(.foo:focus)::some-unknown-pseudo:hover'} - ${'.foo:hover::some-unknown-pseudo:focus'} | ${'#app :is(.foo:hover)::some-unknown-pseudo:focus'} + before | after + ${'.foo'} | ${'#app :is(.foo)'} + ${'.foo .bar'} | ${'#app :is(.foo .bar)'} + ${'.foo:hover'} | ${'#app :is(.foo:hover)'} + ${'.foo .bar:hover'} | ${'#app :is(.foo .bar:hover)'} + ${'.foo::before'} | ${'#app :is(.foo)::before'} + ${'.foo::before'} | ${'#app :is(.foo)::before'} + ${'.foo::file-selector-button'} | ${'#app :is(.foo)::file-selector-button'} + ${'.foo::-webkit-progress-bar'} | ${'#app :is(.foo)::-webkit-progress-bar'} + ${'.foo:hover::before'} | ${'#app :is(.foo:hover)::before'} + ${':is(:where(.dark) :is(:where([dir="rtl"]) .foo::before))'} | ${'#app :is(:where(.dark) :is(:where([dir="rtl"]) .foo))::before'} + ${':is(:where(.dark) .foo) .bar'} | ${'#app :is(:is(:where(.dark) .foo) .bar)'} + ${':is(.foo) :is(.bar)'} | ${'#app :is(:is(.foo) :is(.bar))'} + ${':is(.foo)::before'} | ${'#app :is(.foo)::before'} + ${'.foo:before'} | ${'#app :is(.foo):before'} + ${'.foo::some-unknown-pseudo'} | ${'#app :is(.foo)::some-unknown-pseudo'} + ${'.foo::some-unknown-pseudo:hover'} | ${'#app :is(.foo)::some-unknown-pseudo:hover'} + ${'.foo:focus::some-unknown-pseudo:hover'} | ${'#app :is(.foo:focus)::some-unknown-pseudo:hover'} + ${'.foo:hover::some-unknown-pseudo:focus'} | ${'#app :is(.foo:hover)::some-unknown-pseudo:focus'} `('should generate "$after" from "$before"', ({ before, after }) => { expect(applyImportantSelector(before, '#app')).toEqual(after) }) diff --git a/tests/apply.test.js b/tests/apply.test.js index 27b5f761ecfd..6c79db2b74e1 100644 --- a/tests/apply.test.js +++ b/tests/apply.test.js @@ -215,14 +215,14 @@ test('@apply', () => { text-align: left; } } - :is(.dark .apply-dark-variant) { + :is(:where(.dark) .apply-dark-variant) { text-align: center; } - :is(.dark .apply-dark-variant:hover) { + :is(:where(.dark) .apply-dark-variant:hover) { text-align: right; } @media (min-width: 1024px) { - :is(.dark .apply-dark-variant) { + :is(:where(.dark) .apply-dark-variant) { text-align: left; } } @@ -2016,24 +2016,28 @@ it('pseudo elements inside apply are moved outside of :is() or :has()', () => { return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` - :is(.dark .foo):before, - :is([dir='rtl'] :is(.dark .bar)):before, - :is([dir='rtl'] :is(.dark .baz:hover)):before { + :is(:where(.dark) .foo):before, + :is(:where([dir='rtl']) :is(:where(.dark) .bar)):before, + :is(:where([dir='rtl']) :is(:where(.dark) .baz:hover)):before { background-color: #000; } - :-webkit-any([dir='rtl'] :-webkit-any(.dark .qux))::-webkit-file-upload-button:hover { + :-webkit-any( + :where([dir='rtl']) :-webkit-any(:where(.dark) .qux) + )::-webkit-file-upload-button:hover { background-color: #000; } - :is([dir='rtl'] :is(.dark .qux))::file-selector-button:hover { + :is(:where([dir='rtl']) :is(:where(.dark) .qux))::file-selector-button:hover { background-color: #000; } - :is([dir='rtl'] :is(.dark .steve):hover):before { + :is(:where([dir='rtl']) :is(:where(.dark) .steve):hover):before { background-color: #000; } - :-webkit-any([dir='rtl'] :-webkit-any(.dark .bob))::-webkit-file-upload-button:hover { + :-webkit-any( + :where([dir='rtl']) :-webkit-any(:where(.dark) .bob) + )::-webkit-file-upload-button:hover { background-color: #000; } - :is([dir='rtl'] :is(.dark .bob))::file-selector-button:hover { + :is(:where([dir='rtl']) :is(:where(.dark) .bob))::file-selector-button:hover { background-color: #000; } :has([dir='rtl'] .foo:hover):before { diff --git a/tests/custom-separator.test.js b/tests/custom-separator.test.js index 3b1708dfbfba..a839c547942b 100644 --- a/tests/custom-separator.test.js +++ b/tests/custom-separator.test.js @@ -22,22 +22,22 @@ test('custom separator', () => { .group:hover .group-hover_focus-within_text-left:focus-within { text-align: left; } - :is([dir='rtl'] .rtl_active_text-center:active) { - text-align: center; - } @media (prefers-reduced-motion: no-preference) { .motion-safe_hover_text-center:hover { text-align: center; } } - :is(.dark .dark_focus_text-left:focus) { - text-align: left; - } @media (min-width: 768px) { .md_hover_text-right:hover { text-align: right; } } + :is(:where([dir='rtl']) .rtl_active_text-center:active) { + text-align: center; + } + :is(:where(.dark) .dark_focus_text-left:focus) { + text-align: left; + } `) }) }) diff --git a/tests/dark-mode.test.js b/tests/dark-mode.test.js index 0c5273991939..276c6c9e3c87 100644 --- a/tests/dark-mode.test.js +++ b/tests/dark-mode.test.js @@ -16,7 +16,7 @@ it('should be possible to use the darkMode "class" mode', () => { return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` ${defaults} - :is(.dark .dark\:font-bold) { + :is(:where(.dark) .dark\:font-bold) { font-weight: 700; } `) @@ -39,7 +39,7 @@ it('should be possible to change the class name', () => { return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` ${defaults} - :is(.test-dark .dark\:font-bold) { + :is(:where(.test-dark) .dark\:font-bold) { font-weight: 700; } `) diff --git a/tests/format-variant-selector.test.js b/tests/format-variant-selector.test.js index 9ad2c632e2db..21343b58d78e 100644 --- a/tests/format-variant-selector.test.js +++ b/tests/format-variant-selector.test.js @@ -343,8 +343,8 @@ describe('pseudo elements', () => { ${'.parent::before &:hover'} | ${'.parent &:hover::before'} ${':where(&::before) :is(h1, h2, h3, h4)'} | ${':where(&) :is(h1, h2, h3, h4)::before'} ${':where(&::file-selector-button) :is(h1, h2, h3, h4)'} | ${':where(&::file-selector-button) :is(h1, h2, h3, h4)'} - ${'#app :is(.dark &::before)'} | ${'#app :is(.dark &)::before'} - ${'#app :is(:is(.dark &)::before)'} | ${'#app :is(:is(.dark &))::before'} + ${'#app :is(:where(.dark) &::before)'} | ${'#app :is(:where(.dark) &)::before'} + ${'#app :is(:is(:where(.dark) &)::before)'} | ${'#app :is(:is(:where(.dark) &))::before'} ${'#app :is(.foo::file-selector-button)'} | ${'#app :is(.foo)::file-selector-button'} ${'#app :is(.foo::-webkit-progress-bar)'} | ${'#app :is(.foo)::-webkit-progress-bar'} ${'.parent::marker li'} | ${'.parent li::marker'} diff --git a/tests/important-boolean.test.js b/tests/important-boolean.test.js index d66f21edc6f3..ec49b42439f5 100644 --- a/tests/important-boolean.test.js +++ b/tests/important-boolean.test.js @@ -137,22 +137,22 @@ test('important boolean', () => { .group:hover .group-hover\:focus-within\:text-left:focus-within { text-align: left !important; } - :is([dir='rtl'] .rtl\:active\:text-center:active) { - text-align: center !important; - } @media (prefers-reduced-motion: no-preference) { .motion-safe\:hover\:text-center:hover { text-align: center !important; } } - :is(.dark .dark\:focus\:text-left:focus) { - text-align: left !important; - } @media (min-width: 768px) { .md\:hover\:text-right:hover { text-align: right !important; } } + :is(:where([dir='rtl']) .rtl\:active\:text-center:active) { + text-align: center !important; + } + :is(:where(.dark) .dark\:focus\:text-left:focus) { + text-align: left !important; + } `) }) }) diff --git a/tests/important-selector.test.js b/tests/important-selector.test.js index 1ec20922cb37..aea4f1547ca5 100644 --- a/tests/important-selector.test.js +++ b/tests/important-selector.test.js @@ -135,36 +135,39 @@ test('important selector', () => { #app :is(.group:hover .group-hover\:focus-within\:text-left:focus-within) { text-align: left; } - #app :is([dir='rtl'] .rtl\:active\:text-center:active) { - text-align: center; - } @media (prefers-reduced-motion: no-preference) { #app .motion-safe\:hover\:text-center:hover { text-align: center; } } - #app :is(.dark .dark\:before\:underline):before { - content: var(--tw-content); - text-decoration-line: underline; - } - #app :is(.dark .dark\:focus\:text-left:focus) { - text-align: left; - } @media (min-width: 768px) { #app .md\:hover\:text-right:hover { text-align: right; } } + #app :is(:where([dir='rtl']) .rtl\:active\:text-center:active) { + text-align: center; + } + #app :is(:where(.dark) .dark\:before\:underline):before { + content: var(--tw-content); + text-decoration-line: underline; + } + #app :is(:where(.dark) .dark\:focus\:text-left:focus) { + text-align: left; + } #app :-webkit-any( - [dir='rtl'] - :-webkit-any(.dark .hover\:\[\&\:\:file-selector-button\]\:rtl\:dark\:bg-black\/100) + :where([dir='rtl']) + :-webkit-any( + :where(.dark) .hover\:\[\&\:\:file-selector-button\]\:rtl\:dark\:bg-black\/100 + ) )::-webkit-file-upload-button:hover { background-color: #000; } #app :is( - [dir='rtl'] :is(.dark .hover\:\[\&\:\:file-selector-button\]\:rtl\:dark\:bg-black\/100) + :where([dir='rtl']) + :is(:where(.dark) .hover\:\[\&\:\:file-selector-button\]\:rtl\:dark\:bg-black\/100) )::file-selector-button:hover { background-color: #000; } @@ -193,7 +196,7 @@ test('pseudo-elements are appended after the `:-webkit-any()`', () => { return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` ${defaults} - #app :is(.dark .dark\:before\:flex):before { + #app :is(:where(.dark) .dark\:before\:flex):before { content: var(--tw-content); display: flex; } diff --git a/tests/kitchen-sink.test.js b/tests/kitchen-sink.test.js index 7f64c5c1d397..2151f22db952 100644 --- a/tests/kitchen-sink.test.js +++ b/tests/kitchen-sink.test.js @@ -304,7 +304,7 @@ test('it works', () => { } .drop-empty-rules:hover, .group:hover .apply-group, - :is(.dark .apply-dark-mode) { + :is(:where(.dark) .apply-dark-mode) { font-weight: 700; } .apply-with-existing:hover { @@ -339,7 +339,7 @@ test('it works', () => { .apply-order-b { margin: 1.5rem 1.25rem 1.25rem; } - :is(.dark .group:hover .apply-dark-group-example-a) { + :is(:where(.dark) .group:hover .apply-dark-group-example-a) { --tw-bg-opacity: 1; background-color: rgb(34 197 94 / var(--tw-bg-opacity)); } @@ -744,9 +744,6 @@ test('it works', () => { transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); } } - :is(.dark .dark\:custom-util) { - background: #abcdef; - } @media (min-width: 640px) { .sm\:text-center { text-align: center; @@ -792,9 +789,6 @@ test('it works', () => { transition-duration: 0.15s; transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); } - :is(.dark .md\:dark\:motion-safe\:foo\:active\:custom-util:active) { - background: #abcdef !important; - } } @media (min-width: 640px) { .md\:sm\:text-center { @@ -812,6 +806,16 @@ test('it works', () => { text-align: left; } } + :is(:where(.dark) .dark\:custom-util) { + background: #abcdef; + } + @media (min-width: 768px) { + @media (prefers-reduced-motion: no-preference) { + :is(:where(.dark) .md\:dark\:motion-safe\:foo\:active\:custom-util:active) { + background: #abcdef !important; + } + } + } `) }) }) diff --git a/tests/plugins/variants/__snapshots__/darkVariants.test.js.snap b/tests/plugins/variants/__snapshots__/darkVariants.test.js.snap index 0a3dda916fa9..5414de562dbf 100644 --- a/tests/plugins/variants/__snapshots__/darkVariants.test.js.snap +++ b/tests/plugins/variants/__snapshots__/darkVariants.test.js.snap @@ -12,7 +12,7 @@ exports[`should test the 'darkVariants' plugin 1`] = ` exports[`should test the 'darkVariants' plugin 2`] = ` " -:is(.dark .dark\\:flex) { +:is(:where(.dark) .dark\\:flex) { display: flex; } " @@ -20,7 +20,7 @@ exports[`should test the 'darkVariants' plugin 2`] = ` exports[`should test the 'darkVariants' plugin 3`] = ` " -:is(.my-dark-mode .dark\\:flex) { +:is(:where(.my-dark-mode) .dark\\:flex) { display: flex; } " diff --git a/tests/plugins/variants/__snapshots__/directionVariants.test.js.snap b/tests/plugins/variants/__snapshots__/directionVariants.test.js.snap index 1ee2f8952d32..3f3f79cf96ed 100644 --- a/tests/plugins/variants/__snapshots__/directionVariants.test.js.snap +++ b/tests/plugins/variants/__snapshots__/directionVariants.test.js.snap @@ -2,7 +2,7 @@ exports[`should test the 'directionVariants' plugin 1`] = ` " -:is([dir="ltr"] .ltr\\:flex), :is([dir="rtl"] .rtl\\:flex) { +:is(:where([dir="ltr"]) .ltr\\:flex), :is(:where([dir="rtl"]) .rtl\\:flex) { display: flex; } " diff --git a/tests/prefix.test.js b/tests/prefix.test.js index 79b8413e8eb0..a0ce18cbd5fa 100644 --- a/tests/prefix.test.js +++ b/tests/prefix.test.js @@ -126,7 +126,7 @@ test('prefix', () => { .custom-component { font-weight: 700; } - :is(.tw-dark .tw-group:hover .custom-component) { + :is(:where(.tw-dark) .tw-group:hover .custom-component) { font-weight: 400; } .tw--ml-4 { @@ -153,21 +153,11 @@ test('prefix', () => { .tw-group:hover .group-hover\:focus-within\:tw-text-left:focus-within { text-align: left; } - :is([dir='rtl'] .rtl\:active\:tw-text-center:active) { - text-align: center; - } @media (prefers-reduced-motion: no-preference) { .motion-safe\:hover\:tw-text-center:hover { text-align: center; } } - :is(.tw-dark .dark\:tw-bg-\[rgb\(255\,0\,0\)\]) { - --tw-bg-opacity: 1; - background-color: rgb(255 0 0 / var(--tw-bg-opacity)); - } - :is(.tw-dark .dark\:focus\:tw-text-left:focus) { - text-align: left; - } @media (min-width: 768px) { .md\:tw--ml-5 { margin-left: -1.25rem; @@ -179,6 +169,16 @@ test('prefix', () => { text-align: right; } } + :is(:where([dir='rtl']) .rtl\:active\:tw-text-center:active) { + text-align: center; + } + :is(:where(.tw-dark) .dark\:tw-bg-\[rgb\(255\,0\,0\)\]) { + --tw-bg-opacity: 1; + background-color: rgb(255 0 0 / var(--tw-bg-opacity)); + } + :is(:where(.tw-dark) .dark\:focus\:tw-text-left:focus) { + text-align: left; + } `) }) }) diff --git a/tests/variants.test.css b/tests/variants.test.css index 043ce991ee4a..bf3275257dc9 100644 --- a/tests/variants.test.css +++ b/tests/variants.test.css @@ -270,9 +270,7 @@ .peer:enabled ~ .peer-enabled\:flex, .peer:disabled ~ .peer-disabled\:flex, .peer:disabled:focus:hover ~ .peer-disabled\:peer-focus\:peer-hover\:flex, -.peer:disabled:focus:hover ~ .peer-disabled\:peer-focus\:peer-hover\:first\:flex:first-child, -:is([dir='ltr'] .ltr\:flex), -:is([dir='rtl'] .rtl\:flex) { +.peer:disabled:focus:hover ~ .peer-disabled\:peer-focus\:peer-hover\:first\:flex:first-child { display: flex; } @media (prefers-reduced-motion: no-preference) { @@ -295,16 +293,6 @@ display: flex; } } -:is(.dark .dark\:flex), -:is(.dark .group:disabled:focus:hover .dark\:group-disabled\:group-focus\:group-hover\:flex), -:is(.dark .peer:disabled:focus:hover ~ .dark\:peer-disabled\:peer-focus\:peer-hover\:flex) { - display: flex; -} -@media (forced-colors: active) { - .forced-colors\:flex { - display: flex; - } -} @media print { .print\:flex { display: flex; @@ -323,14 +311,12 @@ } } @media (min-width: 1024px) { - .lg\:flex, - :is(.dark .lg\:dark\:flex) { + .lg\:flex { display: flex; } } @media (min-width: 1280px) { - .xl\:flex, - :is(.dark .xl\:dark\:disabled\:flex:disabled) { + .xl\:flex { display: flex; } } @@ -338,11 +324,6 @@ .\32 xl\:flex { display: flex; } - @media (prefers-reduced-motion: no-preference) { - :is(.dark .\32 xl\:dark\:motion-safe\:focus-within\:flex:focus-within) { - display: flex; - } - } } @media (orientation: portrait) { .portrait\:flex { @@ -354,3 +335,34 @@ display: flex; } } +:is(:where([dir='ltr']) .ltr\:flex), +:is(:where([dir='rtl']) .rtl\:flex), +:is(:where(.dark) .dark\:flex), +:is( + :where(.dark) .group:disabled:focus:hover .dark\:group-disabled\:group-focus\:group-hover\:flex + ), +:is(:where(.dark) .peer:disabled:focus:hover ~ .dark\:peer-disabled\:peer-focus\:peer-hover\:flex) { + display: flex; +} +@media (min-width: 1024px) { + :is(:where(.dark) .lg\:dark\:flex) { + display: flex; + } +} +@media (min-width: 1280px) { + :is(:where(.dark) .xl\:dark\:disabled\:flex:disabled) { + display: flex; + } +} +@media (min-width: 1536px) { + @media (prefers-reduced-motion: no-preference) { + :is(:where(.dark) .\32 xl\:dark\:motion-safe\:focus-within\:flex:focus-within) { + display: flex; + } + } +} +@media (forced-colors: active) { + .forced-colors\:flex { + display: flex; + } +} diff --git a/tests/variants.test.js b/tests/variants.test.js index 8a0509828a25..513b950a6238 100644 --- a/tests/variants.test.js +++ b/tests/variants.test.js @@ -1138,7 +1138,7 @@ test('stacking dark and rtl variants', async () => { let result = await run(input, config) expect(result.css).toMatchFormattedCss(css` - :is(.dark :is([dir='rtl'] .dark\:rtl\:italic)) { + :is(:where(.dark) :is(:where([dir='rtl']) .dark\:rtl\:italic)) { font-style: italic; } `) @@ -1162,7 +1162,7 @@ test('stacking dark and rtl variants with pseudo elements', async () => { let result = await run(input, config) expect(result.css).toMatchFormattedCss(css` - :is(.dark :is([dir='rtl'] .dark\:rtl\:placeholder\:italic))::placeholder { + :is(:where(.dark) :is(:where([dir='rtl']) .dark\:rtl\:placeholder\:italic))::placeholder { font-style: italic; } `)