Repository: francoismassart/eslint-plugin-tailwindcss
Pull request #75 (2021-12-27 22:37:50)

3.0.0
First version of major 3, supporting TailwindCSS v3


Patch:
diff --git a/README.md b/README.md
index 1c298f8..a0c90f8 100644
--- a/README.md
+++ b/README.md
@@ -4,41 +4,60 @@
 
 ![eslint-plugin-tailwindcss logo](.github/logo.png)
 
-Rules enforcing best practices and consistency using [Tailwind CSS](https://tailwindcss.com/) v2.1.2
+Rules enforcing best practices and consistency using [Tailwind CSS](https://tailwindcss.com/)
 
-> **🎉 Since v1.5.0, the plugin will parse the `tailwind.config.js` file and use the correct values based on your own settings.**
->
-> 👍 Most of [the new JIT mode features](https://tailwindcss.com/docs/just-in-time-mode#new-features) are also supported.
+## **🎉 The version 3 of plugin is now ready for TailwindCSS v3 🎉**
 
-## Latest changelog
+## Make sure to use the correct version
+
+- Still using TailwindCSS v2 ?
+  - You should stick with `v1.x.x` or `v2.x.x` of this plugin (next support releases will be using major version `2`)
+- Using TailwindCSS v3 ?
+  - Make sure to use `v3.x.x` of this plugin
+
+## We need you ❤️
 
-- FIX: [classname `aspect-none` should be valid](https://github.com/francoismassart/eslint-plugin-tailwindcss/issues/63)
+Version 3 of the plugin is brand new and you will most likely experience bugs, please provide feedback by opening issues on GitHub with all the useful informations so that we can fix them all.
 
-- FIX: [Invalid regular expression](https://github.com/francoismassart/eslint-plugin-tailwindcss/issues/62)
+If you enjoy my work you can:
 
-- Handling `Literal` attribute values (e.g. `className={'...'}` mind the curly brackets) instead of ignoring them
+- [Share the plugin on Twitter](https://twitter.com/hashtag/eslint-plugin-tailwindcss)
+- Contribute to the project by:
+  - Giving feedback
+  - Creating an issue
+  - Make a pull request
+  - Write a feature request
+- Give back and [sponsor its development](https://github.com/sponsors/francoismassart)
+
+## Latest changelog
 
-- FIX: issue with trim and `TemplateLiteral` causing unwanted concatenation of classnames
+- New rule: [`migration-from-tailwind-2`](docs/rules/migration-from-tailwind-2.md) for easy migration from TailwindCSS `v2` to `v3`
 
-- Support for [per-side border-color in JIT](https://github.com/tailwindlabs/tailwindcss/pull/4404)
+- Support for TailwindCSS v3
 
-- Better support for [JIT mode arbitrary values](https://github.com/francoismassart/eslint-plugin-tailwindcss/pull/40)
+  - New config matching the updated docs
+  - Support for arbitrary properties
 
-- Support for [color opacity shorthand](https://tailwindcss.com/docs/just-in-time-mode#color-opacity-shorthand)
+- `groupByResponsive` is enabled by default for `classnames-order`
 
 [View all releases on github](https://github.com/francoismassart/eslint-plugin-tailwindcss/releases)
 
-## Sponsors
+## Monthly sponsors
 
 <a href="https://daily.dev/" target="_blank">
   <img width="150px" src="https://raw.githubusercontent.com/francoismassart/eslint-plugin-tailwindcss/master/sponsors/daily.dev.jpg">
 </a>
 
+## One-time sponsors
+
+[TheoBr](https://github.com/TheoBr) sponsorship gave me a little extra motivation. Thanks, man
+
 ## Supported Rules
 
 Learn more about each supported rules by reading their documentation:
 
 - [`classnames-order`](docs/rules/classnames-order.md): order classnames by target properties then by variants (`[size:][theme:][state:]`)
+- [`migration-from-tailwind-2`](docs/rules/migration-from-tailwind-2.md) for easy upgrade from TailwindCSS `v2` to `v3`
 - [`no-custom-classname`](docs/rules/no-custom-classname.md): only allow classnames from Tailwind CSS and the values from the `whitelist` option
 - [`no-contradicting-classname`](docs/rules/no-contradicting-classname.md): e.g. avoid `p-2 p-3`, different Tailwind CSS classnames (`pt-2` & `pt-3`) but targeting the same property several times for the same variant.
 
@@ -89,6 +108,7 @@ Configure the rules you want to use under the rules section.
 {
   "rules": {
     "tailwindcss/classnames-order": "warn",
+    "tailwindcss/migration-from-tailwind-2": "warn",
     "tailwindcss/no-custom-classname": "warn",
     "tailwindcss/no-contradicting-classname": "error"
   }
@@ -132,6 +152,10 @@ The plugin will look for each setting value in this order and stop looking as so
 
 ## Upcoming Rules
 
+- `enforces-shorthand`: Make sure you group properties inside a shorthand when possible e.g. `mx-5 my-5` should become `m-5`
+
+- `validate-modifiers`: I don't know if possible, but I'd like to make sure all the modifiers prefixes of a classname are valid e.g. `yolo:bg-red` should throw an error...
+
 - `no-redundant-variant`: e.g. avoid `mx-5 sm:mx-5`, no need to redefine `mx` in `sm:` variant as it uses the same value (`5`)
 
 - `only-valid-arbitrary-values`:
diff --git a/docs/rules/classnames-order.md b/docs/rules/classnames-order.md
index ef20c15..0b7410d 100644
--- a/docs/rules/classnames-order.md
+++ b/docs/rules/classnames-order.md
@@ -28,7 +28,8 @@ Examples of **correct** code for this rule:
   "groupByResponsive": <boolean>,
   "groups": Array<object>,
   "prependCustom": <boolean>,
-  "removeDuplicates": <boolean>
+  "removeDuplicates": <boolean>,
+  "tags": Array<string>,
 }]
 ...
 ```
@@ -53,19 +54,24 @@ It is also possible to directly inject a configuration as plain `object` like `{
 
 Finally, the plugin will [merge the provided configuration](https://tailwindcss.com/docs/configuration#referencing-in-java-script) with [Tailwind CSS's default configuration](https://github.com/tailwindlabs/tailwindcss/blob/master/stubs/defaultConfig.stub.js).
 
-### `groupByResponsive` (default: `false`)
+### `groupByResponsive` (default: `true`)
+
+When this option was introduced in version 2.x.x of the plugin, this setting was set to `false` to avoid a tsunami of reorder in the classnames.
+You had to set it to `true` intentionally.
+
+Since version 3 of the plugin, the default value is now `true`, grouping by responsive modifier in priority vs. grouping by property.
 
 Linting this code:
 
 `<div class="rounded sm:rounded-lg lg:rounded-2xl p-4 sm:p-6 lg:p-8">...</div>`
 
-By default, the ordering process will group the classnames by properties, then by variants:
+By default, the ordering process will group the classnames by variants then by properties:
 
-`<div class="p-4 sm:p-6 lg:p-8 rounded sm:rounded-lg lg:rounded-2xl">...</div>`
+`<div class="p-4 rounded sm:p-6 sm:rounded-lg lg:p-8 lg:rounded-2xl">...</div>`
 
-Set `groupByResponsive` to `true` and the ordering and you will get:
+Set `groupByResponsive` to `false` and the ordering will work by properties, then by variants:
 
-`<div class="p-4 rounded sm:p-6 sm:rounded-lg lg:p-8 lg:rounded-2xl">...</div>`
+`<div class="p-4 sm:p-6 lg:p-8 rounded sm:rounded-lg lg:rounded-2xl">...</div>`
 
 ### `groups` (default defined in [groups.js](../../lib/config/groups.js))
 
@@ -79,7 +85,7 @@ I would recommend you to duplicate the `groups.js` file, move it in your own con
 // custom-groups.js
 module.exports.groups = [
   {
-    type: 'LAYOUT',
+    type: 'Layout',
     members: [
       {
         type: 'Floats',
@@ -117,6 +123,10 @@ By default, classnames which doesn't belong to Tailwind CSS will be pushed at th
 
 Duplicate classnames are automatically removed but you can always disable this behavior by setting `removeDuplicates` to `false`.
 
+### `tags` (default: `[]`)
+
+Optional, if you are using tagged templates, you should provide the tags in this array.
+
 ## Further Reading
 
 ### How it works
@@ -137,198 +147,184 @@ The [default `groups` configuration](../../lib/config/groups.js) will apply the
 Each line represents a group (based on property).
 
 ```
-LAYOUT > Container
-LAYOUT > Box Decoration Break
-LAYOUT > Box Sizing
-LAYOUT > Display
-LAYOUT > Floats
-LAYOUT > Clear
-LAYOUT > Isolation
-LAYOUT > Object Fit
-LAYOUT > Object Position
-LAYOUT > Overflow > overflow
-LAYOUT > Overflow > overflow-x
-LAYOUT > Overflow > overflow-y
-LAYOUT > Overscroll Behavior > overscroll
-LAYOUT > Overscroll Behavior > overscroll-x
-LAYOUT > Overscroll Behavior > overscroll-y
-LAYOUT > Position
-LAYOUT > Top / Right / Bottom / Left > inset
-LAYOUT > Top / Right / Bottom / Left > inset-y
-LAYOUT > Top / Right / Bottom / Left > inset-x
-LAYOUT > Top / Right / Bottom / Left > top
-LAYOUT > Top / Right / Bottom / Left > right
-LAYOUT > Top / Right / Bottom / Left > bottom
-LAYOUT > Top / Right / Bottom / Left > left
-LAYOUT > Visibility
-LAYOUT > Z-Index
-FLEXBOX > Flex Direction
-FLEXBOX > Flex Wrap
-FLEXBOX > Flex
-FLEXBOX > Flex Grow
-FLEXBOX > Flex Shrink
-FLEXBOX > Order
-GRID > Grid Template Columns
-GRID > Grid Column Start / End > grid-column
-GRID > Grid Column Start / End > grid-column-start
-GRID > Grid Column Start / End > grid-column-end
-GRID > Grid Template Rows
-GRID > Grid Row Start / End > grid-row
-GRID > Grid Row Start / End > grid-row-start
-GRID > Grid Row Start / End > grid-row-end
-GRID > Grid Auto Flow
-GRID > Grid Auto Columns
-GRID > Grid Auto Rows
-GRID > Gap > gap
-GRID > Gap > column-gap
-GRID > Gap > row-gap
-BOX ALIGNMENT > Justify Content
-BOX ALIGNMENT > Justify Items
-BOX ALIGNMENT > Justify Self
-BOX ALIGNMENT > Align Content
-BOX ALIGNMENT > Align Items
-BOX ALIGNMENT > Align Self
-BOX ALIGNMENT > Place Content
-BOX ALIGNMENT > Place Items
-BOX ALIGNMENT > Place Self
-SPACING > Padding > p
-SPACING > Padding > py
-SPACING > Padding > px
-SPACING > Padding > pt
-SPACING > Padding > pr
-SPACING > Padding > pb
-SPACING > Padding > pl
-SPACING > Margin > m
-SPACING > Margin > my
-SPACING > Margin > mx
-SPACING > Margin > mt
-SPACING > Margin > mr
-SPACING > Margin > mb
-SPACING > Margin > ml
-SPACING > Space Between > space-y
-SPACING > Space Between > space-x
-SIZING > Width
-SIZING > Min-Width
-SIZING > Max-Width
-SIZING > Height
-SIZING > Min-Height
-SIZING > Max-Height
-TYPOGRAPHY > Font Family
-TYPOGRAPHY > Font Size
-TYPOGRAPHY > Font Smoothing
-TYPOGRAPHY > Font Style
-TYPOGRAPHY > Font Weight
-TYPOGRAPHY > Font Variant Numeric
-TYPOGRAPHY > Letter Spacing
-TYPOGRAPHY > Line Height
-TYPOGRAPHY > List Style Type
-TYPOGRAPHY > List Style Position
-TYPOGRAPHY > Placeholder Color
-TYPOGRAPHY > Placeholder Opacity
-TYPOGRAPHY > Text Alignment
-TYPOGRAPHY > Text Color
-TYPOGRAPHY > Text Opacity
-TYPOGRAPHY > Text Decoration
-TYPOGRAPHY > Text Transform
-TYPOGRAPHY > Text Overflow
-TYPOGRAPHY > Vertical Alignment
-TYPOGRAPHY > Whitespace
-TYPOGRAPHY > Word Break
-BACKGROUNDS > Background Attachment
-BACKGROUNDS > Background Clip
-BACKGROUNDS > Background Color
-BACKGROUNDS > Background Opacity
-BACKGROUNDS > Background Position
-BACKGROUNDS > Background Repeat
-BACKGROUNDS > Background Size
-BACKGROUNDS > Background Image
-BACKGROUNDS > Gradient Color Stops > from
-BACKGROUNDS > Gradient Color Stops > via
-BACKGROUNDS > Gradient Color Stops > to
-BORDERS > Border Radius > border-radius
-BORDERS > Border Radius > border-radius-top
-BORDERS > Border Radius > border-radius-right
-BORDERS > Border Radius > border-radius-bottom
-BORDERS > Border Radius > border-radius-left
-BORDERS > Border Radius > border-radius-top-left
-BORDERS > Border Radius > border-radius-top-right
-BORDERS > Border Radius > border-radius-bottom-right
-BORDERS > Border Radius > border-radius-bottom-left
-BORDERS > Border Width > border-width
-BORDERS > Border Width > border-top-width
-BORDERS > Border Width > border-right-width
-BORDERS > Border Width > border-bottom-width
-BORDERS > Border Width > border-left-width
-BORDERS > Border Color
-BORDERS > Border Opacity
-BORDERS > Border Style
-BORDERS > Divide Width > divide-y
-BORDERS > Divide Width > divide-x
-BORDERS > Divide Width > divide-y-reverse
-BORDERS > Divide Width > divide-x-reverse
-BORDERS > Divide Color
-BORDERS > Divide Opacity
-BORDERS > Divide Style
-BORDERS > Ring Width > ring
-BORDERS > Ring Width > ring-inset
-BORDERS > Ring Color
-BORDERS > Ring Opacity
-BORDERS > Ring Offset Width
-BORDERS > Ring Offset Color
-EFFECTS > Box Shadow
-EFFECTS > Opacity
-EFFECTS > Mix Blend Mode
-EFFECTS > Background Blend Mode
-FILTERS > Filter
-FILTERS > Blur
-FILTERS > Brightness
-FILTERS > Contrast
-FILTERS > Drop Shadow
-FILTERS > Grayscale
-FILTERS > Hue Rotate
-FILTERS > Invert
-FILTERS > Saturate
-FILTERS > Sepia
-FILTERS > Backdrop Filter
-FILTERS > Backdrop Blur
-FILTERS > Backdrop Brightness
-FILTERS > Backdrop Contrast
-FILTERS > Backdrop Grayscale
-FILTERS > Backdrop Hue Rotate
-FILTERS > Backdrop Invert
-FILTERS > Backdrop Opacity
-FILTERS > Backdrop Saturate
-FILTERS > Backdrop Sepia
-TABLES > Border Collapse
-TABLES > Table Layout
-TRANSITIONS AND ANIMATION > Transition Property
-TRANSITIONS AND ANIMATION > Transition Duration
-TRANSITIONS AND ANIMATION > Transition Timing Function
-TRANSITIONS AND ANIMATION > Transition Delay
-TRANSITIONS AND ANIMATION > Animation
-TRANSFORMS > Transform
-TRANSFORMS > Transform Origin
-TRANSFORMS > Scale > scale
-TRANSFORMS > Scale > scale-y
-TRANSFORMS > Scale > scale-x
-TRANSFORMS > Rotate
-TRANSFORMS > Translate > translate-x
-TRANSFORMS > Translate > translate-y
-TRANSFORMS > Skew > skew-x
-TRANSFORMS > Skew > skew-y
-INTERACTIVITY > Appearance
-INTERACTIVITY > Cursor
-INTERACTIVITY > Outline
-INTERACTIVITY > Pointer Events
-INTERACTIVITY > Resize
-INTERACTIVITY > User Select
-SVG > Fill
-SVG > Stroke
-SVG > Stroke Width
-ACCESSIBILITY > Screen Readers
-OFFICIAL PLUGINS > Typography > prose
-OFFICIAL PLUGINS > Typography > prose-modifier
-OFFICIAL PLUGINS > Aspect Ratio > aspect-w
-OFFICIAL PLUGINS > Aspect Ratio > aspect-h
-OFFICIAL PLUGINS > Line Clamp
+Core Concepts
+  Hover, Focus, & Other States
+  Dark Mode
+  Arbitrary properties
+Layout
+  Aspect Ratio
+  Container
+  Columns
+  Break After
+  Break Before
+  Break Inside
+  Box Decoration Break
+  Box Sizing
+  Display
+  Floats
+  Clear
+  Isolation
+  Object Fit
+  Object Position
+  Overflow
+  Overscroll Behavior
+  Position
+  Top / Right / Bottom / Left
+  Visibility
+  Z-Index
+Flexbox & Grid
+  Flex Basis
+  Flex Direction
+  Flex Wrap
+  Flex
+  Flex Grow
+  Flex Shrink
+  Order
+  Grid Template Columns
+  Grid Column Start / End
+  Grid Template Rows
+  Grid Row Start / End
+  Grid Auto Flow
+  Grid Auto Columns
+  Grid Auto Rows
+  Gap
+  Justify Content
+  Justify Items
+  Justify Self
+  Align Content
+  Align Items
+  Align Self
+  Place Content
+  Place Items
+  Place Self
+Spacing
+  Padding
+  Margin
+  Space Between
+Sizing
+  Width
+  Min-Width
+  Max-Width
+  Height
+  Min-Height
+  Max-Height
+Typography
+  Font Family
+  Font Size
+  Font Smoothing
+  Font Style
+  Font Weight
+  Font Variant Numeric
+  Letter Spacing
+  Line Height
+  List Style Type
+  List Style Position
+  Text Alignment
+  Text Color
+  Text Decoration
+  Text Decoration Color
+  Text Decoration Style
+  Text Decoration Thickness
+  Text Underline Offset
+  Text Transform
+  Text Overflow
+  Text Indent
+  Vertical Alignment
+  Whitespace
+  Word Break
+  Content
+Backgrounds
+  Background Attachment
+  Background Clip
+  Background Color
+  Background Origin
+  Background Position
+  Background Repeat
+  Background Size
+  Background Image
+  Gradient Color Stops
+Borders
+  Border Radius
+  Border Width
+  Border Color
+  Border Style
+  Divide Width
+  Divide Color
+  Divide Style
+  Outline Width
+  Outline Color
+  Outline Style
+  Outline Offset
+  Ring Width
+  Ring Inset
+  Ring Color
+  Ring Offset Width
+  Ring Offset Color
+Effects
+  Box Shadow
+  Box Shadow Color
+  Opacity
+  Mix Blend Mode
+  Background Blend Mode
+Filters
+  Blur
+  Brightness
+  Contrast
+  Drop Shadow
+  Grayscale
+  Hue Rotate
+  Invert
+  Saturate
+  Sepia
+  Backdrop Blur
+  Backdrop Brightness
+  Backdrop Contrast
+  Backdrop Grayscale
+  Backdrop Hue Rotate
+  Backdrop Invert
+  Backdrop Opacity
+  Backdrop Saturate
+  Backdrop Sepia
+Tables
+  Border Collapse
+  Table Layout
+Transitions & Animation
+  Transition Property
+  Transition Duration
+  Transition Timing Function
+  Transition Delay
+  Animation
+Transforms
+  Transform GPU
+  Scale
+  Rotate
+  Translate
+  Skew
+  Transform Origin
+Interactivity
+  Accent Color
+  Appearance
+  Cursor
+  Caret Color
+  Pointer Events
+  Resize
+  Scroll Behavior
+  Scroll Margin
+  Scroll Padding
+  Scroll Snap Align
+  Scroll Snap Stop
+  Scroll Snap Type
+  Touch Action
+  User Select
+  Will Change
+SVG
+  Fill
+  Stroke
+  Stroke Width
+Accessibility
+  Screen Readers
+Official Plugins
+  Typography
+  Aspect Ratio
+  Line Clamp
 ```
diff --git a/docs/rules/migration-from-tailwind-2.md b/docs/rules/migration-from-tailwind-2.md
new file mode 100644
index 0000000..ce0bd7d
--- /dev/null
+++ b/docs/rules/migration-from-tailwind-2.md
@@ -0,0 +1,111 @@
+# Detect obsolete classnames when upgrading to Tailwind CSS v3 (migration-from-tailwind-2)
+
+This rule helps you upgrade your codebase from [Tailwind CSS](https://tailwindcss.com/) v2 to v3, you can read more about [upgrading your Tailwind CSS projects from v2 to v3](https://tailwindcss.com/docs/upgrade-guide).
+
+## Rule Details
+
+### Obsolete classnames
+
+Examples of **incorrect** code for this rule:
+
+```html
+<div
+  class="transform scale-50 filter grayscale backdrop-filter backdrop-blur-sm"
+>
+  Automatic transforms and filters
+</div>
+```
+
+Examples of **correct** code for this rule:
+
+```html
+<div class="scale-50 grayscale backdrop-blur-sm">
+  Automatic transforms and filters
+</div>
+```
+
+The classnames `backdrop-filter`, `filter` & `transform` are [not needed when you are using TailwindCSS v3](https://tailwindcss.com/docs/upgrade-guide#automatic-transforms-and-filters) because it is always running in JIT mode.
+
+The rule can fix your code by removing these obsolete classnames.
+
+### Renamed classnames
+
+Examples of **incorrect** code for this rule:
+
+```html
+<div class="overflow-clip overflow-ellipsis">overflow-clip/ellipsis</div>
+```
+
+Examples of **correct** code for this rule:
+
+```html
+<div class="text-clip text-ellipsis">overflow-clip/ellipsis</div>
+```
+
+The classnames `overflow-clip` & `overflow-ellipsis` [were renamed in v3](https://tailwindcss.com/docs/upgrade-guide#overflow-clip-ellipsis) to avoid confusion with new CSS properties. As said in the official docs:
+
+> The old class names will always work but you’re encouraged to update to the new ones.
+
+This rule can replace the old classnames by the updated classnames, it will work on the following classnames:
+
+- `overflow-clip` => `text-clip`
+- `overflow-ellipsis` => `text-ellipsis`
+- `flex-grow` => `grow`
+- `flex-shrink` => `shrink`
+- `decoration-clone` => `box-decoration-clone`
+- `decoration-slice` => `box-decoration-slice`
+- `placeholder-color` => `placeholder:text-color`
+
+### Removed `bg-opacity`
+
+Examples of **incorrect** code for this rule:
+
+```html
+<div class="bg-opacity-50 bg-black">bg-opacity</div>
+```
+
+Examples of **correct** code for this rule:
+
+```html
+<div class="bg-black/50">bg-opacity</div>
+```
+
+While still being supported, the `bg-opacity` utility classname was removed from the docs because you should use a suffix modifier on a `bg-color` to provide an alpha value instead.
+
+This rule will report the issue but **it will not fix it for you**...
+
+### Options
+
+```js
+...
+"tailwindcss/migration-from-tailwind-2": [<enabled>, {
+  "callees": Array<string>,
+  "config": <string>|<object>,
+  "tags": Array<string>,
+}]
+...
+```
+
+### `callees` (default: `["classnames", "clsx", "ctl"]`)
+
+If you use some utility library like [@netlify/classnames-template-literals](https://github.com/netlify/classnames-template-literals), you can add its name to the list to make sure it gets parsed by this rule.
+
+For best results, gather the declarative classnames together, avoid mixing conditional classnames in between, move them at the end.
+
+### `config` (default: `"tailwind.config.js"`)
+
+By default the plugin will try to load the file `tailwind.config.js` at the root of your project.
+
+This allows the plugin to use your customized `colors`, `spacing`, `screens`...
+
+You can provide another path or filename for your Tailwind CSS config file like `"config/tailwind.js"`.
+
+If the external file cannot be loaded (e.g. incorrect path or deleted file), an empty object `{}` will be used instead.
+
+It is also possible to directly inject a configuration as plain `object` like `{ prefix: "tw-", theme: { ... } }`.
+
+Finally, the plugin will [merge the provided configuration](https://tailwindcss.com/docs/configuration#referencing-in-java-script) with [Tailwind CSS's default configuration](https://github.com/tailwindlabs/tailwindcss/blob/master/stubs/defaultConfig.stub.js).
+
+### `tags` (default: `[]`)
+
+Optional, if you are using tagged templates, you should provide the tags in this array.
diff --git a/docs/rules/no-contradicting-classname.md b/docs/rules/no-contradicting-classname.md
index 169bb81..ff23aa3 100644
--- a/docs/rules/no-contradicting-classname.md
+++ b/docs/rules/no-contradicting-classname.md
@@ -25,7 +25,8 @@ Examples of **correct** code for this rule:
 ...
 "tailwindcss/classnames-order": [<enabled>, {
   "callees": Array<string>,
-  "config": <string>|<object>
+  "config": <string>|<object>,
+  "tags": Array<string>,
 }]
 ...
 ```
@@ -50,6 +51,10 @@ It is also possible to directly inject a configuration as plain `object` like `{
 
 Finally, the plugin will [merge the provided configuration](https://tailwindcss.com/docs/configuration#referencing-in-java-script) with [Tailwind CSS's default configuration](https://github.com/tailwindlabs/tailwindcss/blob/master/stubs/defaultConfig.stub.js).
 
+### `tags` (default: `[]`)
+
+Optional, if you are using tagged templates, you should provide the tags in this array.
+
 ## Further Reading
 
 This rule will not fix the issue but will let you know about the issue.
diff --git a/docs/rules/no-custom-classname.md b/docs/rules/no-custom-classname.md
index 04b5977..074e742 100644
--- a/docs/rules/no-custom-classname.md
+++ b/docs/rules/no-custom-classname.md
@@ -26,7 +26,8 @@ Examples of **correct** code for this rule:
   "callees": Array<string>,
   "config": <string>|<object>,
   "cssFiles": Array<string>,
-  "whitelist": Array<string>
+  "tags": Array<string>,
+  "whitelist": Array<string>,
 }]
 ...
 ```
@@ -57,6 +58,10 @@ By default the plugin will now look for any `css` files and ignore the `node_mod
 
 Each `css` files will be processed in order to extract the declared classnames in order to accept them.
 
+### `tags` (default: `[]`)
+
+Optional, if you are using tagged templates, you should provide the tags in this array.
+
 ### `whitelist` (default: `[]`)
 
 The `whitelist` is empty by default but you can add custom regular expressions to this array to avoid getting warnings or errors while using your custom classes.
diff --git a/lib/config/groups.js b/lib/config/groups.js
index b7fe46f..a346493 100644
--- a/lib/config/groups.js
+++ b/lib/config/groups.js
@@ -1,38 +1,71 @@
 /**
  * @fileoverview Default grouping for Tailwind CSS classnames following the order of the official docs
  * @description The hierarchy of `members` can be useful to detect redundant and/or contradicting classnames
- * @version v2.1.0
- * @see https://tailwindcss.com/docs/container
+ * @version v3.0.0
+ * @see https://tailwindcss.com/docs
  * @author François Massart
  */
 module.exports.groups = [
   {
-    type: 'CORE CONCEPTS',
+    type: 'Core Concepts',
     members: [
       {
         type: 'Hover, Focus, & Other States',
-        members: 'group',
+        members: [
+          {
+            type: 'group',
+            members: 'group',
+          },
+          {
+            type: 'peer',
+            members: 'peer',
+          },
+        ],
       },
       {
         type: 'Dark Mode',
         members: '${dark}',
       },
+      {
+        type: 'Arbitrary properties',
+        members: '${arbitraryProperties}',
+      },
     ],
   },
   {
-    type: 'LAYOUT',
+    type: 'Layout',
     members: [
+      {
+        type: 'Aspect Ratio',
+        members: 'aspect\\-(?<value>${aspectRatio})',
+      },
       {
         type: 'Container',
         members: 'container',
       },
+      {
+        type: 'Columns',
+        members: 'columns\\-(?<value>${columns})',
+      },
+      {
+        type: 'Break After',
+        members: 'break\\-after\\-(?<value>auto|avoid|all|avoid\\-page|page|left|right|column)',
+      },
+      {
+        type: 'Break Before',
+        members: 'break\\-before\\-(?<value>auto|avoid|all|avoid\\-page|page|left|right|column)',
+      },
+      {
+        type: 'Break Inside',
+        members: 'break\\-inside\\-(?<value>auto|avoid|avoid\\-page|avoid\\-column)',
+      },
       {
         type: 'Box Decoration Break',
-        members: 'decoration\\-(slice|clone)',
+        members: 'box\\-decoration\\-(?<value>clone|slice)',
       },
       {
         type: 'Box Sizing',
-        members: 'box\\-(border|content)',
+        members: 'box\\-(?<value>border|content)',
       },
       {
         type: 'Display',
@@ -41,11 +74,11 @@ module.exports.groups = [
       },
       {
         type: 'Floats',
-        members: 'float\\-(right|left|none)',
+        members: 'float\\-(?<value>right|left|none)',
       },
       {
         type: 'Clear',
-        members: 'clear\\-(left|right|both|none)',
+        members: 'clear\\-(?<value>left|right|both|none)',
       },
       {
         type: 'Isolation',
@@ -53,26 +86,26 @@ module.exports.groups = [
       },
       {
         type: 'Object Fit',
-        members: 'object\\-(contain|cover|fill|none|scale\\-down)',
+        members: 'object\\-(?<value>contain|cover|fill|none|scale\\-down)',
       },
       {
         type: 'Object Position',
-        members: 'object\\-${objectPosition}',
+        members: 'object\\-(?<value>${objectPosition})',
       },
       {
         type: 'Overflow',
         members: [
           {
             type: 'overflow',
-            members: 'overflow\\-(auto|hidden|visible|scroll)',
+            members: 'overflow\\-(?<value>auto|hidden|clip|visible|scroll)',
           },
           {
             type: 'overflow-x',
-            members: 'overflow\\-x\\-(auto|hidden|visible|scroll)',
+            members: 'overflow\\-x\\-(?<value>auto|hidden|clip|visible|scroll)',
           },
           {
             type: 'overflow-y',
-            members: 'overflow\\-y\\-(auto|hidden|visible|scroll)',
+            members: 'overflow\\-y\\-(?<value>auto|hidden|clip|visible|scroll)',
           },
         ],
       },
@@ -81,15 +114,15 @@ module.exports.groups = [
         members: [
           {
             type: 'overscroll',
-            members: 'overscroll\\-(auto|contain|none)',
+            members: 'overscroll\\-(?<value>auto|contain|none)',
           },
           {
             type: 'overscroll-x',
-            members: 'overscroll\\-x\\-(auto|contain|none)',
+            members: 'overscroll\\-x\\-(?<value>auto|contain|none)',
           },
           {
             type: 'overscroll-y',
-            members: 'overscroll\\-y\\-(auto|contain|none)',
+            members: 'overscroll\\-y\\-(?<value>auto|contain|none)',
           },
         ],
       },
@@ -102,31 +135,31 @@ module.exports.groups = [
         members: [
           {
             type: 'inset',
-            members: '(inset\\-${inset}|\\-inset\\-${-inset})',
+            members: '(inset\\-(?<value>${inset})|\\-inset\\-(?<negativeValue>${-inset}))',
           },
           {
             type: 'inset-y',
-            members: '(inset\\-y\\-${inset}|\\-inset\\-y\\-${-inset})',
+            members: '(inset\\-y\\-(?<value>${inset})|\\-inset\\-y\\-(?<negativeValue>${-inset}))',
           },
           {
             type: 'inset-x',
-            members: '(inset\\-x\\-${inset}|\\-inset\\-x\\-${-inset})',
+            members: '(inset\\-x\\-(?<value>${inset})|\\-inset\\-x\\-(?<negativeValue>${-inset}))',
           },
           {
             type: 'top',
-            members: '(top\\-${inset}|\\-top\\-${-inset})',
+            members: '(top\\-(?<value>${inset})|\\-top\\-(?<negativeValue>${-inset}))',
           },
           {
             type: 'right',
-            members: '(right\\-${inset}|\\-right\\-${-inset})',
+            members: '(right\\-(?<value>${inset})|\\-right\\-(?<negativeValue>${-inset}))',
           },
           {
             type: 'bottom',
-            members: '(bottom\\-${inset}|\\-bottom\\-${-inset})',
+            members: '(bottom\\-(?<value>${inset})|\\-bottom\\-(?<negativeValue>${-inset}))',
           },
           {
             type: 'left',
-            members: '(left\\-${inset}|\\-left\\-${-inset})',
+            members: '(left\\-(?<value>${inset})|\\-left\\-(?<negativeValue>${-inset}))',
           },
         ],
       },
@@ -136,13 +169,17 @@ module.exports.groups = [
       },
       {
         type: 'Z-Index',
-        members: '(z\\-${zIndex}|\\-z\\-${-zIndex})',
+        members: '(z\\-(?<value>${zIndex})|\\-z\\-(?<negativeValue>${-zIndex}))',
       },
     ],
   },
   {
-    type: 'FLEXBOX',
+    type: 'Flexbox & Grid',
     members: [
+      {
+        type: 'Flex Basis',
+        members: 'basis\\-(?<value>${flexBasis})',
+      },
       {
         type: 'Flex Direction',
         members: 'flex\\-(row|col)(\\-reverse)?',
@@ -153,64 +190,59 @@ module.exports.groups = [
       },
       {
         type: 'Flex',
-        members: 'flex\\-${flex}',
+        members: 'flex\\-(?<value>${flex})',
       },
       {
         type: 'Flex Grow',
-        members: 'flex\\-grow(\\-${flexGrow})?',
+        members: 'grow(\\-(?<value>${flexGrow}))?',
       },
       {
         type: 'Flex Shrink',
-        members: 'flex\\-shrink(\\-${flexShrink})?',
+        members: 'shrink(\\-(?<value>${flexShrink}))?',
       },
       {
         type: 'Order',
-        members: '(order\\-${order}|\\-order\\-${-order})',
+        members: '(order\\-(?<value>${order})|\\-order\\-(?<negativeValue>${-order}))',
       },
-    ],
-  },
-  {
-    type: 'GRID',
-    members: [
       {
         type: 'Grid Template Columns',
-        members: 'grid\\-cols\\-${gridTemplateColumns}',
+        members: 'grid\\-cols\\-(?<value>${gridTemplateColumns})',
       },
       {
         type: 'Grid Column Start / End',
         members: [
           {
             type: 'grid-column',
-            members: 'col\\-${gridColumn}',
+            members: 'col\\-(?<value>${gridColumn})',
           },
           {
             type: 'grid-column-start',
-            members: 'col\\-start\\-${gridColumnStart}',
+            members: 'col\\-start\\-(?<value>${gridColumnStart})',
           },
           {
             type: 'grid-column-end',
-            members: 'col\\-end\\-${gridColumnEnd}',
+            members: 'col\\-end\\-(?<value>${gridColumnEnd})',
           },
         ],
       },
       {
         type: 'Grid Template Rows',
-        members: 'grid\\-rows\\-${gridTemplateRows}',
+        members: 'grid\\-rows\\-(?<value>${gridTemplateRows})',
       },
       {
         type: 'Grid Row Start / End',
         members: [
           {
             type: 'grid-row',
-            members: 'row\\-${gridRow}',
+            members: 'row\\-(?<value>${gridRow})',
           },
           {
             type: 'grid-row-start',
-            members: 'row\\-start\\-${gridRowStart}',
+            members: 'row\\-start\\-(?<value>${gridRowStart})',
           },
           {
             type: 'grid-row-end',
-            members: 'row\\-end\\-${gridRowEnd}',
+            members: 'row\\-end\\-(?<value>${gridRowEnd})',
           },
         ],
       },
@@ -220,41 +252,36 @@ module.exports.groups = [
       },
       {
         type: 'Grid Auto Columns',
-        members: 'auto\\-cols\\-${gridAutoColumns}',
+        members: 'auto\\-cols\\-(?<value>${gridAutoColumns})',
       },
       {
         type: 'Grid Auto Rows',
-        members: 'auto\\-rows\\-${gridAutoRows}',
+        members: 'auto\\-rows\\-(?<value>${gridAutoRows})',
       },
       {
         type: 'Gap',
         members: [
           {
             type: 'gap',
-            members: 'gap\\-${gap}',
+            members: 'gap\\-(?<value>${gap})',
           },
           {
             type: 'column-gap',
-            members: 'gap\\-x\\-${gap}',
+            members: 'gap\\-x\\-(?<value>${gap})',
           },
           {
             type: 'row-gap',
-            members: 'gap\\-y\\-${gap}',
+            members: 'gap\\-y\\-(?<value>${gap})',
           },
         ],
       },
-    ],
-  },
-  {
-    type: 'BOX ALIGNMENT',
-    members: [
       {
         type: 'Justify Content',
         members: 'justify\\-(start|end|center|between|around|evenly)',
       },
       {
         type: 'Justify Items',
-        members: 'justify\\-items\\-(auto|start|end|center|stretch)',
+        members: 'justify\\-items\\-(start|end|center|stretch)',
       },
       {
         type: 'Justify Self',
@@ -270,7 +297,7 @@ module.exports.groups = [
       },
       {
         type: 'Align Self',
-        members: 'self\\-(auto|start|end|center|stretch)',
+        members: 'self\\-(auto|start|end|center|stretch|baseline)',
       },
       {
         type: 'Place Content',
@@ -278,7 +305,7 @@ module.exports.groups = [
       },
       {
         type: 'Place Items',
-        members: 'place\\-items\\-(auto|start|end|center|stretch)',
+        members: 'place\\-items\\-(start|end|center|stretch)',
       },
       {
         type: 'Place Self',
@@ -287,38 +314,38 @@ module.exports.groups = [
     ],
   },
   {
-    type: 'SPACING',
+    type: 'Spacing',
     members: [
       {
         type: 'Padding',
         members: [
           {
             type: 'p',
-            members: 'p\\-${padding}',
+            members: 'p\\-(?<value>${padding})',
           },
           {
             type: 'py',
-            members: 'py\\-${padding}',
+            members: 'py\\-(?<value>${padding})',
           },
           {
             type: 'px',
-            members: 'px\\-${padding}',
+            members: 'px\\-(?<value>${padding})',
           },
           {
             type: 'pt',
-            members: 'pt\\-${padding}',
+            members: 'pt\\-(?<value>${padding})',
           },
           {
             type: 'pr',
-            members: 'pr\\-${padding}',
+            members: 'pr\\-(?<value>${padding})',
           },
           {
             type: 'pb',
-            members: 'pb\\-${padding}',
+            members: 'pb\\-(?<value>${padding})',
           },
           {
             type: 'pl',
-            members: 'pl\\-${padding}',
+            members: 'pl\\-(?<value>${padding})',
           },
         ],
       },
@@ -327,31 +354,31 @@ module.exports.groups = [
         members: [
           {
             type: 'm',
-            members: '(m\\-${margin}|\\-m\\-${-margin})',
+            members: '(m\\-(?<value>${margin})|\\-m\\-(?<negativeValue>${-margin}))',
           },
           {
             type: 'my',
-            members: '(my\\-${margin}|\\-my\\-${-margin})',
+            members: '(my\\-(?<value>${margin})|\\-my\\-(?<negativeValue>${-margin}))',
           },
           {
             type: 'mx',
-            members: '(mx\\-${margin}|\\-mx\\-${-margin})',
+            members: '(mx\\-(?<value>${margin})|\\-mx\\-(?<negativeValue>${-margin}))',
           },
           {
             type: 'mt',
-            members: '(mt\\-${margin}|\\-mt\\-${-margin})',
+            members: '(mt\\-(?<value>${margin})|\\-mt\\-(?<negativeValue>${-margin}))',
           },
           {
             type: 'mr',
-            members: '(mr\\-${margin}|\\-mr\\-${-margin})',
+            members: '(mr\\-(?<value>${margin})|\\-mr\\-(?<negativeValue>${-margin}))',
           },
           {
             type: 'mb',
-            members: '(mb\\-${margin}|\\-mb\\-${-margin})',
+            members: '(mb\\-(?<value>${margin})|\\-mb\\-(?<negativeValue>${-margin}))',
           },
           {
             type: 'ml',
-            members: '(ml\\-${margin}|\\-ml\\-${-margin})',
+            members: '(ml\\-(?<value>${margin})|\\-ml\\-(?<negativeValue>${-margin}))',
           },
         ],
       },
@@ -360,11 +387,11 @@ module.exports.groups = [
         members: [
           {
             type: 'space-y',
-            members: '(space\\-y\\-${space}|\\-space\\-y\\-${-space})',
+            members: '(space\\-y\\-(?<value>${space})|\\-space\\-y\\-(?<negativeValue>${-space}))',
           },
           {
             type: 'space-x',
-            members: '(space\\-x\\-${space}|\\-space\\-x\\-${-space})',
+            members: '(space\\-x\\-(?<value>${space})|\\-space\\-x\\-(?<negativeValue>${-space}))',
           },
           {
             type: 'space-y-reverse',
@@ -379,44 +406,44 @@ module.exports.groups = [
     ],
   },
   {
-    type: 'SIZING',
+    type: 'Sizing',
     members: [
       {
         type: 'Width',
-        members: 'w\\-${width}',
+        members: 'w\\-(?<value>${width})',
       },
       {
         type: 'Min-Width',
-        members: 'min\\-w\\-${minWidth}',
+        members: 'min\\-w\\-(?<value>${minWidth})',
       },
       {
         type: 'Max-Width',
-        members: 'max\\-w\\-${maxWidth}',
+        members: 'max\\-w\\-(?<value>${maxWidth})',
       },
       {
         type: 'Height',
-        members: 'h\\-${height}',
+        members: 'h\\-(?<value>${height})',
       },
       {
         type: 'Min-Height',
-        members: 'min\\-h\\-${minHeight}',
+        members: 'min\\-h\\-(?<value>${minHeight})',
       },
       {
         type: 'Max-Height',
-        members: 'max\\-h\\-${maxHeight}',
+        members: 'max\\-h\\-(?<value>${maxHeight})',
       },
     ],
   },
   {
-    type: 'TYPOGRAPHY',
+    type: 'Typography',
     members: [
       {
         type: 'Font Family',
-        members: 'font\\-${fontFamily}',
+        members: 'font\\-(?<value>${fontFamily})',
       },
       {
         type: 'Font Size',
-        members: 'text\\-${fontSize}',
+        members: 'text\\-(?<value>${fontSize})',
       },
       {
         type: 'Font Smoothing',
@@ -428,7 +455,7 @@ module.exports.groups = [
       },
       {
         type: 'Font Weight',
-        members: 'font\\-${fontWeight}',
+        members: 'font\\-(?<value>${fontWeight})',
       },
       {
         type: 'Font Variant Numeric',
@@ -437,43 +464,47 @@ module.exports.groups = [
       },
       {
         type: 'Letter Spacing',
-        members: 'tracking\\-${letterSpacing}',
+        members: '(tracking\\-(?<value>${letterSpacing})|\\-tracking\\-(?<negativeValue>${-letterSpacing}))',
       },
       {
         type: 'Line Height',
-        members: 'leading\\-${lineHeight}',
+        members: 'leading\\-(?<value>${lineHeight})',
       },
       {
         type: 'List Style Type',
-        members: 'list\\-${listStyleType}',
+        members: 'list\\-(?<value>${listStyleType})',
       },
       {
         type: 'List Style Position',
         members: 'list\\-(in|out)side',
       },
       {
-        type: 'Placeholder Color',
-        members: 'placeholder\\-${placeholderColor}',
+        type: 'Text Alignment',
+        members: 'text\\-(left|center|right|justify)',
       },
       {
-        type: 'Placeholder Opacity',
-        members: 'placeholder\\-opacity\\-${placeholderOpacity}',
+        type: 'Text Color',
+        members: 'text\\-(?<value>${textColor})',
       },
       {
-        type: 'Text Alignment',
-        members: 'text\\-(left|center|right|justify)',
+        type: 'Text Decoration',
+        members: '(no\\-)?underline|overline|line\\-through',
       },
       {
-        type: 'Text Color',
-        members: 'text\\-${textColor}',
+        type: 'Text Decoration Color',
+        members: 'decoration\\-(?<value>${textDecorationColor})',
       },
       {
-        type: 'Text Opacity',
-        members: 'text\\-opacity\\-${textOpacity}',
+        type: 'Text Decoration Style',
+        members: 'decoration\\-(solid|double|dotted|dashed|wavy)',
       },
       {
-        type: 'Text Decoration',
-        members: '(no\\-)?underline|line\\-through',
+        type: 'Text Decoration Thickness',
+        members: 'decoration\\-(?<value>${textDecorationThickness})',
+      },
+      {
+        type: 'Text Underline Offset',
+        members: 'underline\\-offset\\-(?<value>${textUnderlineOffset})',
       },
       {
         type: 'Text Transform',
@@ -481,11 +512,15 @@ module.exports.groups = [
       },
       {
         type: 'Text Overflow',
-        members: 'truncate|overflow\\-(ellipsis|clip)',
+        members: 'truncate|text\\-(ellipsis|clip)',
+      },
+      {
+        type: 'Text Indent',
+        members: '(indent\\-(?<value>${textIndent})|\\-indent\\-(?<negativeValue>${-textIndent}))',
       },
       {
         type: 'Vertical Alignment',
-        members: 'align\\-(baseline|top|middle|bottom|text\\-(top|bottom))',
+        members: 'align\\-(baseline|top|middle|bottom|text\\-(top|bottom)|sub|super)',
       },
       {
         type: 'Whitespace',
@@ -495,10 +530,14 @@ module.exports.groups = [
         type: 'Word Break',
         members: 'break\\-(normal|words|all)',
       },
+      {
+        type: 'Content',
+        members: 'content\\-(?<value>${content})',
+      },
     ],
   },
   {
-    type: 'BACKGROUNDS',
+    type: 'Backgrounds',
     members: [
       {
         type: 'Background Attachment',
@@ -510,15 +549,15 @@ module.exports.groups = [
       },
       {
         type: 'Background Color',
-        members: 'bg\\-${backgroundColor}',
+        members: 'bg\\-(?<value>${backgroundColor})',
       },
       {
-        type: 'Background Opacity',
-        members: 'bg\\-opacity\\-${backgroundOpacity}',
+        type: 'Background Origin',
+        members: 'bg\\-origin\\-(border|padding|content)',
       },
       {
         type: 'Background Position',
-        members: 'bg\\-${backgroundPosition}',
+        members: 'bg\\-(?<value>${backgroundPosition})',
       },
       {
         type: 'Background Repeat',
@@ -526,72 +565,72 @@ module.exports.groups = [
       },
       {
         type: 'Background Size',
-        members: 'bg\\-${backgroundSize}',
+        members: 'bg\\-(?<value>${backgroundSize})',
       },
       {
         type: 'Background Image',
-        members: 'bg\\-${backgroundImage}',
+        members: 'bg\\-(?<value>${backgroundImage})',
       },
       {
         type: 'Gradient Color Stops',
         members: [
           {
             type: 'from',
-            members: 'from\\-${gradientColorStops}',
+            members: 'from\\-(?<value>${gradientColorStops})',
           },
           {
             type: 'via',
-            members: 'via\\-${gradientColorStops}',
+            members: 'via\\-(?<value>${gradientColorStops})',
           },
           {
             type: 'to',
-            members: 'to\\-${gradientColorStops}',
+            members: 'to\\-(?<value>${gradientColorStops})',
           },
         ],
       },
     ],
   },
   {
-    type: 'BORDERS',
+    type: 'Borders',
     members: [
       {
         type: 'Border Radius',
         members: [
           {
             type: 'border-radius',
-            members: 'rounded(\\-${borderRadius})?',
+            members: 'rounded(\\-(?<value>${borderRadius}))?',
           },
           {
             type: 'border-radius-top',
-            members: 'rounded\\-t(\\-${borderRadius})?',
+            members: 'rounded\\-t(\\-(?<value>${borderRadius}))?',
           },
           {
             type: 'border-radius-right',
-            members: 'rounded\\-r(\\-${borderRadius})?',
+            members: 'rounded\\-r(\\-(?<value>${borderRadius}))?',
           },
           {
             type: 'border-radius-bottom',
-            members: 'rounded\\-b(\\-${borderRadius})?',
+            members: 'rounded\\-b(\\-(?<value>${borderRadius}))?',
           },
           {
             type: 'border-radius-left',
-            members: 'rounded\\-l(\\-${borderRadius})?',
+            members: 'rounded\\-l(\\-(?<value>${borderRadius}))?',
           },
           {
             type: 'border-radius-top-left',
-            members: 'rounded\\-tl(\\-${borderRadius})?',
+            members: 'rounded\\-tl(\\-(?<value>${borderRadius}))?',
           },
           {
             type: 'border-radius-top-right',
-            members: 'rounded\\-tr(\\-${borderRadius})?',
+            members: 'rounded\\-tr(\\-(?<value>${borderRadius}))?',
           },
           {
             type: 'border-radius-bottom-right',
-            members: 'rounded\\-br(\\-${borderRadius})?',
+            members: 'rounded\\-br(\\-(?<value>${borderRadius}))?',
           },
           {
             type: 'border-radius-bottom-left',
-            members: 'rounded\\-bl(\\-${borderRadius})?',
+            members: 'rounded\\-bl(\\-(?<value>${borderRadius}))?',
           },
         ],
       },
@@ -600,23 +639,31 @@ module.exports.groups = [
         members: [
           {
             type: 'border-width',
-            members: 'border(\\-${borderWidth})?',
+            members: 'border(\\-(?<value>${borderWidth}))?',
+          },
+          {
+            type: 'border-y-width',
+            members: 'border\\-y(\\-(?<value>${borderWidth}))?',
+          },
+          {
+            type: 'border-x-width',
+            members: 'border\\-x(\\-(?<value>${borderWidth}))?',
           },
           {
             type: 'border-top-width',
-            members: 'border\\-t(\\-${borderWidth})?',
+            members: 'border\\-t(\\-(?<value>${borderWidth}))?',
           },
           {
             type: 'border-right-width',
-            members: 'border\\-r(\\-${borderWidth})?',
+            members: 'border\\-r(\\-(?<value>${borderWidth}))?',
           },
           {
             type: 'border-bottom-width',
-            members: 'border\\-b(\\-${borderWidth})?',
+            members: 'border\\-b(\\-(?<value>${borderWidth}))?',
           },
           {
             type: 'border-left-width',
-            members: 'border\\-l(\\-${borderWidth})?',
+            members: 'border\\-l(\\-(?<value>${borderWidth}))?',
           },
         ],
       },
@@ -625,48 +672,48 @@ module.exports.groups = [
         members: [
           {
             type: 'border-color',
-            members: 'border\\-${borderColor}',
+            members: 'border\\-(?<value>${borderColor})',
+          },
+          {
+            type: 'border-y-color',
+            members: 'border\\-y\\-(?<value>${borderColor})',
+          },
+          {
+            type: 'border-x-color',
+            members: 'border\\-x\\-(?<value>${borderColor})',
           },
           {
             type: 'border-top-color',
-            mode: 'jit',
-            members: 'border\\-t\\-${borderColor}',
+            members: 'border\\-t\\-(?<value>${borderColor})',
           },
           {
             type: 'border-right-color',
-            mode: 'jit',
-            members: 'border\\-r\\-${borderColor}',
+            members: 'border\\-r\\-(?<value>${borderColor})',
           },
           {
             type: 'border-bottom-color',
-            mode: 'jit',
-            members: 'border\\-b\\-${borderColor}',
+            members: 'border\\-b\\-(?<value>${borderColor})',
           },
           {
             type: 'border-left-color',
-            mode: 'jit',
-            members: 'border\\-l\\-${borderColor}',
+            members: 'border\\-l\\-(?<value>${borderColor})',
           },
         ],
       },
-      {
-        type: 'Border Opacity',
-        members: 'border\\-opacity\\-${borderOpacity}',
-      },
       {
         type: 'Border Style',
-        members: 'border\\-(solid|dashed|dotted|double|none)',
+        members: 'border\\-(solid|dashed|dotted|double|hidden|none)',
       },
       {
         type: 'Divide Width',
         members: [
           {
             type: 'divide-y',
-            members: 'divide\\-y(\\-${divideWidth})?',
+            members: 'divide\\-y(\\-(?<value>${divideWidth}))?',
           },
           {
             type: 'divide-x',
-            members: 'divide\\-x(\\-${divideWidth})?',
+            members: 'divide\\-x(\\-(?<value>${divideWidth}))?',
           },
           {
             type: 'divide-y-reverse',
@@ -680,23 +727,40 @@ module.exports.groups = [
       },
       {
         type: 'Divide Color',
-        members: 'divide\\-${divideColor}',
-      },
-      {
-        type: 'Divide Opacity',
-        members: 'divide\\-opacity\\-${divideOpacity}',
+        members: 'divide\\-(?<value>${divideColor})',
       },
       {
         type: 'Divide Style',
         members: 'divide\\-(solid|dashed|dotted|double|none)',
       },
+      {
+        type: 'Outline Width',
+        members: 'outline\\-(?<value>${outlineWidth})',
+      },
+      {
+        type: 'Outline Color',
+        members: 'outline\\-(?<value>${outlineColor})',
+      },
+      {
+        type: 'Outline Style',
+        members: 'outline(\\-(none|dashed|dotted|double|hidden))?',
+      },
+      {
+        type: 'Outline Offset',
+        members: 'outline\\-offset\\-(?<value>${outlineOffset})',
+      },
       {
         type: 'Ring Width',
         members: [
           {
             type: 'ring',
-            members: 'ring(\\-${ringWidth})?',
+            members: 'ring(\\-(?<value>${ringWidth}))?',
           },
+        ],
+      },
+      {
+        type: 'Ring Inset',
+        members: [
           {
             type: 'ring-inset',
             members: 'ring\\-inset',
@@ -705,32 +769,32 @@ module.exports.groups = [
       },
       {
         type: 'Ring Color',
-        members: 'ring\\-${ringColor}',
-      },
-      {
-        type: 'Ring Opacity',
-        members: 'ring\\-opacity\\-${ringOpacity}',
+        members: 'ring\\-(?<value>${ringColor})',
       },
       {
         type: 'Ring Offset Width',
-        members: 'ring\\-offset\\-${ringOffsetWidth}',
+        members: 'ring\\-offset\\-(?<value>${ringOffsetWidth})',
       },
       {
         type: 'Ring Offset Color',
-        members: 'ring\\-offset\\-${ringOffsetColor}',
+        members: 'ring\\-offset\\-(?<value>${ringOffsetColor})',
       },
     ],
   },
   {
-    type: 'EFFECTS',
+    type: 'Effects',
     members: [
       {
         type: 'Box Shadow',
-        members: 'shadow(\\-${boxShadow})?',
+        members: 'shadow(\\-(?<value>${boxShadow}))?',
+      },
+      {
+        type: 'Box Shadow Color',
+        members: 'shadow(\\-(?<value>${boxShadowColor}))?',
       },
       {
         type: 'Opacity',
-        members: 'opacity\\-${opacity}',
+        members: 'opacity\\-(?<value>${opacity})',
       },
       {
         type: 'Mix Blend Mode',
@@ -745,92 +809,85 @@ module.exports.groups = [
     ],
   },
   {
-    type: 'FILTERS',
+    type: 'Filters',
     members: [
-      {
-        type: 'Filter',
-        members: 'filter(\\-none)?',
-      },
       {
         type: 'Blur',
-        members: 'blur(\\-${blur})?',
+        members: 'blur(\\-(?<value>${blur}))?',
       },
       {
         type: 'Brightness',
-        members: 'brightness\\-${brightness}',
+        members: 'brightness\\-(?<value>${brightness})',
       },
       {
         type: 'Contrast',
-        members: 'contrast\\-${contrast}',
+        members: 'contrast\\-(?<value>${contrast})',
       },
       {
         type: 'Drop Shadow',
-        members: 'drop\\-shadow(\\-${dropShadow})?',
+        members: 'drop\\-shadow(\\-(?<value>${dropShadow}))?',
       },
       {
         type: 'Grayscale',
-        members: 'grayscale(\\-${grayscale})?',
+        members: 'grayscale(\\-(?<value>${grayscale}))?',
       },
       {
         type: 'Hue Rotate',
-        members: '(\\-)?hue\\-rotate\\-${hueRotate}',
+        members: 'hue\\-rotate\\-(?<value>${hueRotate})|\\-hue\\-rotate\\-(?<negativeValue>${-hueRotate})',
       },
       {
         type: 'Invert',
-        members: 'invert(\\-${invert})?',
+        members: 'invert(\\-(?<value>${invert}))?',
       },
       {
         type: 'Saturate',
-        members: 'saturate\\-${saturate}',
+        members: 'saturate\\-(?<value>${saturate})',
       },
       {
         type: 'Sepia',
-        members: 'sepia(\\-${sepia})?',
-      },
-      {
-        type: 'Backdrop Filter',
-        members: 'backdrop\\-filter(\\-none)?',
+        members: 'sepia(\\-(?<value>${sepia}))?',
       },
       {
         type: 'Backdrop Blur',
-        members: 'backdrop\\-blur(\\-${backdropBlur})?',
+        members: 'backdrop\\-blur(\\-(?<value>${backdropBlur}))?',
       },
       {
         type: 'Backdrop Brightness',
-        members: 'backdrop\\-brightness\\-${backdropBrightness}',
+        members: 'backdrop\\-brightness\\-(?<value>${backdropBrightness})',
       },
       {
         type: 'Backdrop Contrast',
-        members: 'backdrop\\-contrast\\-${backdropContrast}',
+        members: 'backdrop\\-contrast\\-(?<value>${backdropContrast})',
       },
       {
         type: 'Backdrop Grayscale',
-        members: 'backdrop\\-grayscale(\\-${backdropGrayscale})?',
+        members: 'backdrop\\-grayscale(\\-(?<value>${backdropGrayscale}))?',
       },
       {
         type: 'Backdrop Hue Rotate',
-        members: '(\\-)?backdrop\\-hue\\-rotate\\-${backdropHueRotate}',
+        members:
+          'backdrop\\-hue\\-rotate\\-(?<value>${backdropHueRotate})|\\-backdrop\\-hue\\-rotate\\-(?<negativeValue>${-backdropHueRotate})',
       },
       {
         type: 'Backdrop Invert',
-        members: 'backdrop\\-invert(\\-${backdropInvert})?',
+        members: 'backdrop\\-invert(\\-(?<value>${backdropInvert}))?',
       },
       {
         type: 'Backdrop Opacity',
-        members: 'backdrop\\-opacity\\-${backdropOpacity}',
+        members: 'backdrop\\-opacity\\-(?<value>${backdropOpacity})',
       },
       {
         type: 'Backdrop Saturate',
-        members: 'backdrop\\-saturate\\-${backdropSaturate}',
+        members: 'backdrop\\-saturate\\-(?<value>${backdropSaturate})',
       },
       {
         type: 'Backdrop Sepia',
-        members: 'backdrop\\-sepia(\\-${backdropSepia})?',
+        members: 'backdrop\\-sepia(\\-(?<value>${backdropSepia}))?',
       },
     ],
   },
   {
-    type: 'TABLES',
+    type: 'Tables',
     members: [
       {
         type: 'Border Collapse',
@@ -843,72 +900,73 @@ module.exports.groups = [
     ],
   },
   {
-    type: 'TRANSITIONS AND ANIMATION',
+    type: 'Transitions & Animation',
     members: [
       {
         type: 'Transition Property',
-        members: 'transition(\\-${transitionProperty})?',
+        members: 'transition(\\-(?<value>${transitionProperty}))?',
       },
       {
         type: 'Transition Duration',
-        members: 'duration(\\-${transitionDuration})?',
+        members: 'duration(\\-(?<value>${transitionDuration}))?',
       },
       {
         type: 'Transition Timing Function',
-        members: 'ease(\\-${transitionTimingFunction})?',
+        members: 'ease(\\-(?<value>${transitionTimingFunction}))?',
       },
       {
         type: 'Transition Delay',
-        members: 'delay\\-${transitionDelay}',
+        members: 'delay\\-(?<value>${transitionDelay})',
       },
       {
         type: 'Animation',
-        members: 'animate\\-${animation}',
+        members: 'animate\\-(?<value>${animation})',
       },
     ],
   },
   {
-    type: 'TRANSFORMS',
+    type: 'Transforms',
     members: [
       {
-        type: 'Transform',
-        members: 'transform(\\-(gpu|none))?',
-      },
-      {
-        type: 'Transform Origin',
-        members: 'origin\\-${transformOrigin}',
+        type: 'Transform GPU',
+        members: [
+          {
+            type: 'transform-gpu',
+            members: 'transform\\-gpu',
+          },
+        ],
       },
       {
         type: 'Scale',
         members: [
           {
             type: 'scale',
-            members: 'scale\\-${scale}',
+            members: 'scale\\-(?<value>${scale})',
           },
           {
             type: 'scale-y',
-            members: 'scale\\-y\\-${scale}',
+            members: 'scale\\-y\\-(?<value>${scale})',
           },
           {
             type: 'scale-x',
-            members: 'scale\\-x\\-${scale}',
+            members: 'scale\\-x\\-(?<value>${scale})',
           },
         ],
       },
       {
         type: 'Rotate',
-        members: '(rotate\\-${rotate}|\\-rotate\\-${-rotate})',
+        members: '(rotate\\-(?<value>${rotate})|\\-rotate\\-(?<negativeValue>${-rotate}))',
       },
       {
         type: 'Translate',
         members: [
           {
             type: 'translate-x',
-            members: '(translate\\-x\\-${translate}|\\-translate\\-x\\-${-translate})',
+            members: '(translate\\-x\\-(?<value>${translate})|\\-translate\\-x\\-(?<negativeValue>${-translate}))',
           },
           {
             type: 'translate-y',
-            members: '(translate\\-y\\-${translate}|\\-translate\\-y\\-${-translate})',
+            members: '(translate\\-y\\-(?<value>${translate})|\\-translate\\-y\\-(?<negativeValue>${-translate}))',
           },
         ],
       },
@@ -917,30 +975,38 @@ module.exports.groups = [
         members: [
           {
             type: 'skew-x',
-            members: '(skew\\-x\\-${skew}|\\-skew\\-x\\-${-skew})',
+            members: '(skew\\-x\\-(?<value>${skew})|\\-skew\\-x\\-(?<negativeValue>${-skew}))',
           },
           {
             type: 'skew-y',
-            members: '(skew\\-y\\-${skew}|\\-skew\\-y\\-${-skew})',
+            members: '(skew\\-y\\-(?<value>${skew})|\\-skew\\-y\\-(?<negativeValue>${-skew}))',
           },
         ],
       },
+      {
+        type: 'Transform Origin',
+        members: 'origin\\-(?<value>${transformOrigin})',
+      },
     ],
   },
   {
-    type: 'INTERACTIVITY',
+    type: 'Interactivity',
     members: [
+      {
+        type: 'Accent Color',
+        members: 'accent\\-(?<value>${accentColor})',
+      },
       {
         type: 'Appearance',
         members: 'appearance\\-none',
       },
       {
         type: 'Cursor',
-        members: 'cursor\\-${cursor}',
+        members: 'cursor\\-(?<value>${cursor})',
       },
       {
-        type: 'Outline',
-        members: 'outline\\-${outline}',
+        type: 'Caret Color',
+        members: 'caret\\-(?<value>${caretColor})',
       },
       {
         type: 'Pointer Events',
@@ -950,10 +1016,102 @@ module.exports.groups = [
         type: 'Resize',
         members: 'resize(\\-(none|x|y))?',
       },
+      {
+        type: 'Scroll Behavior',
+        members: 'scroll\\-(auto|smooth)',
+      },
+      {
+        type: 'Scroll Margin',
+        members: 'scroll\\-(?<value>${scrollMargin})',
+        members: [
+          {
+            type: 'scroll-m',
+            members: 'scroll-m\\-(?<value>${scrollMargin})|\\-scroll-m\\-(?<negativeValue>${-scrollMargin})',
+          },
+          {
+            type: 'scroll-my',
+            members: 'scroll-my\\-(?<value>${scrollMargin})|\\-scroll-my\\-(?<negativeValue>${-scrollMargin})',
+          },
+          {
+            type: 'scroll-mx',
+            members: 'scroll-mx\\-(?<value>${scrollMargin})|\\-scroll-mx\\-(?<negativeValue>${-scrollMargin})',
+          },
+          {
+            type: 'scroll-mt',
+            members: 'scroll-mt\\-(?<value>${scrollMargin})|\\-scroll-mt\\-(?<negativeValue>${-scrollMargin})',
+          },
+          {
+            type: 'scroll-mr',
+            members: 'scroll-mr\\-(?<value>${scrollMargin})|\\-scroll-mr\\-(?<negativeValue>${-scrollMargin})',
+          },
+          {
+            type: 'scroll-mb',
+            members: 'scroll-mb\\-(?<value>${scrollMargin})|\\-scroll-mb\\-(?<negativeValue>${-scrollMargin})',
+          },
+          {
+            type: 'scroll-ml',
+            members: 'scroll-ml\\-(?<value>${scrollMargin})|\\-scroll-ml\\-(?<negativeValue>${-scrollMargin})',
+          },
+        ],
+      },
+      {
+        type: 'Scroll Padding',
+        members: 'scroll\\-(?<value>${scrollPadding})',
+        members: [
+          {
+            type: 'scroll-p',
+            members: 'scroll-p\\-(?<value>${scrollPadding})',
+          },
+          {
+            type: 'scroll-py',
+            members: 'scroll-py\\-(?<value>${scrollPadding})',
+          },
+          {
+            type: 'scroll-px',
+            members: 'scroll-px\\-(?<value>${scrollPadding})',
+          },
+          {
+            type: 'scroll-pt',
+            members: 'scroll-pt\\-(?<value>${scrollPadding})',
+          },
+          {
+            type: 'scroll-pr',
+            members: 'scroll-pr\\-(?<value>${scrollPadding})',
+          },
+          {
+            type: 'scroll-pb',
+            members: 'scroll-pb\\-(?<value>${scrollPadding})',
+          },
+          {
+            type: 'scroll-pl',
+            members: 'scroll-pl\\-(?<value>${scrollPadding})',
+          },
+        ],
+      },
+      {
+        type: 'Scroll Snap Align',
+        members: 'snap\\-(start|end|center|align-none)',
+      },
+      {
+        type: 'Scroll Snap Stop',
+        members: 'snap\\-(normal|always)',
+      },
+      {
+        type: 'Scroll Snap Type',
+        members: 'snap\\-(none|x|y|both|mandatory|proximity)',
+      },
+      {
+        type: 'Touch Action',
+        members: 'touch\\-(auto|none|pan\\-(x|left|right|y|up|down)|pinch\\-zoom|manipulation)',
+      },
       {
         type: 'User Select',
         members: 'select\\-(none|text|all|auto)',
       },
+      {
+        type: 'Will Change',
+        members: 'will\\-change\\-(?<value>${willChange})',
+      },
     ],
   },
   {
@@ -961,20 +1119,20 @@ module.exports.groups = [
     members: [
       {
         type: 'Fill',
-        members: 'fill\\-${fill}',
+        members: 'fill\\-(?<value>${fill})',
       },
       {
         type: 'Stroke',
-        members: 'stroke\\-${stroke}',
+        members: 'stroke\\-(?<value>${stroke})',
       },
       {
         type: 'Stroke Width',
-        members: 'stroke\\-${strokeWidth}',
+        members: 'stroke\\-(?<value>${strokeWidth})',
       },
     ],
   },
   {
-    type: 'ACCESSIBILITY',
+    type: 'Accessibility',
     members: [
       {
         type: 'Screen Readers',
@@ -983,7 +1141,7 @@ module.exports.groups = [
     ],
   },
   {
-    type: 'OFFICIAL PLUGINS',
+    type: 'Official Plugins',
     members: [
       {
         type: 'Typography',
@@ -994,7 +1152,7 @@ module.exports.groups = [
           },
           {
             type: 'prose-modifier',
-            members: 'prose(\\-${typography})?',
+            members: 'prose(\\-(?<value>${typography}))?',
           },
         ],
       },
@@ -1004,17 +1162,17 @@ module.exports.groups = [
         members: [
           {
             type: 'aspect-w',
-            members: 'aspect\\-(none|w\\-${aspectRatio})',
+            members: 'aspect\\-(none|w\\-(?<value>${aspectRatio}))',
           },
           {
             type: 'aspect-h',
-            members: 'aspect\\-h\\-${aspectRatio}',
+            members: 'aspect\\-h\\-(?<value>${aspectRatio})',
           },
         ],
       },
       {
         type: 'Line Clamp',
-        members: 'line\\-clamp\\-(none|${lineClamp})',
+        members: 'line\\-clamp\\-(none|(?<value>${lineClamp}))',
       },
     ],
   },
diff --git a/lib/index.js b/lib/index.js
index 03400c5..2c68739 100644
--- a/lib/index.js
+++ b/lib/index.js
@@ -13,6 +13,7 @@ var base = __dirname + '/rules/';
 module.exports = {
   rules: {
     'classnames-order': require(base + 'classnames-order'),
+    'migration-from-tailwind-2': require(base + 'migration-from-tailwind-2'),
     'no-contradicting-classname': require(base + 'no-contradicting-classname'),
     'no-custom-classname': require(base + 'no-custom-classname'),
   },
@@ -26,6 +27,7 @@ module.exports = {
       },
       rules: {
         'tailwindcss/classnames-order': 'warn',
+        'tailwindcss/migration-from-tailwind-2': 'warn',
         'tailwindcss/no-custom-classname': 'warn',
         'tailwindcss/no-contradicting-classname': 'error',
       },
diff --git a/lib/rules/classnames-order.js b/lib/rules/classnames-order.js
index af355a0..57a072b 100644
--- a/lib/rules/classnames-order.js
+++ b/lib/rules/classnames-order.js
@@ -46,6 +46,10 @@ module.exports = {
             default: 'tailwind.config.js',
             type: ['string', 'object'],
           },
+          groupByResponsive: {
+            default: true,
+            type: 'boolean',
+          },
           groups: {
             type: 'array',
             items: { type: 'object' },
diff --git a/lib/rules/migration-from-tailwind-2.js b/lib/rules/migration-from-tailwind-2.js
new file mode 100644
index 0000000..bd2ecd8
--- /dev/null
+++ b/lib/rules/migration-from-tailwind-2.js
@@ -0,0 +1,268 @@
+/**
+ * @fileoverview Detect obsolete classnames when upgrading to Tailwind CSS v3
+ * @author François Massart
+ */
+'use strict';
+
+const docsUrl = require('../util/docsUrl');
+const customConfig = require('../util/customConfig');
+const astUtil = require('../util/ast');
+const attrUtil = require('../util/attr');
+const groupUtil = require('../util/groupMethods');
+const getOption = require('../util/settings');
+const parserUtil = require('../util/parser');
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+// Predefine message for use in context.report conditional.
+// messageId will still be usable in tests.
+const CLASSNAME_NOT_NEEDED_MSG = `Classname '{{classnames}}' is not needed in Tailwind CSS v3!`;
+const CLASSNAMES_NOT_NEEDED_MSG = `Classnames '{{classnames}}' are not needed in Tailwind CSS v3!`;
+const CLASSNAME_CHANGED_MSG = `Classname '{{deprecated}}' should be updated to '{{updated}}' in Tailwind CSS v3!`;
+const BG_OPACITY_DEPRECATED_MSG = `Classname '{{classname}}' should be replaced by an opacity suffix (eg. '/{{value}}')`;
+
+module.exports = {
+  meta: {
+    docs: {
+      description: 'Detect obsolete classnames when upgrading to Tailwind CSS v3',
+      category: 'Possible Errors',
+      recommended: true,
+      url: docsUrl('migration-from-tailwind-2'),
+    },
+    messages: {
+      classnameNotNeeded: CLASSNAME_NOT_NEEDED_MSG,
+      classnamesNotNeeded: CLASSNAMES_NOT_NEEDED_MSG,
+      classnameChanged: CLASSNAME_CHANGED_MSG,
+      bgOpacityDeprecated: BG_OPACITY_DEPRECATED_MSG,
+    },
+    fixable: 'code',
+    schema: [
+      {
+        type: 'object',
+        properties: {
+          callees: {
+            type: 'array',
+            items: { type: 'string', minLength: 0 },
+            uniqueItems: true,
+          },
+          config: {
+            default: 'tailwind.config.js',
+            type: ['string', 'object'],
+          },
+          tags: {
+            type: 'array',
+            items: { type: 'string', minLength: 0 },
+            uniqueItems: true,
+          },
+        },
+      },
+    ],
+  },
+
+  create: function (context) {
+    const callees = getOption(context, 'callees');
+    const tags = getOption(context, 'tags');
+    const twConfig = getOption(context, 'config');
+
+    const mergedConfig = customConfig.resolve(twConfig);
+
+    //----------------------------------------------------------------------
+    // Helpers
+    //----------------------------------------------------------------------
+
+    /**
+     * Recursive function crawling into child nodes
+     * @param {ASTNode} node The root node of the current parsing
+     * @param {ASTNode} arg The child node of node
+     * @returns {void}
+     */
+    const parseForObsoleteClassNames = (node, arg = null) => {
+      let originalClassNamesValue = null;
+      let start = null;
+      let end = null;
+      let prefix = '';
+      let suffix = '';
+      let trim = false;
+      if (arg === null) {
+        originalClassNamesValue = astUtil.extractValueFromNode(node);
+        const range = astUtil.extractRangeFromNode(node);
+        start = range[0] + 1;
+        end = range[1] - 1;
+      } else {
+        switch (arg.type) {
+          case 'TemplateLiteral':
+            arg.expressions.forEach((exp) => {
+              parseForObsoleteClassNames(node, exp);
+            });
+            arg.quasis.forEach((quasis) => {
+              parseForObsoleteClassNames(node, quasis);
+            });
+            return;
+          case 'ConditionalExpression':
+            parseForObsoleteClassNames(node, arg.consequent);
+            parseForObsoleteClassNames(node, arg.alternate);
+            return;
+          case 'LogicalExpression':
+            parseForObsoleteClassNames(node, arg.right);
+            return;
+          case 'Literal':
+            trim = true;
+            originalClassNamesValue = arg.value;
+            start = arg.range[0] + 1;
+            end = arg.range[1] - 1;
+            break;
+          case 'TemplateElement':
+            originalClassNamesValue = arg.value.raw;
+            start = arg.range[0];
+            end = arg.range[1];
+            // https://github.com/eslint/eslint/issues/13360
+            // The problem is that range computation includes the backticks (`test`)
+            // but value.raw does not include them, so there is a mismatch.
+            // start/end does not include the backticks, therefore it matches value.raw.
+            const txt = context.getSourceCode().getText(arg);
+            prefix = astUtil.getTemplateElementPrefix(txt, originalClassNamesValue);
+            suffix = astUtil.getTemplateElementSuffix(txt, originalClassNamesValue);
+            break;
+        }
+      }
+
+      let classNames = attrUtil.getClassNamesFromAttribute(originalClassNamesValue, trim);
+      const isSingleLine = attrUtil.isSingleLine(originalClassNamesValue);
+      let before = null;
+      let after = null;
+
+      if (!isSingleLine) {
+        const spacesOnly = /^(\s)*$/;
+        if (spacesOnly.test(classNames[0])) {
+          before = classNames.shift();
+        }
+        if (spacesOnly.test(classNames[classNames.length - 1])) {
+          after = classNames.pop();
+        }
+      }
+
+      const notNeeded = [];
+      const outdated = [];
+      const deprecatedBgOpacity = [];
+      const filtered = classNames.filter((cls) => {
+        const suffix = groupUtil.getSuffix(cls, mergedConfig.separator);
+        if (/^(backdrop\-)?filter|filter|transform$/i.test(suffix)) {
+          notNeeded.push(cls);
+          return false;
+        }
+        let overflowRes = /^overflow\-(?<value>clip|ellipsis)$/i.exec(suffix);
+        if (overflowRes && overflowRes.groups && overflowRes.groups.value) {
+          outdated.push([cls, cls.replace(/overflow\-(clip|ellipsis)$/i, `text-${overflowRes.groups.value}`)]);
+        }
+        let growShrinkRes = /flex\-(?<prop>grow|shrink)(\-(?<value>${flexVal}))?/i.exec(suffix);
+        if (growShrinkRes && growShrinkRes.groups && growShrinkRes.groups.prop) {
+          const prop = growShrinkRes.groups.prop;
+          const flexVal = growShrinkRes.groups.flexVal;
+          const optionalVal = flexVal ? `\-${flexVal}` : '';
+          const fixRegex = new RegExp(`flex\-${prop}${optionalVal}`);
+          outdated.push([cls, cls.replace(fixRegex, `${prop}${flexVal ? '-' + flexVal : ''}`)]);
+        }
+        let boxRes = /^decoration\-(?<value>clone|slice)$/i.exec(suffix);
+        if (boxRes && boxRes.groups && boxRes.groups.value) {
+          const boxVal = boxRes.groups.value;
+          const fixRegex = new RegExp(`decoration\-${boxVal}`);
+          outdated.push([cls, cls.replace(fixRegex, `box-decoration\-${boxVal}`)]);
+        }
+        let bgOpacityRes = /^bg\-opacity\-(?<value>\d{1,})$/i.exec(suffix);
+        if (bgOpacityRes && bgOpacityRes.groups && bgOpacityRes.groups.value) {
+          const opacityVal = bgOpacityRes.groups.value;
+          deprecatedBgOpacity.push([cls, opacityVal]);
+        }
+        let placeholderRes = /^placeholder\-(?<value>.{1,})$/i.exec(suffix);
+        if (placeholderRes && placeholderRes.groups && placeholderRes.groups.value) {
+          const placeholderVal = placeholderRes.groups.value;
+          const fixPlaceholderRegex = new RegExp(`placeholder\-${placeholderVal}$`);
+          outdated.push([cls, cls.replace(fixPlaceholderRegex, `placeholder:text\-${placeholderVal}`)]);
+        }
+        return true;
+      });
+
+      if (notNeeded.length) {
+        let validatedClassNamesValue = filtered.join(isSingleLine ? ' ' : '\n');
+        validatedClassNamesValue = prefix + validatedClassNamesValue + suffix;
+        context.report({
+          node,
+          messageId: notNeeded.length === 1 ? 'classnameNotNeeded' : 'classnamesNotNeeded',
+          data: {
+            classnames: notNeeded.join(', '),
+          },
+          fix: function (fixer) {
+            return fixer.replaceTextRange([start, end], validatedClassNamesValue);
+          },
+        });
+      }
+
+      outdated.forEach((outdatedClass) => {
+        let validatedClassNamesValue = filtered.join(isSingleLine ? ' ' : '\n');
+        validatedClassNamesValue =
+          prefix + validatedClassNamesValue.replace(outdatedClass[0], outdatedClass[1]) + suffix;
+        context.report({
+          node,
+          messageId: 'classnameChanged',
+          data: {
+            deprecated: outdatedClass[0],
+            updated: outdatedClass[1],
+          },
+          fix: function (fixer) {
+            return fixer.replaceTextRange([start, end], validatedClassNamesValue);
+          },
+        });
+      });
+      deprecatedBgOpacity.forEach((bgClass) => {
+        context.report({
+          node,
+          messageId: 'bgOpacityDeprecated',
+          data: {
+            classname: bgClass[0],
+            value: bgClass[1],
+          },
+        });
+      });
+    };
+
+    //----------------------------------------------------------------------
+    // Public
+    //----------------------------------------------------------------------
+
+    const scriptVisitor = {
+      JSXAttribute: function (node) {
+        if (!astUtil.isValidJSXAttribute(node)) {
+          return;
+        }
+        parseForObsoleteClassNames(node);
+      },
+      CallExpression: function (node) {
+        if (callees.findIndex((name) => node.callee.name === name) === -1) {
+          return;
+        }
+        node.arguments.forEach((arg) => {
+          parseForObsoleteClassNames(node, arg);
+        });
+      },
+      TaggedTemplateExpression: function (node) {
+        if (!tags.includes(node.tag.name)) {
+          return;
+        }
+        parseForObsoleteClassNames(node, node.quasi);
+      },
+    };
+
+    const templateVisitor = {
+      VAttribute: function (node) {
+        if (!astUtil.isValidVueAttribute(node)) {
+          return;
+        }
+        parseForObsoleteClassNames(node);
+      },
+    };
+
+    return parserUtil.defineTemplateBodyVisitor(context, templateVisitor, scriptVisitor);
+  },
+};
diff --git a/lib/util/groupMethods.js b/lib/util/groupMethods.js
index 8ac50f3..e2cac6f 100644
--- a/lib/util/groupMethods.js
+++ b/lib/util/groupMethods.js
@@ -32,20 +32,6 @@ function escapeSpecialChars(str) {
   return str.replace(/[\-\.\/]/g, '\\$&');
 }
 
-/**
- * Get additional opacity suffix if property supports it
- *
- * @param {String} propName The property
- * @param {Object} config Tailwind CSS Config
- * @returns {String} The suffix or an empty string
- */
-function getOpacitySuffix(propName, config) {
-  if (['backgroundColor', 'textColor', 'placeholderColor'].includes(propName)) {
-    return generateOptionalOpacitySuffix(config);
-  }
-  return '';
-}
-
 /**
  * Generates the opacity suffix based on config
  *
@@ -70,8 +56,9 @@ function generateOptionalOpacitySuffix(config) {
  * @returns {String} Generated part of regex exposing the possible values
  */
 function generateOptions(propName, keys, config, isNegative = false) {
+  const opacitySuffixes = generateOptionalOpacitySuffix(config);
   const genericArbitraryOption = '\\[(.*)\\]';
-  const supportArbitrary = config.mode === 'jit' && !isNegative;
+  const supportArbitrary = !isNegative;
   const defaultKeyIndex = keys.findIndex((v) => v === 'DEFAULT');
   if (defaultKeyIndex > -1) {
     keys.splice(defaultKeyIndex, 1);
@@ -80,20 +67,28 @@ function generateOptions(propName, keys, config, isNegative = false) {
     case 'dark':
       // Optional `dark` class
       return config.darkMode === 'class' ? 'dark' : '';
+    case 'arbitraryProperties':
+      keys.push(genericArbitraryOption);
+      return '(' + keys.join('|') + ')';
+    case 'accentColor':
     case 'backgroundColor':
     case 'borderColor':
+    case 'boxShadowColor':
+    case 'caretColor':
     case 'divideColor':
+    case 'fill':
+    case 'outlineColor':
     case 'ringColor':
     case 'ringOffsetColor':
     case 'textColor':
+    case 'textDecorationColor':
     case 'stroke':
     case 'gradientColorStops':
-    case 'placeholderColor':
       // Colors can use segments like 'indigo' and 'indigo-light'
       // https://tailwindcss.com/docs/customizing-colors#color-object-syntax
       const options = [];
       // Conditionnaly generates the opacity suffix
-      const opacitySuffix = supportArbitrary ? getOpacitySuffix(propName, config) : '';
+      const opacitySuffix = supportArbitrary ? opacitySuffixes : '';
       keys.forEach((k) => {
         const color = config.theme[propName][k] || config.theme.colors[k];
         if (typeof color === 'string') {
@@ -111,12 +106,19 @@ function generateOptions(propName, keys, config, isNegative = false) {
       if (supportArbitrary) {
         const arbitraryColors = [...color.mergedColorValues];
         switch (propName) {
+          case 'fill':
+            // Forbidden prefixes
+            arbitraryColors.push(`(?!(angle|length|list)\:).{1,}`);
+            break;
           case 'gradientColorStops':
-          case 'placeholderColor':
             arbitraryColors.push(color.RGBAPercentages); // RGBA % 0.5[%]
             arbitraryColors.push(color.optionalColorPrefixedVar);
             arbitraryColors.push(color.notHSLAPlusWildcard);
             break;
+          case 'textColor':
+            arbitraryColors.push(color.RGBAPercentages); // RGBA % 0.5[%]
+            arbitraryColors.push(color.mandatoryColorPrefixed);
+            break;
           default:
             arbitraryColors.push(color.mandatoryColorPrefixed);
         }
@@ -126,24 +128,23 @@ function generateOptions(propName, keys, config, isNegative = false) {
     case 'borderWidth':
     case 'divideWidth':
     case 'fontSize':
+    case 'outlineWidth':
+    case 'outlineOffset':
     case 'ringWidth':
     case 'ringOffsetWidth':
-      if (supportArbitrary) {
-        keys.push(length.selectedUnitsRegEx);
-        keys.push(length.anyCalcRegEx);
-        // Mandatory `length:` prefix + wildcard
-        keys.push(`\\[length\\:.{1,}\\]`);
-      }
+    case 'textUnderlineOffset':
+      keys.push(length.selectedUnitsRegEx);
+      keys.push(length.anyCalcRegEx);
+      // Mandatory `length:` prefix + wildcard
+      keys.push(`\\[length\\:.{1,}\\]`);
       return '(' + keys.join('|') + ')';
     case 'strokeWidth':
-      if (supportArbitrary) {
-        keys.push(length.selectedUnitsRegEx);
-        keys.push(length.anyCalcRegEx);
-        // Mandatory `length:` prefix + calc + wildcard
-        keys.push(`\\[length\\:calc\\(.{1,}\\)\\]`);
-        // Mandatory `length:` prefix + wildcard + optional units
-        keys.push(`\\[length\\:(.{1,})(${length.selectedUnits.join('|')})?\\]`);
-      }
+      keys.push(length.selectedUnitsRegEx);
+      keys.push(length.anyCalcRegEx);
+      // Mandatory `length:` prefix + calc + wildcard
+      keys.push(`\\[length\\:calc\\(.{1,}\\)\\]`);
+      // Mandatory `length:` prefix + wildcard + optional units
+      keys.push(`\\[length\\:(.{1,})(${length.selectedUnits.join('|')})?\\]`);
       return '(' + keys.join('|') + ')';
     case 'gap':
     case 'height':
@@ -154,15 +155,10 @@ function generateOptions(propName, keys, config, isNegative = false) {
     case 'minWidth':
     case 'padding':
     case 'width':
-    case 'inset':
-    case 'letterSpacing':
-    case 'margin':
-    case 'space':
     case 'blur':
     case 'brightness':
     case 'contrast':
     case 'grayscale':
-    case 'hueRotate':
     case 'invert':
     case 'saturate':
     case 'sepia':
@@ -170,7 +166,6 @@ function generateOptions(propName, keys, config, isNegative = false) {
     case 'backdropBrightness':
     case 'backdropContrast':
     case 'backdropGrayscale':
-    case 'backdropHueRotate':
     case 'backdropInvert':
     case 'backdropOpacity':
     case 'backdropSaturate':
@@ -181,10 +176,7 @@ function generateOptions(propName, keys, config, isNegative = false) {
     case 'animation':
     case 'transformOrigin':
     case 'scale':
-    case 'translate':
-    case 'skew':
     case 'cursor':
-    case 'outline':
       if (supportArbitrary) {
         // All units
         keys.push(length.mergedUnitsRegEx);
@@ -192,28 +184,29 @@ function generateOptions(propName, keys, config, isNegative = false) {
         keys.push(`\\[(?!(angle|color|length|list)\:).{1,}\\]`);
       }
       return '(' + keys.join('|') + ')';
-    case 'fill':
+    case 'backdropHueRotate':
+    case 'hueRotate':
+    case 'inset':
+    case 'letterSpacing':
+    case 'margin':
+    case 'scrollMargin':
+    case 'skew':
+    case 'space':
+    case 'textIndent':
+    case 'translate':
       if (supportArbitrary) {
         // All units
         keys.push(length.mergedUnitsRegEx);
         // Forbidden prefixes
-        keys.push(`\\[(?!(angle|length|list)\:).{1,}\\]`);
+        keys.push(`\\[(?!(angle|color|length|list)\:).{1,}\\]`);
       }
       return '(' + keys.join('|') + ')';
-    case 'placeholderOpacity':
-    case 'textOpacity':
-    case 'backgroundOpacity':
-    case 'borderOpacity':
-    case 'divideOpacity':
-    case 'ringOpacity':
     case 'opacity':
-      if (supportArbitrary) {
-        // 0 ... .5 ... 1
-        keys.push(`\\[(0(\\.\\d{1,})?|\\.\\d{1,}|1)\\]`);
-        keys.push(length.anyCalcRegEx);
-        // Unprefixed var()
-        keys.push(`\\[var\\(\\-\\-[A-Za-z\\-]{1,}\\)\\]`);
-      }
+      // 0 ... .5 ... 1
+      keys.push(`\\[(0(\\.\\d{1,})?|\\.\\d{1,}|1)\\]`);
+      keys.push(length.anyCalcRegEx);
+      // Unprefixed var()
+      keys.push(`\\[var\\(\\-\\-[A-Za-z\\-]{1,}\\)\\]`);
       return '(' + keys.join('|') + ')';
     case 'rotate':
       if (supportArbitrary) {
@@ -230,46 +223,51 @@ function generateOptions(propName, keys, config, isNegative = false) {
     case 'gridRowEnd':
     case 'gridAutoColumns':
     case 'gridAutoRows':
-      if (supportArbitrary) {
-        // Forbidden prefixes
-        keys.push(`\\[(?!(angle|color|length)\:).{1,}\\]`);
-      }
+      // Forbidden prefixes
+      keys.push(`\\[(?!(angle|color|length)\:).{1,}\\]`);
       return '(' + keys.join('|') + ')';
     case 'listStyleType':
-      if (supportArbitrary) {
-        // Forbidden prefixes
-        keys.push(`\\[(?!(angle|color|length|list)\:).{1,}\\]`);
-      }
+      // Forbidden prefixes
+      keys.push(`\\[(?!(angle|color|length|list)\:).{1,}\\]`);
       return '(' + keys.join('|') + ')';
     case 'objectPosition':
-      if (supportArbitrary) {
-        // Forbidden prefixes
-        keys.push(`\\[(?!(angle|color|length)\:).{1,}\\]`);
-      }
+      // Forbidden prefixes
+      keys.push(`\\[(?!(angle|color|length)\:).{1,}\\]`);
       return '(' + keys.join('|') + ')';
     case 'backgroundPosition':
-    case 'backgroundSize':
-    case 'backgroundImage':
-    case 'fontFamily':
-    case 'fontWeight':
     case 'boxShadow':
     case 'dropShadow':
     case 'transitionProperty':
+      // Forbidden prefixes
+      keys.push(`\\[(?!((angle|color|length|list)\:)|var\\().{1,}\\]`);
+      return '(' + keys.join('|') + ')';
+    case 'backgroundSize':
+      // Forbidden prefixes
+      keys.push(`\\[length\:.{1,}\\]`);
+      return '(' + keys.join('|') + ')';
+    case 'backgroundImage':
+      // Forbidden prefixes
+      keys.push(`\\[url\\(.{1,}\\)\\]`);
+      return '(' + keys.join('|') + ')';
+    case 'order':
+    case 'zIndex':
+      if (supportArbitrary) {
+        keys.push(genericArbitraryOption);
+      }
+      return '(' + keys.join('|') + ')';
+    case 'fontWeight':
     case 'typography':
-    case 'aspectRatio':
     case 'lineClamp':
       // Cannot be arbitrary?
       return '(' + keys.join('|') + ')';
+    case 'aspectRatio':
     case 'flexGrow':
     case 'flexShrink':
-    case 'order':
-    case 'zIndex':
+    case 'fontFamily':
     case 'flex':
     case 'borderRadius':
     default:
-      if (supportArbitrary) {
-        keys.push(genericArbitraryOption);
-      }
+      keys.push(genericArbitraryOption);
       return '(' + keys.join('|') + ')';
   }
 }
@@ -282,10 +280,7 @@ function generateOptions(propName, keys, config, isNegative = false) {
  * @returns {String} Patched version with config values and additinal parameters
  */
 function patchRegex(re, config) {
-  let patched = '';
-  if (config.mode === 'jit') {
-    patched += '\\!?';
-  }
+  let patched = '\\!?';
   // Prefix
   if (config.prefix.length) {
     patched += escapeSpecialChars(config.prefix);
@@ -293,35 +288,60 @@ function patchRegex(re, config) {
   // Props
   let replaced = re;
   const propsRe = /\$\{(\-?[a-z]*)\}/gi;
-  const props = [...replaced.matchAll(propsRe)].map((arr) => arr[1]);
+  const res = replaced.matchAll(propsRe);
+  const resArray = [...res];
+  const props = resArray.map((arr) => arr[1]);
   if (props.length === 0) {
     return patched + replaced;
   }
-  // e.g. backgroundColor, letterSpacing...
+  // e.g. backgroundColor, letterSpacing, -margin...
   props.forEach((prop) => {
     const token = new RegExp('\\$\\{' + prop + '\\}');
     const isNegative = prop.substr(0, 1) === '-';
-    const patchedProp = isNegative ? prop.substr(1) : prop;
+    const absoluteProp = isNegative ? prop.substr(1) : prop;
     if (prop === 'dark') {
       // Special case, not a default property from the theme
-      replaced = replaced.replace(token, generateOptions(patchedProp, [], config, isNegative));
+      replaced = replaced.replace(token, generateOptions(absoluteProp, [], config, isNegative));
+      return patched + replaced;
+    } else if (prop === 'arbitraryProperties') {
+      // Special case
+      replaced = replaced.replace(
+        new RegExp('\\$\\{' + absoluteProp + '\\}'),
+        generateOptions(absoluteProp, [], config, isNegative)
+      );
       return patched + replaced;
-    } else if (!config.theme || !config.theme[patchedProp]) {
+    } else if (!config.theme || !config.theme[absoluteProp]) {
       // prop not found in config
       return;
     }
-    const keys = Object.keys(config.theme[patchedProp]).filter((k) => {
-      const first = k.substr(0, 1);
-      return isNegative ? first === '-' : first !== '-';
-    });
-    const absoluteKeys = keys.map((k) => {
-      return isNegative ? k.substr(1) : k;
-    });
+    // Normal scenario
+    const keys = Object.keys(config.theme[absoluteProp])
+      .filter((key) => {
+        if (isNegative) {
+          // Negative prop cannot support NaN values and inherits positive values
+          const val = config.theme[absoluteProp][key];
+          const num = parseFloat(val);
+          if (isNaN(num)) {
+            return false;
+          }
+        } else if (key[0] === '-') {
+          // Positive prop cannot use key starting with '-'
+          return false;
+        }
+        return true;
+      })
+      .map((key) => {
+        if (isNegative && key[0] === '-') {
+          return key.substring(1);
+        }
+        return key;
+      });
     if (keys.length === 0 || replaced.match(token) === null) {
       // empty array
       return;
     }
-    replaced = replaced.replace(token, generateOptions(patchedProp, absoluteKeys, config, isNegative));
+    const opts = generateOptions(absoluteProp, keys, config, isNegative);
+    replaced = replaced.replace(token, opts);
   });
   return patched + replaced;
 }
@@ -334,7 +354,6 @@ function patchRegex(re, config) {
  * @returns {Array} Flatten array
  */
 function getGroups(groupsConfig, twConfig = null) {
-  const jitEnabled = twConfig && twConfig.mode && twConfig.mode === 'jit';
   const groups = [];
   groupsConfig.forEach((group) => {
     // e.g. SIZING or SPACING
@@ -346,14 +365,7 @@ function getGroups(groupsConfig, twConfig = null) {
       } else {
         // Multiple properties, like `padding`, `padding-top`...
         prop.members.forEach((subprop) => {
-          const jitOnly = subprop['mode'] === 'jit';
-          if (!jitOnly) {
-            // Supported
-            groups.push(subprop.members);
-          } else if (jitEnabled) {
-            // Only supported via JIT mode
-            groups.push(subprop.members);
-          }
+          groups.push(subprop.members);
         });
       }
     });
@@ -401,6 +413,15 @@ function getGroupIndex(name, arr, separator = ':') {
  * @returns {String} The classname without its variants
  */
 function getSuffix(className, separator = ':') {
+  const arbitraryPropertiesRe = new RegExp(
+    `^\\!?([a-z]*${escapeSpecialChars(separator)})*(?<value>\\[(.{1,})\\])$`,
+    'i'
+  );
+  let res = arbitraryPropertiesRe.exec(className);
+  if (res && res.groups && res.groups.value) {
+    // arbitraryProperties detected !
+    return res.groups.value;
+  }
   const arbitraryArr = className.split('-[');
   if (arbitraryArr.length === 1) {
     return className.split(separator).pop();
@@ -409,7 +430,8 @@ function getSuffix(className, separator = ':') {
 }
 
 module.exports = {
-  getGroups,
   initGroupSlots,
+  getGroups,
   getGroupIndex,
+  getSuffix,
 };
diff --git a/lib/util/settings.js b/lib/util/settings.js
index 7068b22..592d3ea 100644
--- a/lib/util/settings.js
+++ b/lib/util/settings.js
@@ -20,7 +20,7 @@ function getOption(context, name) {
     case 'cssFiles':
       return ['**/*.css', '!**/node_modules'];
     case 'groupByResponsive':
-      return false;
+      return true;
     case 'groups':
       return defaultGroups;
     case 'prependCustom':
diff --git a/package-lock.json b/package-lock.json
index d0491c0..f198d2b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
 {
   "name": "eslint-plugin-tailwindcss",
-  "version": "1.17.2",
+  "version": "3.0.0",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
@@ -8,7 +8,6 @@
       "version": "7.12.11",
       "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz",
       "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==",
-      "dev": true,
       "requires": {
         "@babel/highlight": "^7.10.4"
       }
@@ -16,14 +15,12 @@
     "@babel/helper-validator-identifier": {
       "version": "7.12.11",
       "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz",
-      "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==",
-      "dev": true
+      "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw=="
     },
     "@babel/highlight": {
       "version": "7.13.10",
       "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.10.tgz",
       "integrity": "sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg==",
-      "dev": true,
       "requires": {
         "@babel/helper-validator-identifier": "^7.12.11",
         "chalk": "^2.0.0",
@@ -34,7 +31,6 @@
           "version": "2.4.2",
           "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
           "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
-          "dev": true,
           "requires": {
             "ansi-styles": "^3.2.1",
             "escape-string-regexp": "^1.0.5",
@@ -71,14 +67,6 @@
         }
       }
     },
-    "@fullhuman/postcss-purgecss": {
-      "version": "3.1.3",
-      "resolved": "https://registry.npmjs.org/@fullhuman/postcss-purgecss/-/postcss-purgecss-3.1.3.tgz",
-      "integrity": "sha512-kwOXw8fZ0Lt1QmeOOrd+o4Ibvp4UTEBFQbzvWldjlKv5n+G9sXfIPn1hh63IQIL8K8vbvv1oYMJiIUbuy9bGaA==",
-      "requires": {
-        "purgecss": "^3.1.3"
-      }
-    },
     "@nodelib/fs.scandir": {
       "version": "2.1.5",
       "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -103,21 +91,30 @@
       }
     },
     "@tailwindcss/aspect-ratio": {
-      "version": "0.2.0",
-      "resolved": "https://registry.npmjs.org/@tailwindcss/aspect-ratio/-/aspect-ratio-0.2.0.tgz",
-      "integrity": "sha512-v5LyHkwXj/4lI74B06zUrmWEdmSqS43+jw717pkt3fAXqb7ALwu77A8t7j+Bej+ZbdlIIqNMYheGN7wSGV1A6w==",
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/@tailwindcss/aspect-ratio/-/aspect-ratio-0.4.0.tgz",
+      "integrity": "sha512-WJu0I4PpqNPuutpaA9zDUq2JXR+lorZ7PbLcKNLmb6GL9/HLfC7w3CRsMhJF4BbYd/lkY6CfXOvkYpuGnZfkpQ==",
       "dev": true
     },
+    "@tailwindcss/forms": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.4.0.tgz",
+      "integrity": "sha512-DeaQBx6EgEeuZPQACvC+mKneJsD8am1uiJugjgQK1+/Vt+Ai0GpFBC2T2fqnUad71WgOxyrZPE6BG1VaI6YqfQ==",
+      "dev": true,
+      "requires": {
+        "mini-svg-data-uri": "^1.2.3"
+      }
+    },
     "@tailwindcss/line-clamp": {
-      "version": "0.2.0",
-      "resolved": "https://registry.npmjs.org/@tailwindcss/line-clamp/-/line-clamp-0.2.0.tgz",
-      "integrity": "sha512-+jXSdRK3/9V/BCPCr+iNpMMhxWMMv62vn/AS2b3/ClmueGuhCijW3bUwO1IiHnE7uCaF74Sli8jUCv9djwvpLg==",
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/@tailwindcss/line-clamp/-/line-clamp-0.3.0.tgz",
+      "integrity": "sha512-ffDDclrqr3sy8cpChCozedDUAN8enxqAiWeH8d4dGQ2hcXlxf51+7KleveFi/n/TxEuRVApoL7hICeDOdYPKpg==",
       "dev": true
     },
     "@tailwindcss/typography": {
-      "version": "0.4.0",
-      "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.4.0.tgz",
-      "integrity": "sha512-3BfOYT5MYNEq81Ism3L2qu/HRP2Q5vWqZtZRQqQrthHuaTK9qpuPfbMT5WATjAM5J1OePKBaI5pLoX4S1JGNMQ==",
+      "version": "0.5.0",
+      "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.0.tgz",
+      "integrity": "sha512-1p/3C6C+JJziS/ghtG8ACYalbA2SyLJY27Pm33cVTlAoY6VQ7zfm2H64cPxUMBkVIlWXTtWHhZcZJPobMRmQAA==",
       "dev": true,
       "requires": {
         "lodash.castarray": "^4.4.0",
@@ -126,6 +123,11 @@
         "lodash.uniq": "^4.5.0"
       }
     },
+    "@types/parse-json": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
+      "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA=="
+    },
     "@typescript-eslint/parser": {
       "version": "4.33.0",
       "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.33.0.tgz",
@@ -241,11 +243,17 @@
       "version": "3.1.1",
       "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz",
       "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==",
+      "dev": true,
       "requires": {
         "normalize-path": "^3.0.0",
         "picomatch": "^2.0.4"
       }
     },
+    "arg": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.1.tgz",
+      "integrity": "sha512-e0hDa9H2Z9AwFkk2qDlwhoMYE4eToKarchkQHovNdLTCYMHZHeRjI71crOh+dio4K6u1IcwubQqo79Ga4CyAQA=="
+    },
     "argparse": {
       "version": "1.0.10",
       "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
@@ -267,10 +275,19 @@
       "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
       "dev": true
     },
-    "at-least-node": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
-      "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg=="
+    "autoprefixer": {
+      "version": "10.4.0",
+      "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.0.tgz",
+      "integrity": "sha512-7FdJ1ONtwzV1G43GDD0kpVMn/qbiNqyOPMFTX5nRffI+7vgWoFEc6DcXOxHJxrWNDXrZh18eDsZjvZGUljSRGA==",
+      "dev": true,
+      "requires": {
+        "browserslist": "^4.17.5",
+        "caniuse-lite": "^1.0.30001272",
+        "fraction.js": "^4.1.1",
+        "normalize-range": "^0.1.2",
+        "picocolors": "^1.0.0",
+        "postcss-value-parser": "^4.1.0"
+      }
     },
     "balanced-match": {
       "version": "1.0.0",
@@ -305,10 +322,18 @@
       "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
       "dev": true
     },
-    "bytes": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
-      "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
+    "browserslist": {
+      "version": "4.18.1",
+      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.18.1.tgz",
+      "integrity": "sha512-8ScCzdpPwR2wQh8IT82CA2VgDwjHyqMovPBZSNH54+tm4Jk2pCuv90gmAdH6J84OCRWi0b4gMe6O6XPXuJnjgQ==",
+      "dev": true,
+      "requires": {
+        "caniuse-lite": "^1.0.30001280",
+        "electron-to-chromium": "^1.3.896",
+        "escalade": "^3.1.1",
+        "node-releases": "^2.0.1",
+        "picocolors": "^1.0.0"
+      }
     },
     "call-bind": {
       "version": "1.0.2",
@@ -323,8 +348,7 @@
     "callsites": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
-      "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
-      "dev": true
+      "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="
     },
     "camelcase": {
       "version": "5.3.1",
@@ -337,10 +361,17 @@
       "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
       "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA=="
     },
+    "caniuse-lite": {
+      "version": "1.0.30001286",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001286.tgz",
+      "integrity": "sha512-zaEMRH6xg8ESMi2eQ3R4eZ5qw/hJiVsO/HlLwniIwErij0JDr9P+8V4dtx1l+kLq6j3yy8l8W4fst1lBnat5wQ==",
+      "dev": true
+    },
     "chalk": {
       "version": "4.1.0",
       "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
       "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
+      "dev": true,
       "requires": {
         "ansi-styles": "^4.1.0",
         "supports-color": "^7.1.0"
@@ -350,6 +381,7 @@
           "version": "4.3.0",
           "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
           "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "dev": true,
           "requires": {
             "color-convert": "^2.0.1"
           }
@@ -358,6 +390,7 @@
           "version": "2.0.1",
           "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
           "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
           "requires": {
             "color-name": "~1.1.4"
           }
@@ -365,17 +398,20 @@
         "color-name": {
           "version": "1.1.4",
           "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true
         },
         "has-flag": {
           "version": "4.0.0",
           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true
         },
         "supports-color": {
           "version": "7.2.0",
           "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
           "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "dev": true,
           "requires": {
             "has-flag": "^4.0.0"
           }
@@ -449,15 +485,6 @@
         }
       }
     },
-    "color": {
-      "version": "3.1.3",
-      "resolved": "https://registry.npmjs.org/color/-/color-3.1.3.tgz",
-      "integrity": "sha512-xgXAcTHa2HeFCGLE9Xs/R82hujGtu9Jd9x4NW3T34+OMs7VoPsjwzRczKHvTAHeJwWFwX5j15+MgAppE8ztObQ==",
-      "requires": {
-        "color-convert": "^1.9.1",
-        "color-string": "^1.5.4"
-      }
-    },
     "color-convert": {
       "version": "1.9.3",
       "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
@@ -471,30 +498,23 @@
       "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
       "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
     },
-    "color-string": {
-      "version": "1.5.5",
-      "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.5.tgz",
-      "integrity": "sha512-jgIoum0OfQfq9Whcfc2z/VhCNcmQjWbey6qBX0vqt7YICflUmBCh9E9CiQD5GSJ+Uehixm3NUwHVhqUAWRivZg==",
-      "requires": {
-        "color-name": "^1.0.0",
-        "simple-swizzle": "^0.2.2"
-      }
-    },
-    "colorette": {
-      "version": "1.2.2",
-      "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz",
-      "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w=="
-    },
-    "commander": {
-      "version": "6.2.1",
-      "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
-      "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA=="
-    },
     "concat-map": {
       "version": "0.0.1",
       "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
       "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
     },
+    "cosmiconfig": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz",
+      "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==",
+      "requires": {
+        "@types/parse-json": "^4.0.0",
+        "import-fresh": "^3.2.1",
+        "parse-json": "^5.0.0",
+        "path-type": "^4.0.0",
+        "yaml": "^1.10.0"
+      }
+    },
     "cross-spawn": {
       "version": "7.0.3",
       "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@@ -506,11 +526,6 @@
         "which": "^2.0.1"
       }
     },
-    "css-unit-converter": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz",
-      "integrity": "sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA=="
-    },
     "cssesc": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
@@ -562,9 +577,9 @@
       }
     },
     "didyoumean": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.1.tgz",
-      "integrity": "sha1-6S7f2tplN9SE1zwBcv0eugxJdv8="
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
+      "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw=="
     },
     "diff": {
       "version": "3.5.0",
@@ -595,6 +610,12 @@
         "esutils": "^2.0.2"
       }
     },
+    "electron-to-chromium": {
+      "version": "1.4.15",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.15.tgz",
+      "integrity": "sha512-WDw2IUL3k4QpbzInV3JZK+Zd1NjWJPDZ28oUSchWb/kf6AVj7/niaAlgcJlvojFa1d7pJSyQ/KSZsEtq5W7aGQ==",
+      "dev": true
+    },
     "emoji-regex": {
       "version": "8.0.0",
       "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
@@ -610,6 +631,14 @@
         "ansi-colors": "^4.1.1"
       }
     },
+    "error-ex": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+      "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+      "requires": {
+        "is-arrayish": "^0.2.1"
+      }
+    },
     "es-abstract": {
       "version": "1.18.0",
       "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0.tgz",
@@ -659,6 +688,12 @@
         "is-symbol": "^1.0.2"
       }
     },
+    "escalade": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
+      "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
+      "dev": true
+    },
     "escape-string-regexp": {
       "version": "1.0.5",
       "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
@@ -903,16 +938,11 @@
       "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==",
       "dev": true
     },
-    "fs-extra": {
-      "version": "9.1.0",
-      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
-      "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
-      "requires": {
-        "at-least-node": "^1.0.0",
-        "graceful-fs": "^4.2.0",
-        "jsonfile": "^6.0.1",
-        "universalify": "^2.0.0"
-      }
+    "fraction.js": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.1.2.tgz",
+      "integrity": "sha512-o2RiJQ6DZaR/5+Si0qJUIy637QMRudSi9kU/FFzx9EZazrIdnBgpU+3sEWCxAVhH2RtxW2Oz+T4p2o8uOPVcgA==",
+      "dev": true
     },
     "fs.realpath": {
       "version": "1.0.0",
@@ -967,38 +997,6 @@
         "path-is-absolute": "^1.0.0"
       }
     },
-    "glob-base": {
-      "version": "0.3.0",
-      "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz",
-      "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=",
-      "requires": {
-        "glob-parent": "^2.0.0",
-        "is-glob": "^2.0.0"
-      },
-      "dependencies": {
-        "glob-parent": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz",
-          "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=",
-          "requires": {
-            "is-glob": "^2.0.0"
-          }
-        },
-        "is-extglob": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
-          "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA="
-        },
-        "is-glob": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
-          "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
-          "requires": {
-            "is-extglob": "^1.0.0"
-          }
-        }
-      }
-    },
     "glob-parent": {
       "version": "5.1.2",
       "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
@@ -1046,11 +1044,6 @@
         }
       }
     },
-    "graceful-fs": {
-      "version": "4.2.6",
-      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz",
-      "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ=="
-    },
     "growl": {
       "version": "1.10.5",
       "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz",
@@ -1088,27 +1081,44 @@
       "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
       "dev": true
     },
-    "html-tags": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.1.0.tgz",
-      "integrity": "sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg=="
-    },
     "ignore": {
       "version": "4.0.6",
       "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
       "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
       "dev": true
     },
+    "import-cwd": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-3.0.0.tgz",
+      "integrity": "sha512-4pnzH16plW+hgvRECbDWpQl3cqtvSofHWh44met7ESfZ8UZOWWddm8hEyDTqREJ9RbYHY8gi8DqmaelApoOGMg==",
+      "requires": {
+        "import-from": "^3.0.0"
+      }
+    },
     "import-fresh": {
       "version": "3.3.0",
       "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
       "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
-      "dev": true,
       "requires": {
         "parent-module": "^1.0.0",
         "resolve-from": "^4.0.0"
       }
     },
+    "import-from": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/import-from/-/import-from-3.0.0.tgz",
+      "integrity": "sha512-CiuXOFFSzkU5x/CR0+z7T91Iht4CXgfCxVOFRhh2Zyhg5wOpWvvDLQUsWl+gcN+QscYBjez8hDCt85O7RLDttQ==",
+      "requires": {
+        "resolve-from": "^5.0.0"
+      },
+      "dependencies": {
+        "resolve-from": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+          "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="
+        }
+      }
+    },
     "imurmurhash": {
       "version": "0.1.4",
       "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
@@ -1130,9 +1140,9 @@
       "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
     },
     "is-arrayish": {
-      "version": "0.3.2",
-      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
-      "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+      "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0="
     },
     "is-bigint": {
       "version": "1.0.1",
@@ -1170,9 +1180,9 @@
       "dev": true
     },
     "is-core-module": {
-      "version": "2.4.0",
-      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz",
-      "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==",
+      "version": "2.8.0",
+      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz",
+      "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==",
       "requires": {
         "has": "^1.0.3"
       }
@@ -1183,11 +1193,6 @@
       "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==",
       "dev": true
     },
-    "is-dotfile": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz",
-      "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE="
-    },
     "is-extglob": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@@ -1258,8 +1263,7 @@
     "js-tokens": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
-      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
-      "dev": true
+      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
     },
     "js-yaml": {
       "version": "3.14.1",
@@ -1271,6 +1275,11 @@
         "esprima": "^4.0.0"
       }
     },
+    "json-parse-even-better-errors": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
+      "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="
+    },
     "json-schema-traverse": {
       "version": "0.4.1",
       "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
@@ -1283,15 +1292,6 @@
       "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=",
       "dev": true
     },
-    "jsonfile": {
-      "version": "6.1.0",
-      "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
-      "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
-      "requires": {
-        "graceful-fs": "^4.1.6",
-        "universalify": "^2.0.0"
-      }
-    },
     "levn": {
       "version": "0.4.1",
       "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
@@ -1302,6 +1302,16 @@
         "type-check": "~0.4.0"
       }
     },
+    "lilconfig": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.4.tgz",
+      "integrity": "sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA=="
+    },
+    "lines-and-columns": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+      "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
+    },
     "locate-path": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
@@ -1315,7 +1325,8 @@
     "lodash": {
       "version": "4.17.21",
       "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
-      "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
+      "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
+      "dev": true
     },
     "lodash.castarray": {
       "version": "4.4.0",
@@ -1335,16 +1346,6 @@
       "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
       "dev": true
     },
-    "lodash.toarray": {
-      "version": "4.4.0",
-      "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz",
-      "integrity": "sha1-JMS/zWsvuji/0FlNsRedjptlZWE="
-    },
-    "lodash.topath": {
-      "version": "4.5.2",
-      "resolved": "https://registry.npmjs.org/lodash.topath/-/lodash.topath-4.5.2.tgz",
-      "integrity": "sha1-NhY1Hzu6YZlKCTGYlmC9AyVP0Ak="
-    },
     "lodash.uniq": {
       "version": "4.5.0",
       "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
@@ -1403,6 +1404,12 @@
         }
       }
     },
+    "mini-svg-data-uri": {
+      "version": "1.4.3",
+      "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.3.tgz",
+      "integrity": "sha512-gSfqpMRC8IxghvMcxzzmMnWpXAChSA+vy4cia33RgerMS8Fex95akUyQZPbxJJmeBGiGmK7n/1OpUX8ksRjIdA==",
+      "dev": true
+    },
     "minimatch": {
       "version": "3.0.4",
       "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
@@ -1528,11 +1535,6 @@
         }
       }
     },
-    "modern-normalize": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/modern-normalize/-/modern-normalize-1.1.0.tgz",
-      "integrity": "sha512-2lMlY1Yc1+CUy0gw4H95uNN7vjbpoED7NNRSBHE25nWfLBdmMzFCsPshlzbxHz+gYMcBEUN8V4pU16prcdPSgA=="
-    },
     "ms": {
       "version": "2.1.2",
       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@@ -1540,9 +1542,9 @@
       "dev": true
     },
     "nanoid": {
-      "version": "3.1.23",
-      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz",
-      "integrity": "sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw=="
+      "version": "3.1.30",
+      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.30.tgz",
+      "integrity": "sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ=="
     },
     "natural-compare": {
       "version": "1.4.0",
@@ -1550,14 +1552,6 @@
       "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
       "dev": true
     },
-    "node-emoji": {
-      "version": "1.10.0",
-      "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.10.0.tgz",
-      "integrity": "sha512-Yt3384If5H6BYGVHiHwTL+99OzJKHhgp82S8/dktEK73T26BazdgZ4JZh92xSVtGNJvz9UbXdNAc5hcrXV42vw==",
-      "requires": {
-        "lodash.toarray": "^4.4.0"
-      }
-    },
     "node-environment-flags": {
       "version": "1.0.6",
       "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz",
@@ -1576,20 +1570,27 @@
         }
       }
     },
+    "node-releases": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz",
+      "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==",
+      "dev": true
+    },
     "normalize-path": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
       "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="
     },
-    "object-assign": {
-      "version": "4.1.1",
-      "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
-      "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
+    "normalize-range": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
+      "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=",
+      "dev": true
     },
     "object-hash": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.1.1.tgz",
-      "integrity": "sha512-VOJmgmS+7wvXf8CjbQmimtCnEx3IAoLxI3fp2fbWehxrWBcAQFbk+vcwb6vzR0VZv/eNCJ/27j151ZTwqW/JeQ=="
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz",
+      "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw=="
     },
     "object-inspect": {
       "version": "1.9.0",
@@ -1676,35 +1677,19 @@
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
       "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
-      "dev": true,
       "requires": {
         "callsites": "^3.0.0"
       }
     },
-    "parse-glob": {
-      "version": "3.0.4",
-      "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz",
-      "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=",
+    "parse-json": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
+      "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
       "requires": {
-        "glob-base": "^0.3.0",
-        "is-dotfile": "^1.0.0",
-        "is-extglob": "^1.0.0",
-        "is-glob": "^2.0.0"
-      },
-      "dependencies": {
-        "is-extglob": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
-          "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA="
-        },
-        "is-glob": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
-          "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
-          "requires": {
-            "is-extglob": "^1.0.0"
-          }
-        }
+        "@babel/code-frame": "^7.0.0",
+        "error-ex": "^1.3.1",
+        "json-parse-even-better-errors": "^2.3.0",
+        "lines-and-columns": "^1.1.6"
       }
     },
     "path-exists": {
@@ -1725,15 +1710,19 @@
       "dev": true
     },
     "path-parse": {
-      "version": "1.0.6",
-      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
-      "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw=="
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+      "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
     },
     "path-type": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
-      "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
-      "dev": true
+      "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="
+    },
+    "picocolors": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
+      "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
     },
     "picomatch": {
       "version": "2.2.2",
@@ -1741,51 +1730,13 @@
       "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg=="
     },
     "postcss": {
-      "version": "8.3.0",
-      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.0.tgz",
-      "integrity": "sha512-+ogXpdAjWGa+fdYY5BQ96V/6tAo+TdSSIMP5huJBIygdWwKtVoB5JWZ7yUd4xZ8r+8Kvvx4nyg/PQ071H4UtcQ==",
-      "requires": {
-        "colorette": "^1.2.2",
-        "nanoid": "^3.1.23",
-        "source-map-js": "^0.6.2"
-      }
-    },
-    "postcss-functions": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/postcss-functions/-/postcss-functions-3.0.0.tgz",
-      "integrity": "sha1-DpTQFERwCkgd4g3k1V+yZAVkJQ4=",
+      "version": "8.4.4",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.4.tgz",
+      "integrity": "sha512-joU6fBsN6EIer28Lj6GDFoC/5yOZzLCfn0zHAn/MYXI7aPt4m4hK5KC5ovEZXy+lnCjmYIbQWngvju2ddyEr8Q==",
       "requires": {
-        "glob": "^7.1.2",
-        "object-assign": "^4.1.1",
-        "postcss": "^6.0.9",
-        "postcss-value-parser": "^3.3.0"
-      },
-      "dependencies": {
-        "chalk": {
-          "version": "2.4.2",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
-          "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
-          "requires": {
-            "ansi-styles": "^3.2.1",
-            "escape-string-regexp": "^1.0.5",
-            "supports-color": "^5.3.0"
-          }
-        },
-        "postcss": {
-          "version": "6.0.23",
-          "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
-          "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==",
-          "requires": {
-            "chalk": "^2.4.1",
-            "source-map": "^0.6.1",
-            "supports-color": "^5.4.0"
-          }
-        },
-        "postcss-value-parser": {
-          "version": "3.3.1",
-          "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
-          "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ=="
-        }
+        "nanoid": "^3.1.30",
+        "picocolors": "^1.0.0",
+        "source-map-js": "^1.0.1"
       }
     },
     "postcss-js": {
@@ -1797,27 +1748,37 @@
         "postcss": "^8.1.6"
       }
     },
+    "postcss-load-config": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.0.tgz",
+      "integrity": "sha512-ipM8Ds01ZUophjDTQYSVP70slFSYg3T0/zyfII5vzhN6V57YSxMgG5syXuwi5VtS8wSf3iL30v0uBdoIVx4Q0g==",
+      "requires": {
+        "import-cwd": "^3.0.0",
+        "lilconfig": "^2.0.3",
+        "yaml": "^1.10.2"
+      }
+    },
     "postcss-nested": {
-      "version": "5.0.5",
-      "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-5.0.5.tgz",
-      "integrity": "sha512-GSRXYz5bccobpTzLQZXOnSOfKl6TwVr5CyAQJUPub4nuRJSOECK5AqurxVgmtxP48p0Kc/ndY/YyS1yqldX0Ew==",
+      "version": "5.0.6",
+      "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-5.0.6.tgz",
+      "integrity": "sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==",
       "requires": {
-        "postcss-selector-parser": "^6.0.4"
+        "postcss-selector-parser": "^6.0.6"
       }
     },
     "postcss-selector-parser": {
-      "version": "6.0.6",
-      "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz",
-      "integrity": "sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg==",
+      "version": "6.0.7",
+      "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.7.tgz",
+      "integrity": "sha512-U+b/Deoi4I/UmE6KOVPpnhS7I7AYdKbhGcat+qTQ27gycvaACvNEw11ba6RrkwVmDVRW7sigWgLj4/KbbJjeDA==",
       "requires": {
         "cssesc": "^3.0.0",
         "util-deprecate": "^1.0.2"
       }
     },
     "postcss-value-parser": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz",
-      "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ=="
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
+      "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
     },
     "prelude-ls": {
       "version": "1.2.1",
@@ -1825,11 +1786,6 @@
       "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
       "dev": true
     },
-    "pretty-hrtime": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz",
-      "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE="
-    },
     "progress": {
       "version": "2.0.3",
       "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
@@ -1842,17 +1798,6 @@
       "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
       "dev": true
     },
-    "purgecss": {
-      "version": "3.1.3",
-      "resolved": "https://registry.npmjs.org/purgecss/-/purgecss-3.1.3.tgz",
-      "integrity": "sha512-hRSLN9mguJ2lzlIQtW4qmPS2kh6oMnA9RxdIYK8sz18QYqd6ePp4GNDl18oWHA1f2v2NEQIh51CO8s/E3YGckQ==",
-      "requires": {
-        "commander": "^6.0.0",
-        "glob": "^7.0.0",
-        "postcss": "^8.2.1",
-        "postcss-selector-parser": "^6.0.2"
-      }
-    },
     "queue-microtask": {
       "version": "1.2.3",
       "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@@ -1872,22 +1817,6 @@
         "picomatch": "^2.0.4"
       }
     },
-    "reduce-css-calc": {
-      "version": "2.1.8",
-      "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-2.1.8.tgz",
-      "integrity": "sha512-8liAVezDmUcH+tdzoEGrhfbGcP7nOV4NkGE3a74+qqvE7nt9i4sKLGBuZNOnpI4WiGksiNPklZxva80061QiPg==",
-      "requires": {
-        "css-unit-converter": "^1.1.1",
-        "postcss-value-parser": "^3.3.0"
-      },
-      "dependencies": {
-        "postcss-value-parser": {
-          "version": "3.3.1",
-          "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
-          "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ=="
-        }
-      }
-    },
     "regexpp": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz",
@@ -1924,8 +1853,7 @@
     "resolve-from": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
-      "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
-      "dev": true
+      "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="
     },
     "reusify": {
       "version": "1.0.4",
@@ -1936,7 +1864,6 @@
       "version": "3.0.2",
       "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
       "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
-      "dev": true,
       "requires": {
         "glob": "^7.1.3"
       }
@@ -1979,14 +1906,6 @@
       "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
       "dev": true
     },
-    "simple-swizzle": {
-      "version": "0.2.2",
-      "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
-      "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=",
-      "requires": {
-        "is-arrayish": "^0.3.1"
-      }
-    },
     "slash": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
@@ -2030,15 +1949,10 @@
         }
       }
     },
-    "source-map": {
-      "version": "0.6.1",
-      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
-    },
     "source-map-js": {
-      "version": "0.6.2",
-      "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-0.6.2.tgz",
-      "integrity": "sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug=="
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.1.tgz",
+      "integrity": "sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA=="
     },
     "sprintf-js": {
       "version": "1.0.3",
@@ -2133,52 +2047,117 @@
       }
     },
     "tailwindcss": {
-      "version": "2.1.2",
-      "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-2.1.2.tgz",
-      "integrity": "sha512-T5t+wwd+/hsOyRw2HJuFuv0LTUm3MUdHm2DJ94GPVgzqwPPFa9XxX0KlwLWupUuiOUj6uiKURCzYPHFcuPch/w==",
-      "requires": {
-        "@fullhuman/postcss-purgecss": "^3.1.3",
-        "bytes": "^3.0.0",
-        "chalk": "^4.1.0",
-        "chokidar": "^3.5.1",
-        "color": "^3.1.3",
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.0.0.tgz",
+      "integrity": "sha512-UPAp2PS5vojAvGClJFIkdh2hfFyaSWo09Ma9j2vZYW+ANhTvpUHFjY85JgtrvvXXREtDvOXy2BxW1yHOz8apCg==",
+      "requires": {
+        "arg": "^5.0.1",
+        "chalk": "^4.1.2",
+        "chokidar": "^3.5.2",
+        "color-name": "^1.1.4",
+        "cosmiconfig": "^7.0.1",
         "detective": "^5.2.0",
-        "didyoumean": "^1.2.1",
+        "didyoumean": "^1.2.2",
         "dlv": "^1.1.3",
-        "fast-glob": "^3.2.5",
-        "fs-extra": "^9.1.0",
-        "html-tags": "^3.1.0",
-        "lodash": "^4.17.21",
-        "lodash.topath": "^4.5.2",
-        "modern-normalize": "^1.0.0",
-        "node-emoji": "^1.8.1",
+        "fast-glob": "^3.2.7",
+        "glob-parent": "^6.0.2",
+        "is-glob": "^4.0.3",
         "normalize-path": "^3.0.0",
-        "object-hash": "^2.1.1",
-        "parse-glob": "^3.0.4",
-        "postcss-functions": "^3",
+        "object-hash": "^2.2.0",
         "postcss-js": "^3.0.3",
-        "postcss-nested": "5.0.5",
-        "postcss-selector-parser": "^6.0.4",
-        "postcss-value-parser": "^4.1.0",
-        "pretty-hrtime": "^1.0.3",
+        "postcss-load-config": "^3.1.0",
+        "postcss-nested": "5.0.6",
+        "postcss-selector-parser": "^6.0.6",
+        "postcss-value-parser": "^4.2.0",
         "quick-lru": "^5.1.1",
-        "reduce-css-calc": "^2.1.8",
-        "resolve": "^1.20.0"
+        "resolve": "^1.20.0",
+        "tmp": "^0.2.1"
       },
       "dependencies": {
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "anymatch": {
+          "version": "3.1.2",
+          "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
+          "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
+          "requires": {
+            "normalize-path": "^3.0.0",
+            "picomatch": "^2.0.4"
+          }
+        },
+        "chalk": {
+          "version": "4.1.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
         "chokidar": {
-          "version": "3.5.1",
-          "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz",
-          "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==",
+          "version": "3.5.2",
+          "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz",
+          "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==",
           "requires": {
-            "anymatch": "~3.1.1",
+            "anymatch": "~3.1.2",
             "braces": "~3.0.2",
-            "fsevents": "~2.3.1",
-            "glob-parent": "~5.1.0",
+            "fsevents": "~2.3.2",
+            "glob-parent": "~5.1.2",
             "is-binary-path": "~2.1.0",
             "is-glob": "~4.0.1",
             "normalize-path": "~3.0.0",
-            "readdirp": "~3.5.0"
+            "readdirp": "~3.6.0"
+          },
+          "dependencies": {
+            "glob-parent": {
+              "version": "5.1.2",
+              "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+              "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+              "requires": {
+                "is-glob": "^4.0.1"
+              }
+            }
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+        },
+        "fast-glob": {
+          "version": "3.2.7",
+          "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz",
+          "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==",
+          "requires": {
+            "@nodelib/fs.stat": "^2.0.2",
+            "@nodelib/fs.walk": "^1.2.3",
+            "glob-parent": "^5.1.2",
+            "merge2": "^1.3.0",
+            "micromatch": "^4.0.4"
+          },
+          "dependencies": {
+            "glob-parent": {
+              "version": "5.1.2",
+              "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+              "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+              "requires": {
+                "is-glob": "^4.0.1"
+              }
+            }
           }
         },
         "fsevents": {
@@ -2187,13 +2166,42 @@
           "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
           "optional": true
         },
+        "glob-parent": {
+          "version": "6.0.2",
+          "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+          "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+          "requires": {
+            "is-glob": "^4.0.3"
+          }
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
+        },
+        "is-glob": {
+          "version": "4.0.3",
+          "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+          "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+          "requires": {
+            "is-extglob": "^2.1.1"
+          }
+        },
         "readdirp": {
-          "version": "3.5.0",
-          "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz",
-          "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==",
+          "version": "3.6.0",
+          "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+          "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
           "requires": {
             "picomatch": "^2.2.1"
           }
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
         }
       }
     },
@@ -2203,6 +2211,14 @@
       "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
       "dev": true
     },
+    "tmp": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
+      "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==",
+      "requires": {
+        "rimraf": "^3.0.0"
+      }
+    },
     "to-regex-range": {
       "version": "5.0.1",
       "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@@ -2259,11 +2275,6 @@
         "which-boxed-primitive": "^1.0.1"
       }
     },
-    "universalify": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
-      "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ=="
-    },
     "uri-js": {
       "version": "4.4.1",
       "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
@@ -2466,6 +2477,11 @@
       "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
       "dev": true
     },
+    "yaml": {
+      "version": "1.10.2",
+      "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
+      "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg=="
+    },
     "yargs": {
       "version": "13.3.2",
       "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz",
diff --git a/package.json b/package.json
index f461eb5..4f66744 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "eslint-plugin-tailwindcss",
-  "version": "1.17.2",
+  "version": "3.0.0",
   "description": "Rules enforcing best practices while using Tailwind CSS",
   "keywords": [
     "eslint",
@@ -25,14 +25,16 @@
   ],
   "dependencies": {
     "fast-glob": "^3.2.5",
-    "postcss": "^8.3.0",
-    "tailwindcss": "^2.1.2"
+    "postcss": "^8.4.4",
+    "tailwindcss": "^3.0.0"
   },
   "devDependencies": {
-    "@tailwindcss/aspect-ratio": "^0.2.0",
-    "@tailwindcss/line-clamp": "^0.2.0",
-    "@tailwindcss/typography": "^0.4.0",
+    "@tailwindcss/aspect-ratio": "^0.4.0",
+    "@tailwindcss/forms": "^0.4.0",
+    "@tailwindcss/line-clamp": "^0.3.0",
+    "@tailwindcss/typography": "^0.5.0",
     "@typescript-eslint/parser": "^4.33.0",
+    "autoprefixer": "^10.4.0",
     "eslint": "^7.1.0",
     "mocha": "^7.2.0",
     "typescript": "4.3.5",


Test patch:
diff --git a/tests/lib/rules/arbitrary-values.js b/tests/lib/rules/arbitrary-values.js
index 0f752f9..69ee1af 100644
--- a/tests/lib/rules/arbitrary-values.js
+++ b/tests/lib/rules/arbitrary-values.js
@@ -27,17 +27,7 @@ var parserOptions = {
 var config = [
   {
     config: {
-      mode: "jit",
-      theme: {
-        order: {
-          "-1": "-1",
-          0: "0",
-        },
-        zIndex: {
-          "-1": "-1",
-          0: "0",
-        },
-      },
+      darkMode: "class",
     },
   },
 ];
@@ -59,6 +49,24 @@ var ruleTester = new RuleTester({ parserOptions });
 
 ruleTester.run("arbitrary-values", rule, {
   valid: [
+    {
+      code: `
+      <div class="dark">
+        <span class="dark:text-white">
+          TailwindCSS V3: dark is valid when
+          <code>config.darkMode === 'class'</code>
+        </span>
+      </div>
+      `,
+      options: config,
+    },
+    {
+      code: `
+      <div class="aspect-[4/3]">
+        Aspect Ratio accepts arbitrary values
+      </div>
+      `,
+    },
     {
       code: `
       <div class="object-center object-[0%,10%] object-[10px,-66vh]">
@@ -69,20 +77,13 @@ ruleTester.run("arbitrary-values", rule, {
     },
     {
       code: `
-      <div class="top-[-325px] right-[50%] w-[762px] h-[0] flex-grow-[var(--some-grow)] flex-shrink-[12] z-[var(--some-z-index)]">
+      <div class="top-[-325px] right-[50%] w-[762px] h-[0] grow-[var(--some-grow)] shrink-[12] z-[var(--some-z-index)]">
         Should accept the arbitrary values
       </div>`,
-      options: [
-        {
-          config: {
-            mode: "jit",
-          },
-        },
-      ],
     },
     {
       code: `
-      <div class="z-0 -z-1 z-[auto] z-[inherit] z-[initial] z-[unset] z-[var(--some)] z-[2] z-[-3]">
+      <div class="z-0 -z-10 z-[auto] z-[inherit] z-[initial] z-[unset] z-[var(--some)] z-[2] z-[-3]">
         Arbitrary values for zIndex
       </div>
       `,
@@ -98,7 +99,7 @@ ruleTester.run("arbitrary-values", rule, {
     },
     {
       code: `
-      <div class="flex-shrink flex-shrink-0 flex-shrink-[inherit] flex-shrink-[initial] flex-shrink-[unset] flex-shrink-[var(--some)] flex-shrink-[0.5] flex-shrink-[5]">
+      <div class="shrink shrink-0 shrink-[inherit] shrink-[initial] shrink-[unset] shrink-[var(--some)] shrink-[0.5] shrink-[5]">
         Arbitrary values for positive integers
       </div>
       `,
@@ -106,7 +107,7 @@ ruleTester.run("arbitrary-values", rule, {
     },
     {
       code: `
-      <div class="order-0 -order-1 order-[inherit] order-[initial] order-[unset] order-[var(--some)] order-[calc(1+1)] order-[2] order-[-3]">
+      <div class="order-2 -order-1 order-[inherit] order-[initial] order-[unset] order-[var(--some)] order-[calc(1+1)] order-[2] order-[-3]">
         Arbitrary values for order
       </div>
       `,
@@ -114,7 +115,7 @@ ruleTester.run("arbitrary-values", rule, {
     },
     {
       code: `
-      <div class="placeholder-white placeholder-[#123456aB] placeholder-[#123456] placeholder-[#1234] placeholder-[#123]">
+      <div class="placeholder:text-white placeholder:text-[#123456aB] placeholder:text-[#123456] placeholder:text-[#1234] placeholder:text-[#123]">
         placeholderColor using #RGB
       </div>
       `,
@@ -122,7 +123,7 @@ ruleTester.run("arbitrary-values", rule, {
     },
     {
       code: `
-      <div class="placeholder-white placeholder-[rgb(4,8,15)] placeholder-[rgb(16%,23%,42%)] placeholder-[rgba(23,0,42,0.5)] placeholder-[rgba(10%,20%,30%,100%)] ">
+      <div class="placeholder:text-white placeholder:text-[rgb(4,8,15)] placeholder:text-[rgb(16%,23%,42%)] placeholder:text-[rgba(23,0,42,0.5)] placeholder:text-[rgba(10%,20%,30%,100%)] ">
         placeholderColor using rgb[a]()
       </div>
       `,
@@ -130,28 +131,12 @@ ruleTester.run("arbitrary-values", rule, {
     },
     {
       code: `
-      <div class="placeholder-white placeholder-[rgba(255,0,0/0.4)] placeholder-[rgba(255,0,0/.4)] placeholder-[rgba(255,0,0/40%)]">
-        placeholderColor using rgba(255 0 0 / 0.4)
-      </div>
-      `,
-      options: config,
-    },
-    {
-      code: `
-      <div class="placeholder-white placeholder-[hsl(120,100%,25%)]">
+      <div class="placeholder:text-white placeholder:text-[hsl(120,100%,25%)]">
         placeholderColor using hsl
       </div>
       `,
       options: config,
     },
-    {
-      code: `
-      <div class="placeholder-white placeholder-[var(--some)] placeholder-[color:var(--some)]">
-        placeholderColor using var
-      </div>
-      `,
-      options: config,
-    },
     {
       code: `
       <div class="text-white text-[#123456aB] text-[#123456] text-[#1234] text-[#123] text-[rgb(4,8,15)] text-[rgb(16%,23%,42%)] text-[rgba(23,0,42,0.5)] text-[hsl(120,100%,25%)] text-[color:var(--some)]">
@@ -162,7 +147,7 @@ ruleTester.run("arbitrary-values", rule, {
     },
     {
       code: `
-      <div class="bg-white/80 text-red-500/25 placeholder-black/50">
+      <div class="bg-white/80 text-red-500/25 placeholder:text-black/50">
         Color opacity shorthands
       </div>
       `,
@@ -317,7 +302,7 @@ ruleTester.run("arbitrary-values", rule, {
     },
     {
       code: `
-      <div class="h-20 w-20 bg-black transform rotate-3 rotate-[calc(15deg+5deg)] rotate-[var(--some)]">rotate</div>
+      <div class="h-20 w-20 bg-black rotate-3 rotate-[calc(15deg+5deg)] rotate-[var(--some)]">rotate</div>
       `,
       options: config,
     },
@@ -351,13 +336,6 @@ ruleTester.run("arbitrary-values", rule, {
         Arbitrary values for border-radius
       </div>
       `,
-      options: [
-        {
-          config: {
-            mode: "jit",
-          },
-        },
-      ],
     },
     {
       code: `
@@ -368,103 +346,103 @@ ruleTester.run("arbitrary-values", rule, {
     },
     {
       code: `
-      <button class="bg-[#00800034] filter blur-[4] blur-[1px] blur-[0.5ch] blur-[.1em] blur-[1ex] blur-[1lh] blur-[1rem] blur-[1rlh] blur-[2vh] blur-[2vw] blur-[2vmin] blur-[2vmax] blur-[3px] blur-[3mm] blur-[3cm] blur-[3in] blur-[3pt] blur-[3pc] blur-[3lin] blur-[3%] blur-[calc(50%+10px)]">valid blur</button>
+      <button class="bg-[#00800034] blur-[4] blur-[1px] blur-[0.5ch] blur-[.1em] blur-[1ex] blur-[1lh] blur-[1rem] blur-[1rlh] blur-[2vh] blur-[2vw] blur-[2vmin] blur-[2vmax] blur-[3px] blur-[3mm] blur-[3cm] blur-[3in] blur-[3pt] blur-[3pc] blur-[3lin] blur-[3%] blur-[calc(50%+10px)]">valid blur</button>
       `,
       options: config,
     },
     {
       code: `
-      <button class="bg-red-500 filter brightness-[4] brightness-[1px] brightness-[0.5ch] brightness-[.1em] brightness-[1ex] brightness-[1lh] brightness-[1rem] brightness-[1rlh] brightness-[2vh] brightness-[2vw] brightness-[2vmin] brightness-[2vmax] brightness-[3px] brightness-[3mm] brightness-[3cm] brightness-[3in] brightness-[3pt] brightness-[3pc] brightness-[3lin] brightness-[33.3%] brightness-[calc(50%+10px)]">valid brightness</button>
+      <button class="bg-red-500 brightness-[4] brightness-[1px] brightness-[0.5ch] brightness-[.1em] brightness-[1ex] brightness-[1lh] brightness-[1rem] brightness-[1rlh] brightness-[2vh] brightness-[2vw] brightness-[2vmin] brightness-[2vmax] brightness-[3px] brightness-[3mm] brightness-[3cm] brightness-[3in] brightness-[3pt] brightness-[3pc] brightness-[3lin] brightness-[33.3%] brightness-[calc(50%+10px)]">valid brightness</button>
       `,
       options: config,
     },
     {
       code: `
-      <button class="bg-red-500 filter contrast-[4] contrast-[1px] contrast-[0.5ch] contrast-[.1em] contrast-[1ex] contrast-[1lh] contrast-[1rem] contrast-[1rlh] contrast-[2vh] contrast-[2vw] contrast-[2vmin] contrast-[2vmax] contrast-[3px] contrast-[3mm] contrast-[3cm] contrast-[3in] contrast-[3pt] contrast-[3pc] contrast-[3lin] contrast-[33.3%] contrast-[calc(50%+10px)]">valid contrast</button>
+      <button class="bg-red-500 contrast-[4] contrast-[1px] contrast-[0.5ch] contrast-[.1em] contrast-[1ex] contrast-[1lh] contrast-[1rem] contrast-[1rlh] contrast-[2vh] contrast-[2vw] contrast-[2vmin] contrast-[2vmax] contrast-[3px] contrast-[3mm] contrast-[3cm] contrast-[3in] contrast-[3pt] contrast-[3pc] contrast-[3lin] contrast-[33.3%] contrast-[calc(50%+10px)]">valid contrast</button>
       `,
       options: config,
     },
     {
       code: `
-      <button class="bg-red-500 filter grayscale-[4] grayscale-[1px] grayscale-[0.5ch] grayscale-[.1em] grayscale-[1ex] grayscale-[1lh] grayscale-[1rem] grayscale-[1rlh] grayscale-[2vh] grayscale-[2vw] grayscale-[2vmin] grayscale-[2vmax] grayscale-[3px] grayscale-[3mm] grayscale-[3cm] grayscale-[3in] grayscale-[3pt] grayscale-[3pc] grayscale-[3lin] grayscale-[33.3%] grayscale-[calc(50%+10px)]">valid grayscale</button>
+      <button class="bg-red-500 grayscale-[4] grayscale-[1px] grayscale-[0.5ch] grayscale-[.1em] grayscale-[1ex] grayscale-[1lh] grayscale-[1rem] grayscale-[1rlh] grayscale-[2vh] grayscale-[2vw] grayscale-[2vmin] grayscale-[2vmax] grayscale-[3px] grayscale-[3mm] grayscale-[3cm] grayscale-[3in] grayscale-[3pt] grayscale-[3pc] grayscale-[3lin] grayscale-[33.3%] grayscale-[calc(50%+10px)]">valid grayscale</button>
       `,
       options: config,
     },
     {
       code: `
-      <button class="bg-red-500 filter hue-rotate-[4] hue-rotate-[1px] hue-rotate-[0.5ch] hue-rotate-[.1em] hue-rotate-[1ex] hue-rotate-[1lh] hue-rotate-[1rem] hue-rotate-[1rlh] hue-rotate-[2vh] hue-rotate-[2vw] hue-rotate-[2vmin] hue-rotate-[2vmax] hue-rotate-[3px] hue-rotate-[3mm] hue-rotate-[3cm] hue-rotate-[3in] hue-rotate-[3pt] hue-rotate-[3pc] hue-rotate-[3lin] hue-rotate-[33.3%] hue-rotate-[calc(50%+10px)]">valid hue-rotate</button>
+      <button class="bg-red-500 hue-rotate-[4] hue-rotate-[1px] hue-rotate-[0.5ch] hue-rotate-[.1em] hue-rotate-[1ex] hue-rotate-[1lh] hue-rotate-[1rem] hue-rotate-[1rlh] hue-rotate-[2vh] hue-rotate-[2vw] hue-rotate-[2vmin] hue-rotate-[2vmax] hue-rotate-[3px] hue-rotate-[3mm] hue-rotate-[3cm] hue-rotate-[3in] hue-rotate-[3pt] hue-rotate-[3pc] hue-rotate-[3lin] hue-rotate-[33.3%] hue-rotate-[calc(50%+10px)]">valid hue-rotate</button>
       `,
       options: config,
     },
     {
       code: `
-      <button class="bg-red-500 filter invert-[4] invert-[1px] invert-[0.5ch] invert-[.1em] invert-[1ex] invert-[1lh] invert-[1rem] invert-[1rlh] invert-[2vh] invert-[2vw] invert-[2vmin] invert-[2vmax] invert-[3px] invert-[3mm] invert-[3cm] invert-[3in] invert-[3pt] invert-[3pc] invert-[3lin] invert-[33.3%] invert-[calc(50%+10px)]">valid invert</button>
+      <button class="bg-red-500 invert-[4] invert-[1px] invert-[0.5ch] invert-[.1em] invert-[1ex] invert-[1lh] invert-[1rem] invert-[1rlh] invert-[2vh] invert-[2vw] invert-[2vmin] invert-[2vmax] invert-[3px] invert-[3mm] invert-[3cm] invert-[3in] invert-[3pt] invert-[3pc] invert-[3lin] invert-[33.3%] invert-[calc(50%+10px)]">valid invert</button>
       `,
       options: config,
     },
     {
       code: `
-      <button class="bg-red-500 filter saturate-[4] saturate-[1px] saturate-[0.5ch] saturate-[.1em] saturate-[1ex] saturate-[1lh] saturate-[1rem] saturate-[1rlh] saturate-[2vh] saturate-[2vw] saturate-[2vmin] saturate-[2vmax] saturate-[3px] saturate-[3mm] saturate-[3cm] saturate-[3in] saturate-[3pt] saturate-[3pc] saturate-[3lin] saturate-[33.3%] saturate-[calc(50%+10px)]">valid saturate</button>
+      <button class="bg-red-500 saturate-[4] saturate-[1px] saturate-[0.5ch] saturate-[.1em] saturate-[1ex] saturate-[1lh] saturate-[1rem] saturate-[1rlh] saturate-[2vh] saturate-[2vw] saturate-[2vmin] saturate-[2vmax] saturate-[3px] saturate-[3mm] saturate-[3cm] saturate-[3in] saturate-[3pt] saturate-[3pc] saturate-[3lin] saturate-[33.3%] saturate-[calc(50%+10px)]">valid saturate</button>
       `,
       options: config,
     },
     {
       code: `
-      <button class="bg-red-500 filter sepia-[4] sepia-[1px] sepia-[0.5ch] sepia-[.1em] sepia-[1ex] sepia-[1lh] sepia-[1rem] sepia-[1rlh] sepia-[2vh] sepia-[2vw] sepia-[2vmin] sepia-[2vmax] sepia-[3px] sepia-[3mm] sepia-[3cm] sepia-[3in] sepia-[3pt] sepia-[3pc] sepia-[3lin] sepia-[33.3%] sepia-[calc(50%+10px)]">valid sepia</button>
+      <button class="bg-red-500 sepia-[4] sepia-[1px] sepia-[0.5ch] sepia-[.1em] sepia-[1ex] sepia-[1lh] sepia-[1rem] sepia-[1rlh] sepia-[2vh] sepia-[2vw] sepia-[2vmin] sepia-[2vmax] sepia-[3px] sepia-[3mm] sepia-[3cm] sepia-[3in] sepia-[3pt] sepia-[3pc] sepia-[3lin] sepia-[33.3%] sepia-[calc(50%+10px)]">valid sepia</button>
       `,
       options: config,
     },
     {
       code: `
-      <button class="bg-red-500 backdrop-filter backdrop-blur-[4] backdrop-blur-[1px] backdrop-blur-[0.5ch] backdrop-blur-[.1em] backdrop-blur-[1ex] backdrop-blur-[1lh] backdrop-blur-[1rem] backdrop-blur-[1rlh] backdrop-blur-[2vh] backdrop-blur-[2vw] backdrop-blur-[2vmin] backdrop-blur-[2vmax] backdrop-blur-[3px] backdrop-blur-[3mm] backdrop-blur-[3cm] backdrop-blur-[3in] backdrop-blur-[3pt] backdrop-blur-[3pc] backdrop-blur-[3lin] backdrop-blur-[33.3%] backdrop-blur-[calc(50%+10px)]">valid backdrop-blur</button>
+      <button class="bg-red-500 backdrop-blur-[4] backdrop-blur-[1px] backdrop-blur-[0.5ch] backdrop-blur-[.1em] backdrop-blur-[1ex] backdrop-blur-[1lh] backdrop-blur-[1rem] backdrop-blur-[1rlh] backdrop-blur-[2vh] backdrop-blur-[2vw] backdrop-blur-[2vmin] backdrop-blur-[2vmax] backdrop-blur-[3px] backdrop-blur-[3mm] backdrop-blur-[3cm] backdrop-blur-[3in] backdrop-blur-[3pt] backdrop-blur-[3pc] backdrop-blur-[3lin] backdrop-blur-[33.3%] backdrop-blur-[calc(50%+10px)]">valid backdrop-blur</button>
       `,
       options: config,
     },
     {
       code: `
-      <button class="bg-red-500 backdrop-filter backdrop-brightness-[4] backdrop-brightness-[1px] backdrop-brightness-[0.5ch] backdrop-brightness-[.1em] backdrop-brightness-[1ex] backdrop-brightness-[1lh] backdrop-brightness-[1rem] backdrop-brightness-[1rlh] backdrop-brightness-[2vh] backdrop-brightness-[2vw] backdrop-brightness-[2vmin] backdrop-brightness-[2vmax] backdrop-brightness-[3px] backdrop-brightness-[3mm] backdrop-brightness-[3cm] backdrop-brightness-[3in] backdrop-brightness-[3pt] backdrop-brightness-[3pc] backdrop-brightness-[3lin] backdrop-brightness-[33.3%] backdrop-brightness-[calc(50%+10px)]">valid backdrop-brightness</button>
+      <button class="bg-red-500 backdrop-brightness-[4] backdrop-brightness-[1px] backdrop-brightness-[0.5ch] backdrop-brightness-[.1em] backdrop-brightness-[1ex] backdrop-brightness-[1lh] backdrop-brightness-[1rem] backdrop-brightness-[1rlh] backdrop-brightness-[2vh] backdrop-brightness-[2vw] backdrop-brightness-[2vmin] backdrop-brightness-[2vmax] backdrop-brightness-[3px] backdrop-brightness-[3mm] backdrop-brightness-[3cm] backdrop-brightness-[3in] backdrop-brightness-[3pt] backdrop-brightness-[3pc] backdrop-brightness-[3lin] backdrop-brightness-[33.3%] backdrop-brightness-[calc(50%+10px)]">valid backdrop-brightness</button>
       `,
       options: config,
     },
     {
       code: `
-      <button class="bg-red-500 backdrop-filter backdrop-contrast-[4] backdrop-contrast-[1px] backdrop-contrast-[0.5ch] backdrop-contrast-[.1em] backdrop-contrast-[1ex] backdrop-contrast-[1lh] backdrop-contrast-[1rem] backdrop-contrast-[1rlh] backdrop-contrast-[2vh] backdrop-contrast-[2vw] backdrop-contrast-[2vmin] backdrop-contrast-[2vmax] backdrop-contrast-[3px] backdrop-contrast-[3mm] backdrop-contrast-[3cm] backdrop-contrast-[3in] backdrop-contrast-[3pt] backdrop-contrast-[3pc] backdrop-contrast-[3lin] backdrop-contrast-[33.3%] backdrop-contrast-[calc(50%+10px)]">valid backdrop-contrast</button>
+      <button class="bg-red-500 backdrop-contrast-[4] backdrop-contrast-[1px] backdrop-contrast-[0.5ch] backdrop-contrast-[.1em] backdrop-contrast-[1ex] backdrop-contrast-[1lh] backdrop-contrast-[1rem] backdrop-contrast-[1rlh] backdrop-contrast-[2vh] backdrop-contrast-[2vw] backdrop-contrast-[2vmin] backdrop-contrast-[2vmax] backdrop-contrast-[3px] backdrop-contrast-[3mm] backdrop-contrast-[3cm] backdrop-contrast-[3in] backdrop-contrast-[3pt] backdrop-contrast-[3pc] backdrop-contrast-[3lin] backdrop-contrast-[33.3%] backdrop-contrast-[calc(50%+10px)]">valid backdrop-contrast</button>
       `,
       options: config,
     },
     {
       code: `
-      <button class="bg-red-500 backdrop-filter backdrop-grayscale-[4] backdrop-grayscale-[1px] backdrop-grayscale-[0.5ch] backdrop-grayscale-[.1em] backdrop-grayscale-[1ex] backdrop-grayscale-[1lh] backdrop-grayscale-[1rem] backdrop-grayscale-[1rlh] backdrop-grayscale-[2vh] backdrop-grayscale-[2vw] backdrop-grayscale-[2vmin] backdrop-grayscale-[2vmax] backdrop-grayscale-[3px] backdrop-grayscale-[3mm] backdrop-grayscale-[3cm] backdrop-grayscale-[3in] backdrop-grayscale-[3pt] backdrop-grayscale-[3pc] backdrop-grayscale-[3lin] backdrop-grayscale-[33.3%] backdrop-grayscale-[calc(50%+10px)]">valid backdrop-grayscale</button>
+      <button class="bg-red-500 backdrop-grayscale-[4] backdrop-grayscale-[1px] backdrop-grayscale-[0.5ch] backdrop-grayscale-[.1em] backdrop-grayscale-[1ex] backdrop-grayscale-[1lh] backdrop-grayscale-[1rem] backdrop-grayscale-[1rlh] backdrop-grayscale-[2vh] backdrop-grayscale-[2vw] backdrop-grayscale-[2vmin] backdrop-grayscale-[2vmax] backdrop-grayscale-[3px] backdrop-grayscale-[3mm] backdrop-grayscale-[3cm] backdrop-grayscale-[3in] backdrop-grayscale-[3pt] backdrop-grayscale-[3pc] backdrop-grayscale-[3lin] backdrop-grayscale-[33.3%] backdrop-grayscale-[calc(50%+10px)]">valid backdrop-grayscale</button>
       `,
       options: config,
     },
     {
       code: `
-      <button class="bg-red-500 backdrop-filter backdrop-hue-rotate-[4] backdrop-hue-rotate-[1px] backdrop-hue-rotate-[0.5ch] backdrop-hue-rotate-[.1em] backdrop-hue-rotate-[1ex] backdrop-hue-rotate-[1lh] backdrop-hue-rotate-[1rem] backdrop-hue-rotate-[1rlh] backdrop-hue-rotate-[2vh] backdrop-hue-rotate-[2vw] backdrop-hue-rotate-[2vmin] backdrop-hue-rotate-[2vmax] backdrop-hue-rotate-[3px] backdrop-hue-rotate-[3mm] backdrop-hue-rotate-[3cm] backdrop-hue-rotate-[3in] backdrop-hue-rotate-[3pt] backdrop-hue-rotate-[3pc] backdrop-hue-rotate-[3lin] backdrop-hue-rotate-[33.3%] backdrop-hue-rotate-[calc(50%+10px)]">valid backdrop-hue-rotate</button>
+      <button class="bg-red-500 backdrop-hue-rotate-[4] backdrop-hue-rotate-[1px] backdrop-hue-rotate-[0.5ch] backdrop-hue-rotate-[.1em] backdrop-hue-rotate-[1ex] backdrop-hue-rotate-[1lh] backdrop-hue-rotate-[1rem] backdrop-hue-rotate-[1rlh] backdrop-hue-rotate-[2vh] backdrop-hue-rotate-[2vw] backdrop-hue-rotate-[2vmin] backdrop-hue-rotate-[2vmax] backdrop-hue-rotate-[3px] backdrop-hue-rotate-[3mm] backdrop-hue-rotate-[3cm] backdrop-hue-rotate-[3in] backdrop-hue-rotate-[3pt] backdrop-hue-rotate-[3pc] backdrop-hue-rotate-[3lin] backdrop-hue-rotate-[33.3%] backdrop-hue-rotate-[calc(50%+10px)]">valid backdrop-hue-rotate</button>
       `,
       options: config,
     },
     {
       code: `
-      <button class="bg-red-500 backdrop-filter backdrop-invert-[4] backdrop-invert-[1px] backdrop-invert-[0.5ch] backdrop-invert-[.1em] backdrop-invert-[1ex] backdrop-invert-[1lh] backdrop-invert-[1rem] backdrop-invert-[1rlh] backdrop-invert-[2vh] backdrop-invert-[2vw] backdrop-invert-[2vmin] backdrop-invert-[2vmax] backdrop-invert-[3px] backdrop-invert-[3mm] backdrop-invert-[3cm] backdrop-invert-[3in] backdrop-invert-[3pt] backdrop-invert-[3pc] backdrop-invert-[3lin] backdrop-invert-[33.3%] backdrop-invert-[calc(50%+10px)]">valid backdrop-invert</button>
+      <button class="bg-red-500 backdrop-invert-[4] backdrop-invert-[1px] backdrop-invert-[0.5ch] backdrop-invert-[.1em] backdrop-invert-[1ex] backdrop-invert-[1lh] backdrop-invert-[1rem] backdrop-invert-[1rlh] backdrop-invert-[2vh] backdrop-invert-[2vw] backdrop-invert-[2vmin] backdrop-invert-[2vmax] backdrop-invert-[3px] backdrop-invert-[3mm] backdrop-invert-[3cm] backdrop-invert-[3in] backdrop-invert-[3pt] backdrop-invert-[3pc] backdrop-invert-[3lin] backdrop-invert-[33.3%] backdrop-invert-[calc(50%+10px)]">valid backdrop-invert</button>
       `,
       options: config,
     },
     {
       code: `
-      <button class="bg-red-500 backdrop-filter backdrop-opacity-[4] backdrop-opacity-[1px] backdrop-opacity-[0.5ch] backdrop-opacity-[.1em] backdrop-opacity-[1ex] backdrop-opacity-[1lh] backdrop-opacity-[1rem] backdrop-opacity-[1rlh] backdrop-opacity-[2vh] backdrop-opacity-[2vw] backdrop-opacity-[2vmin] backdrop-opacity-[2vmax] backdrop-opacity-[3px] backdrop-opacity-[3mm] backdrop-opacity-[3cm] backdrop-opacity-[3in] backdrop-opacity-[3pt] backdrop-opacity-[3pc] backdrop-opacity-[3lin] backdrop-opacity-[33.3%] backdrop-opacity-[calc(50%+10px)]">valid backdrop-opacity</button>
+      <button class="bg-red-500 backdrop-opacity-[4] backdrop-opacity-[1px] backdrop-opacity-[0.5ch] backdrop-opacity-[.1em] backdrop-opacity-[1ex] backdrop-opacity-[1lh] backdrop-opacity-[1rem] backdrop-opacity-[1rlh] backdrop-opacity-[2vh] backdrop-opacity-[2vw] backdrop-opacity-[2vmin] backdrop-opacity-[2vmax] backdrop-opacity-[3px] backdrop-opacity-[3mm] backdrop-opacity-[3cm] backdrop-opacity-[3in] backdrop-opacity-[3pt] backdrop-opacity-[3pc] backdrop-opacity-[3lin] backdrop-opacity-[33.3%] backdrop-opacity-[calc(50%+10px)]">valid backdrop-opacity</button>
       `,
       options: config,
     },
     {
       code: `
-      <button class="bg-red-500 backdrop-filter backdrop-saturate-[4] backdrop-saturate-[1px] backdrop-saturate-[0.5ch] backdrop-saturate-[.1em] backdrop-saturate-[1ex] backdrop-saturate-[1lh] backdrop-saturate-[1rem] backdrop-saturate-[1rlh] backdrop-saturate-[2vh] backdrop-saturate-[2vw] backdrop-saturate-[2vmin] backdrop-saturate-[2vmax] backdrop-saturate-[3px] backdrop-saturate-[3mm] backdrop-saturate-[3cm] backdrop-saturate-[3in] backdrop-saturate-[3pt] backdrop-saturate-[3pc] backdrop-saturate-[3lin] backdrop-saturate-[33.3%] backdrop-saturate-[calc(50%+10px)]">valid backdrop-saturate</button>
+      <button class="bg-red-500 backdrop-saturate-[4] backdrop-saturate-[1px] backdrop-saturate-[0.5ch] backdrop-saturate-[.1em] backdrop-saturate-[1ex] backdrop-saturate-[1lh] backdrop-saturate-[1rem] backdrop-saturate-[1rlh] backdrop-saturate-[2vh] backdrop-saturate-[2vw] backdrop-saturate-[2vmin] backdrop-saturate-[2vmax] backdrop-saturate-[3px] backdrop-saturate-[3mm] backdrop-saturate-[3cm] backdrop-saturate-[3in] backdrop-saturate-[3pt] backdrop-saturate-[3pc] backdrop-saturate-[3lin] backdrop-saturate-[33.3%] backdrop-saturate-[calc(50%+10px)]">valid backdrop-saturate</button>
       `,
       options: config,
     },
     {
       code: `
-      <button class="bg-red-500 backdrop-filter backdrop-sepia-[4] backdrop-sepia-[1px] backdrop-sepia-[0.5ch] backdrop-sepia-[.1em] backdrop-sepia-[1ex] backdrop-sepia-[1lh] backdrop-sepia-[1rem] backdrop-sepia-[1rlh] backdrop-sepia-[2vh] backdrop-sepia-[2vw] backdrop-sepia-[2vmin] backdrop-sepia-[2vmax] backdrop-sepia-[3px] backdrop-sepia-[3mm] backdrop-sepia-[3cm] backdrop-sepia-[3in] backdrop-sepia-[3pt] backdrop-sepia-[3pc] backdrop-sepia-[3lin] backdrop-sepia-[33.3%] backdrop-sepia-[calc(50%+10px)]">valid backdrop-sepia</button>
+      <button class="bg-red-500 backdrop-sepia-[4] backdrop-sepia-[1px] backdrop-sepia-[0.5ch] backdrop-sepia-[.1em] backdrop-sepia-[1ex] backdrop-sepia-[1lh] backdrop-sepia-[1rem] backdrop-sepia-[1rlh] backdrop-sepia-[2vh] backdrop-sepia-[2vw] backdrop-sepia-[2vmin] backdrop-sepia-[2vmax] backdrop-sepia-[3px] backdrop-sepia-[3mm] backdrop-sepia-[3cm] backdrop-sepia-[3in] backdrop-sepia-[3pt] backdrop-sepia-[3pc] backdrop-sepia-[3lin] backdrop-sepia-[33.3%] backdrop-sepia-[calc(50%+10px)]">valid backdrop-sepia</button>
       `,
       options: config,
     },
@@ -494,31 +472,31 @@ ruleTester.run("arbitrary-values", rule, {
     },
     {
       code: `
-      <div class="transform rotate-45 h-20 w-20 bg-green-600 origin-top-left origin-[var(--some)] origin-[20%] origin-[90%,90%]">origin</div>
+      <div class="rotate-45 h-20 w-20 bg-green-600 origin-top-left origin-[var(--some)] origin-[20%] origin-[90%,90%]">origin</div>
       `,
       options: config,
     },
     {
       code: `
-      <div class="transform scale-50 scale-0 scale-[90%] scale-[5]">scale</div>
+      <div class="scale-50 scale-0 scale-[90%] scale-[5]">scale</div>
       `,
       options: config,
     },
     {
       code: `
-      <div class="transform scale-50 scale-0 scale-[90%] scale-[5]">scale</div>
+      <div class="scale-50 scale-0 scale-[90%] scale-[5]">scale</div>
       `,
       options: config,
     },
     {
       code: `
-      <div class="transform translate-y-6 translate-y-[10px] translate-y-[-10px] translate-y-[1%]">translate</div>
+      <div class="translate-y-6 translate-y-[10px] translate-y-[-10px] translate-y-[1%]">translate</div>
       `,
       options: config,
     },
     {
       code: `
-      <div class="transform skew-y-6 skew-y-[10px] skew-y-[-10px] skew-y-[1%]">skew</div>
+      <div class="skew-y-6 skew-y-[10px] skew-y-[-10px] skew-y-[1%]">skew</div>
       `,
       options: config,
     },
@@ -530,7 +508,7 @@ ruleTester.run("arbitrary-values", rule, {
     },
     {
       code: `
-      <button class="outline-black outline-['2px,solid,red'] outline-[var(--some)]">outline</button>
+      <button class="outline-black">outline</button>
       `,
       options: config,
     },
@@ -557,6 +535,45 @@ ruleTester.run("arbitrary-values", rule, {
   ],
 
   invalid: [
+    {
+      code: `
+      <div class="dark">
+        <span class="dark:text-white">
+          TailwindCSS V3: dark is not valid unless
+          <code>config.darkMode === 'class'</code>
+        </span>
+      </div>
+      `,
+      errors: generateErrors("dark"),
+    },
+    {
+      code: `
+      <div class="aspect-ko">
+        Aspect Ratio
+      </div>
+      `,
+      errors: generateErrors("aspect-ko"),
+    },
+    {
+      code: `
+      <div class="placeholder:text-white placeholder:text-[var(--some)] placeholder:text-[color:var(--some)]">
+        placeholderColor using var
+      </div>
+      `,
+      options: config,
+      errors: generateErrors("placeholder:text-[var(--some)]"),
+    },
+    {
+      code: `
+      <div class="placeholder:text-white placeholder:text-[rgba(255,0,0/0.4)] placeholder:text-[rgba(255,0,0/.4)] placeholder:text-[rgba(255,0,0/40%)]">
+        placeholderColor using rgba(255 0 0 / 0.4)
+      </div>
+      `,
+      options: config,
+      errors: generateErrors(
+        "placeholder:text-[rgba(255,0,0/0.4)] placeholder:text-[rgba(255,0,0/.4)] placeholder:text-[rgba(255,0,0/40%)]"
+      ),
+    },
     {
       code: `
       <div class="bg-[var(--donno)]">
@@ -577,12 +594,12 @@ ruleTester.run("arbitrary-values", rule, {
     },
     {
       code: `
-      <div class="placeholder-[hsla(240,100%,50%,0.7]">
+      <div class="placeholder:text-[hsla(240,100%,50%,0.7]">
         Unsupported placeholderColor using hsla
       </div>
       `,
       options: config,
-      errors: generateErrors("placeholder-[hsla(240,100%,50%,0.7]"),
+      errors: generateErrors("placeholder:text-[hsla(240,100%,50%,0.7]"),
     },
     {
       code: `
@@ -592,7 +609,7 @@ ruleTester.run("arbitrary-values", rule, {
       `,
       options: config,
       errors: generateErrors(
-        "text-[rgba(10%,20%,30%,100%)] text-[rgba(255,0,0/0.4)] text-[rgba(255,0,0/.4)] text-[rgba(255,0,0/40%)] text-[var(--some)]"
+        "text-[rgba(255,0,0/0.4)] text-[rgba(255,0,0/.4)] text-[rgba(255,0,0/40%)] text-[var(--some)]"
       ),
     },
     {
@@ -790,7 +807,7 @@ ruleTester.run("arbitrary-values", rule, {
     },
     {
       code: `
-      <button class="filter brightness-[length:0] brightness-[length:thick] brightness-[length:var(--some)] brightness-[length:calc(50%+10px)]">Invalid brightness</button> 
+      <button class="brightness-[length:0] brightness-[length:thick] brightness-[length:var(--some)] brightness-[length:calc(50%+10px)]">Invalid brightness</button>
       `,
       options: config,
       errors: generateErrors(
@@ -799,7 +816,7 @@ ruleTester.run("arbitrary-values", rule, {
     },
     {
       code: `
-      <button class="filter contrast-[length:0] contrast-[length:thick] contrast-[length:var(--some)] contrast-[length:calc(50%+10px)]">Invalid contrast</button> 
+      <button class="contrast-[length:0] contrast-[length:thick] contrast-[length:var(--some)] contrast-[length:calc(50%+10px)]">Invalid contrast</button>
       `,
       options: config,
       errors: generateErrors(
@@ -808,7 +825,7 @@ ruleTester.run("arbitrary-values", rule, {
     },
     {
       code: `
-      <button class="filter grayscale-[length:0] grayscale-[length:thick] grayscale-[length:var(--some)] grayscale-[length:calc(50%+10px)]">Invalid grayscale</button> 
+      <button class="grayscale-[length:0] grayscale-[length:thick] grayscale-[length:var(--some)] grayscale-[length:calc(50%+10px)]">Invalid grayscale</button>
       `,
       options: config,
       errors: generateErrors(
@@ -817,7 +834,7 @@ ruleTester.run("arbitrary-values", rule, {
     },
     {
       code: `
-      <button class="filter hue-rotate-[length:0] hue-rotate-[length:thick] hue-rotate-[length:var(--some)] hue-rotate-[length:calc(50%+10px)]">Invalid hue-rotate</button> 
+      <button class="hue-rotate-[length:0] hue-rotate-[length:thick] hue-rotate-[length:var(--some)] hue-rotate-[length:calc(50%+10px)]">Invalid hue-rotate</button>
       `,
       options: config,
       errors: generateErrors(
@@ -826,7 +843,7 @@ ruleTester.run("arbitrary-values", rule, {
     },
     {
       code: `
-      <button class="filter invert-[length:0] invert-[length:thick] invert-[length:var(--some)] invert-[length:calc(50%+10px)]">Invalid invert</button> 
+      <button class="invert-[length:0] invert-[length:thick] invert-[length:var(--some)] invert-[length:calc(50%+10px)]">Invalid invert</button>
       `,
       options: config,
       errors: generateErrors(
@@ -835,7 +852,7 @@ ruleTester.run("arbitrary-values", rule, {
     },
     {
       code: `
-      <button class="filter saturate-[length:0] saturate-[length:thick] saturate-[length:var(--some)] saturate-[length:calc(50%+10px)]">Invalid saturate</button> 
+      <button class="saturate-[length:0] saturate-[length:thick] saturate-[length:var(--some)] saturate-[length:calc(50%+10px)]">Invalid saturate</button>
       `,
       options: config,
       errors: generateErrors(
@@ -844,7 +861,7 @@ ruleTester.run("arbitrary-values", rule, {
     },
     {
       code: `
-      <button class="filter sepia-[length:0] sepia-[length:thick] sepia-[length:var(--some)] sepia-[length:calc(50%+10px)]">Invalid sepia</button> 
+      <button class="sepia-[length:0] sepia-[length:thick] sepia-[length:var(--some)] sepia-[length:calc(50%+10px)]">Invalid sepia</button>
       `,
       options: config,
       errors: generateErrors(
@@ -853,7 +870,7 @@ ruleTester.run("arbitrary-values", rule, {
     },
     {
       code: `
-      <button class="backdrop-filter backdrop-blur-[length:0] backdrop-blur-[length:thick] backdrop-blur-[length:var(--some)] backdrop-blur-[length:calc(50%+10px)]">Invalid backdrop-blur</button> 
+      <button class="backdrop-blur-[length:0] backdrop-blur-[length:thick] backdrop-blur-[length:var(--some)] backdrop-blur-[length:calc(50%+10px)]">Invalid backdrop-blur</button>
       `,
       options: config,
       errors: generateErrors(
@@ -862,7 +879,7 @@ ruleTester.run("arbitrary-values", rule, {
     },
     {
       code: `
-      <button class="backdrop-filter backdrop-brightness-[length:0] backdrop-brightness-[length:thick] backdrop-brightness-[length:var(--some)] backdrop-brightness-[length:calc(50%+10px)]">Invalid backdrop-brightness</button> 
+      <button class="backdrop-brightness-[length:0] backdrop-brightness-[length:thick] backdrop-brightness-[length:var(--some)] backdrop-brightness-[length:calc(50%+10px)]">Invalid backdrop-brightness</button>
       `,
       options: config,
       errors: generateErrors(
@@ -871,7 +888,7 @@ ruleTester.run("arbitrary-values", rule, {
     },
     {
       code: `
-      <button class="backdrop-filter backdrop-contrast-[length:0] backdrop-contrast-[length:thick] backdrop-contrast-[length:var(--some)] backdrop-contrast-[length:calc(50%+10px)]">Invalid backdrop-contrast</button> 
+      <button class="backdrop-contrast-[length:0] backdrop-contrast-[length:thick] backdrop-contrast-[length:var(--some)] backdrop-contrast-[length:calc(50%+10px)]">Invalid backdrop-contrast</button>
       `,
       options: config,
       errors: generateErrors(
@@ -880,7 +897,7 @@ ruleTester.run("arbitrary-values", rule, {
     },
     {
       code: `
-      <button class="backdrop-filter backdrop-grayscale-[length:0] backdrop-grayscale-[length:thick] backdrop-grayscale-[length:var(--some)] backdrop-grayscale-[length:calc(50%+10px)]">Invalid backdrop-grayscale</button> 
+      <button class="backdrop-grayscale-[length:0] backdrop-grayscale-[length:thick] backdrop-grayscale-[length:var(--some)] backdrop-grayscale-[length:calc(50%+10px)]">Invalid backdrop-grayscale</button>
       `,
       options: config,
       errors: generateErrors(
@@ -889,7 +906,7 @@ ruleTester.run("arbitrary-values", rule, {
     },
     {
       code: `
-      <button class="backdrop-filter backdrop-hue-rotate-[length:0] backdrop-hue-rotate-[length:thick] backdrop-hue-rotate-[length:var(--some)] backdrop-hue-rotate-[length:calc(50%+10px)]">Invalid backdrop-hue-rotate</button> 
+      <button class="backdrop-hue-rotate-[length:0] backdrop-hue-rotate-[length:thick] backdrop-hue-rotate-[length:var(--some)] backdrop-hue-rotate-[length:calc(50%+10px)]">Invalid backdrop-hue-rotate</button>
       `,
       options: config,
       errors: generateErrors(
@@ -898,7 +915,7 @@ ruleTester.run("arbitrary-values", rule, {
     },
     {
       code: `
-      <button class="backdrop-filter backdrop-invert-[length:0] backdrop-invert-[length:thick] backdrop-invert-[length:var(--some)] backdrop-invert-[length:calc(50%+10px)]">Invalid backdrop-invert</button> 
+      <button class="backdrop-invert-[length:0] backdrop-invert-[length:thick] backdrop-invert-[length:var(--some)] backdrop-invert-[length:calc(50%+10px)]">Invalid backdrop-invert</button>
       `,
       options: config,
       errors: generateErrors(
@@ -907,7 +924,7 @@ ruleTester.run("arbitrary-values", rule, {
     },
     {
       code: `
-      <button class="backdrop-filter backdrop-opacity-[length:0] backdrop-opacity-[length:thick] backdrop-opacity-[length:var(--some)] backdrop-opacity-[length:calc(50%+10px)]">Invalid backdrop-opacity</button> 
+      <button class="backdrop-opacity-[length:0] backdrop-opacity-[length:thick] backdrop-opacity-[length:var(--some)] backdrop-opacity-[length:calc(50%+10px)]">Invalid backdrop-opacity</button>
       `,
       options: config,
       errors: generateErrors(
@@ -916,7 +933,7 @@ ruleTester.run("arbitrary-values", rule, {
     },
     {
       code: `
-      <button class="backdrop-filter backdrop-saturate-[length:0] backdrop-saturate-[length:thick] backdrop-saturate-[length:var(--some)] backdrop-saturate-[length:calc(50%+10px)]">Invalid backdrop-saturate</button> 
+      <button class="backdrop-saturate-[length:0] backdrop-saturate-[length:thick] backdrop-saturate-[length:var(--some)] backdrop-saturate-[length:calc(50%+10px)]">Invalid backdrop-saturate</button>
       `,
       options: config,
       errors: generateErrors(
@@ -925,7 +942,7 @@ ruleTester.run("arbitrary-values", rule, {
     },
     {
       code: `
-      <button class="backdrop-filter backdrop-sepia-[length:0] backdrop-sepia-[length:thick] backdrop-sepia-[length:var(--some)] backdrop-sepia-[length:calc(50%+10px)]">Invalid backdrop-sepia</button> 
+      <button class="backdrop-sepia-[length:0] backdrop-sepia-[length:thick] backdrop-sepia-[length:var(--some)] backdrop-sepia-[length:calc(50%+10px)]">Invalid backdrop-sepia</button>
       `,
       options: config,
       errors: generateErrors(
@@ -934,7 +951,7 @@ ruleTester.run("arbitrary-values", rule, {
     },
     {
       code: `
-      <button class="duration-[length:0] duration-[length:thick] duration-[length:var(--some)] duration-[length:calc(50%+10px)]">Invalid duration</button> 
+      <button class="duration-[length:0] duration-[length:thick] duration-[length:var(--some)] duration-[length:calc(50%+10px)]">Invalid duration</button>
       `,
       options: config,
       errors: generateErrors(
@@ -964,35 +981,35 @@ ruleTester.run("arbitrary-values", rule, {
     },
     {
       code: `
-      <div class="transform rotate-45 h-20 w-20 bg-green-600 origin-top-left origin-[list:top,right] origin-[list:10%]">origin</div>
+      <div class="rotate-45 h-20 w-20 bg-green-600 origin-top-left origin-[list:top,right] origin-[list:10%]">origin</div>
       `,
       options: config,
       errors: generateErrors("origin-[list:top,right] origin-[list:10%]"),
     },
     {
       code: `
-      <div class="transform scale-50 scale-0 scale-[length:90%] scale-[length:0.5]">scale</div>
+      <div class="scale-50 scale-0 scale-[length:90%] scale-[length:0.5]">scale</div>
       `,
       options: config,
       errors: generateErrors("scale-[length:90%] scale-[length:0.5]"),
     },
     {
       code: `
-      <div class="transform translate-y-6 translate-y-[length:10px] translate-y-[list:-10px]">translate</div>
+      <div class="translate-y-6 translate-y-[length:10px] translate-y-[list:-10px]">translate</div>
       `,
       options: config,
       errors: generateErrors("translate-y-[length:10px] translate-y-[list:-10px]"),
     },
     {
       code: `
-      <div class="transform translate-y-6 translate-y-[length:10px] translate-y-[list:-10px]">translate</div>
+      <div class="translate-y-6 translate-y-[length:10px] translate-y-[list:-10px]">translate</div>
       `,
       options: config,
       errors: generateErrors("translate-y-[length:10px] translate-y-[list:-10px]"),
     },
     {
       code: `
-      <div class="transform skew-y-6 skew-y-[length:10px] skew-y-[list:-10px]">skew</div>
+      <div class="skew-y-6 skew-y-[length:10px] skew-y-[list:-10px]">skew</div>
       `,
       options: config,
       errors: generateErrors("skew-y-[length:10px] skew-y-[list:-10px]"),
diff --git a/tests/lib/rules/classnames-order.js b/tests/lib/rules/classnames-order.js
index 6b31064..d3e667b 100644
--- a/tests/lib/rules/classnames-order.js
+++ b/tests/lib/rules/classnames-order.js
@@ -71,7 +71,7 @@ ruleTester.run("classnames-order", rule, {
       ],
     },
     {
-      code: `<div class="p-5 lg:p-4 md:py-2 sm:px-3 xl:px-6">'p', then 'py' then 'px'</div>`,
+      code: `<div class="p-5 sm:px-3 md:py-2 lg:p-4 xl:px-6">'p', then 'py' then 'px'</div>`,
     },
     {
       code: `<template><div class="container box-content lg:box-border custom">Simple, basic</div></template>`,
@@ -84,7 +84,7 @@ ruleTester.run("classnames-order", rule, {
       parser: require.resolve("vue-eslint-parser"),
     },
     {
-      code: `<template><div class="p-5 lg:p-4 md:py-2 sm:px-3 xl:px-6">'p', then 'py' then 'px'</div></template>`,
+      code: `<template><div class="p-5 sm:px-3 md:py-2 lg:p-4 xl:px-6">'p', then 'py' then 'px'</div></template>`,
       filename: "test.vue",
       parser: require.resolve("vue-eslint-parser"),
     },
@@ -115,30 +115,15 @@ ruleTester.run("classnames-order", rule, {
     },
     {
       code: `<div class="w-12 lg:w-[500px]">Allowed arbitrary value</div>`,
-      options: [
-        {
-          config: { mode: "jit" },
-        },
-      ],
     },
     {
       code: `<div class="dark:focus:hover:bg-black md:dark:disabled:focus:hover:bg-gray-400">Stackable variants</div>`,
-      options: [
-        {
-          config: {
-            mode: "jit",
-          },
-        },
-      ],
     },
     {
       code: `<div className={clsx(\`flex absolute bottom-0 flex-col w-full h-[270px]\`)}>clsx</div>`,
       options: [
         {
           callees: ["clsx"],
-          config: {
-            mode: "jit",
-          },
         },
       ],
     },
@@ -233,12 +218,12 @@ ruleTester.run("classnames-order", rule, {
     },
     {
       code: `<div class="sm:py-5 p-4 sm:px-7 lg:p-8">Enhancing readability</div>`,
-      output: `<div class="p-4 lg:p-8 sm:py-5 sm:px-7">Enhancing readability</div>`,
+      output: `<div class="p-4 sm:py-5 sm:px-7 lg:p-8">Enhancing readability</div>`,
       errors: errors,
     },
     {
       code: `<div class="grid grid-cols-1 sm:grid-cols-2 sm:px-8 sm:py-12 sm:gap-x-8 md:py-16">:)</div>`,
-      output: `<div class="grid grid-cols-1 sm:grid-cols-2 sm:gap-x-8 sm:py-12 md:py-16 sm:px-8">:)</div>`,
+      output: `<div class="grid grid-cols-1 sm:grid-cols-2 sm:gap-x-8 sm:py-12 sm:px-8 md:py-16">:)</div>`,
       errors: errors,
     },
     {
@@ -250,14 +235,14 @@ ruleTester.run("classnames-order", rule, {
     },
     {
       code: `<template><div class="sm:py-5 p-4 sm:px-7 lg:p-8">Enhancing readability</div></template>`,
-      output: `<template><div class="p-4 lg:p-8 sm:py-5 sm:px-7">Enhancing readability</div></template>`,
+      output: `<template><div class="p-4 sm:py-5 sm:px-7 lg:p-8">Enhancing readability</div></template>`,
       errors: errors,
       filename: "test.vue",
       parser: require.resolve("vue-eslint-parser"),
     },
     {
       code: `<template><div class="grid grid-cols-1 sm:grid-cols-2 sm:px-8 sm:py-12 sm:gap-x-8 md:py-16">:)</div></template>`,
-      output: `<template><div class="grid grid-cols-1 sm:grid-cols-2 sm:gap-x-8 sm:py-12 md:py-16 sm:px-8">:)</div></template>`,
+      output: `<template><div class="grid grid-cols-1 sm:grid-cols-2 sm:gap-x-8 sm:py-12 sm:px-8 md:py-16">:)</div></template>`,
       errors: errors,
       filename: "test.vue",
       parser: require.resolve("vue-eslint-parser"),
@@ -391,23 +376,11 @@ ruleTester.run("classnames-order", rule, {
     {
       code: `<div class="sm:w-12 w-[320px]">Allowed arbitrary value but incorrect order</div>`,
       output: `<div class="w-[320px] sm:w-12">Allowed arbitrary value but incorrect order</div>`,
-      options: [
-        {
-          config: { mode: "jit" },
-        },
-      ],
       errors: errors,
     },
     {
       code: `<div className='absolute bottom-0 w-full h-[270px] flex flex-col'>clsx</div>`,
       output: `<div className='flex absolute bottom-0 flex-col w-full h-[270px]'>clsx</div>`,
-      options: [
-        {
-          config: {
-            mode: "jit",
-          },
-        },
-      ],
       errors: errors,
     },
     {
@@ -416,9 +389,6 @@ ruleTester.run("classnames-order", rule, {
       options: [
         {
           callees: ["clsx"],
-          config: {
-            mode: "jit",
-          },
         },
       ],
       errors: errors,
@@ -429,9 +399,6 @@ ruleTester.run("classnames-order", rule, {
       options: [
         {
           callees: ["clsx"],
-          config: {
-            mode: "jit",
-          },
         },
       ],
       errors: errors,
@@ -442,9 +409,6 @@ ruleTester.run("classnames-order", rule, {
       options: [
         {
           callees: ["clsx"],
-          config: {
-            mode: "jit",
-          },
         },
       ],
       errors: errors,
diff --git a/tests/lib/rules/migration-from-tailwind-2.js b/tests/lib/rules/migration-from-tailwind-2.js
new file mode 100644
index 0000000..9b1d310
--- /dev/null
+++ b/tests/lib/rules/migration-from-tailwind-2.js
@@ -0,0 +1,175 @@
+/**
+ * @fileoverview Detect obsolete classnames when upgrading to Tailwind CSS v3
+ * @author François Massart
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+var rule = require("../../../lib/rules/migration-from-tailwind-2");
+var RuleTester = require("eslint").RuleTester;
+
+//------------------------------------------------------------------------------
+// Tests
+//------------------------------------------------------------------------------
+
+var parserOptions = {
+  ecmaVersion: 2019,
+  sourceType: "module",
+  ecmaFeatures: {
+    jsx: true,
+  },
+};
+
+var ruleTester = new RuleTester({ parserOptions });
+
+ruleTester.run("migration-from-tailwind-2", rule, {
+  valid: [
+    {
+      code: `<div class="scale-50 grayscale backdrop-blur-sm">Automatic transforms and filters</div>`,
+    },
+  ],
+  invalid: [
+    {
+      code: `<div class="transform scale-50">Automatic transform</div>`,
+      output: `<div class="scale-50">Automatic transform</div>`,
+      errors: [
+        {
+          messageId: "classnameNotNeeded",
+          data: {
+            classnames: "transform",
+          },
+        },
+      ],
+    },
+    {
+      code: `<div class="backdrop-filter backdrop-blur-sm">Automatic transform</div>`,
+      output: `<div class="backdrop-blur-sm">Automatic transform</div>`,
+      errors: [
+        {
+          messageId: "classnameNotNeeded",
+          data: {
+            classnames: "backdrop-filter",
+          },
+        },
+      ],
+    },
+    {
+      code: `<div class="transform scale-50 filter grayscale backdrop-filter backdrop-blur-sm">Automatic transforms and filters</div>`,
+      output: `<div class="scale-50 grayscale backdrop-blur-sm">Automatic transforms and filters</div>`,
+      errors: [
+        {
+          messageId: "classnamesNotNeeded",
+          data: {
+            classnames: "transform, filter, backdrop-filter",
+          },
+        },
+      ],
+    },
+    {
+      code: `<div class="overflow-clip">overflow-clip/ellipsis</div>`,
+      output: `<div class="text-clip">overflow-clip/ellipsis</div>`,
+      errors: [
+        {
+          messageId: "classnameChanged",
+          data: {
+            deprecated: "overflow-clip",
+            updated: "text-clip",
+          },
+        },
+      ],
+    },
+    {
+      code: `<div class="overflow-ellipsis">overflow-clip/ellipsis</div>`,
+      output: `<div class="text-ellipsis">overflow-clip/ellipsis</div>`,
+      errors: [
+        {
+          messageId: "classnameChanged",
+          data: {
+            deprecated: "overflow-ellipsis",
+            updated: "text-ellipsis",
+          },
+        },
+      ],
+    },
+    {
+      code: `<div class="flex-grow-0">flex-grow/shrink</div>`,
+      output: `<div class="grow-0">flex-grow/shrink</div>`,
+      errors: [
+        {
+          messageId: "classnameChanged",
+          data: {
+            deprecated: "flex-grow-0",
+            updated: "grow-0",
+          },
+        },
+      ],
+    },
+    {
+      code: `<div class="flex-shrink">flex-grow/shrink</div>`,
+      output: `<div class="shrink">flex-grow/shrink</div>`,
+      errors: [
+        {
+          messageId: "classnameChanged",
+          data: {
+            deprecated: "flex-shrink",
+            updated: "shrink",
+          },
+        },
+      ],
+    },
+    {
+      code: `<div class="decoration-clone">decoration-clone/slice</div>`,
+      output: `<div class="box-decoration-clone">decoration-clone/slice</div>`,
+      errors: [
+        {
+          messageId: "classnameChanged",
+          data: {
+            deprecated: "decoration-clone",
+            updated: "box-decoration-clone",
+          },
+        },
+      ],
+    },
+    {
+      code: `<div class="decoration-slice">decoration-clone/slice</div>`,
+      output: `<div class="box-decoration-slice">decoration-clone/slice</div>`,
+      errors: [
+        {
+          messageId: "classnameChanged",
+          data: {
+            deprecated: "decoration-slice",
+            updated: "box-decoration-slice",
+          },
+        },
+      ],
+    },
+    {
+      code: `<div class="bg-opacity-50">bg-opacity</div>`,
+      errors: [
+        {
+          messageId: "bgOpacityDeprecated",
+          data: {
+            classname: "bg-opacity-50",
+            value: "50",
+          },
+        },
+      ],
+    },
+    {
+      code: `<div class="placeholder-red-900"></div>`,
+      output: `<div class="placeholder:text-red-900"></div>`,
+      errors: [
+        {
+          messageId: "classnameChanged",
+          data: {
+            deprecated: "placeholder-red-900",
+            updated: "placeholder:text-red-900",
+          },
+        },
+      ],
+    },
+  ],
+});
diff --git a/tests/lib/rules/no-contradicting-classname.js b/tests/lib/rules/no-contradicting-classname.js
index 1b79dd5..e32138e 100644
--- a/tests/lib/rules/no-contradicting-classname.js
+++ b/tests/lib/rules/no-contradicting-classname.js
@@ -26,26 +26,34 @@ var parserOptions = {
 var config = [
   {
     config: {
-      mode: "jit",
       theme: {
         aspectRatio: {
           1: "1",
           9: "9",
           16: "16",
         },
-        order: {
-          "-1": "-1",
-          0: "0",
-        },
-        zIndex: {
-          "-1": "-1",
-          0: "0",
-        },
       },
     },
   },
 ];
 
+var generateErrors = (classnames) => {
+  const errors = [];
+  if (typeof classnames === "string") {
+    classnames = [classnames];
+  }
+  classnames.map((classname) => {
+    const cls = classname.split(" ").join(", ");
+    errors.push({
+      messageId: "conflictingClassnames",
+      data: {
+        classnames: cls,
+      },
+    });
+  });
+  return errors;
+};
+
 var ruleTester = new RuleTester({ parserOptions });
 
 ruleTester.run("no-contradicting-classname", rule, {
@@ -56,6 +64,9 @@ ruleTester.run("no-contradicting-classname", rule, {
     {
       code: '<div class="p-1 px-2 sm:px-3 sm:pt-0">Accepts shorthands</div>',
     },
+    {
+      code: '<div class="ring-2 ring-pink-300 ring-inset">Ring</div>',
+    },
     {
       code: '<template><div class="overflow-auto overflow-x-hidden lg:overflow-x-auto lg:dark:overflow-x-visible lg:dark:active:overflow-x-visible active:overflow-auto"></div></template>',
       filename: "test.vue",
@@ -183,25 +194,11 @@ ruleTester.run("no-contradicting-classname", rule, {
       export default Fake;
       `,
       parser: require.resolve("@typescript-eslint/parser"),
-      errors: [
-        {
-          messageId: "conflictingClassnames",
-          data: {
-            classnames: "w-1, w-2",
-          },
-        },
-      ],
+      errors: generateErrors("w-1 w-2"),
     },
     {
       code: '<div class="container w-1 w-2"></div>',
-      errors: [
-        {
-          messageId: "conflictingClassnames",
-          data: {
-            classnames: "w-1, w-2",
-          },
-        },
-      ],
+      errors: generateErrors("w-1 w-2"),
     },
     {
       code: '<div class="container sm_w-3 sm_w-4 lg_w-6"></div>',
@@ -210,25 +207,11 @@ ruleTester.run("no-contradicting-classname", rule, {
           config: { separator: "_" },
         },
       ],
-      errors: [
-        {
-          messageId: "conflictingClassnames",
-          data: {
-            classnames: "sm_w-3, sm_w-4",
-          },
-        },
-      ],
+      errors: generateErrors("sm_w-3 sm_w-4"),
     },
     {
       code: '<template><div class="container w-1 w-2"></div></template>',
-      errors: [
-        {
-          messageId: "conflictingClassnames",
-          data: {
-            classnames: "w-1, w-2",
-          },
-        },
-      ],
+      errors: generateErrors("w-1 w-2"),
       filename: "test.vue",
       parser: require.resolve("vue-eslint-parser"),
     },
@@ -239,33 +222,13 @@ ruleTester.run("no-contradicting-classname", rule, {
           config: { separator: "_" },
         },
       ],
-      errors: [
-        {
-          messageId: "conflictingClassnames",
-          data: {
-            classnames: "sm_w-3, sm_w-4",
-          },
-        },
-      ],
+      errors: generateErrors("sm_w-3 sm_w-4"),
       filename: "test.vue",
       parser: require.resolve("vue-eslint-parser"),
     },
     {
       code: '<div class="flex-1 order-first order-11 sm:order-last flex-none"></div>',
-      errors: [
-        {
-          messageId: "conflictingClassnames",
-          data: {
-            classnames: "flex-1, flex-none",
-          },
-        },
-        {
-          messageId: "conflictingClassnames",
-          data: {
-            classnames: "order-first, order-11",
-          },
-        },
-      ],
+      errors: generateErrors(["flex-1 flex-none", "order-first order-11"]),
     },
     {
       code: `
@@ -278,32 +241,12 @@ ruleTester.run("no-contradicting-classname", rule, {
         flex
         lg:w-4
       \`);`,
-      errors: [
-        {
-          messageId: "conflictingClassnames",
-          data: {
-            classnames: "w-8, w-12",
-          },
-        },
-      ],
+      errors: generateErrors("w-8 w-12"),
     },
     {
       code: '<div class="container sm:w-3 sm:w-[40%] lg:w-6 z-0 z-[var(--some)]"></div>',
       options: config,
-      errors: [
-        {
-          messageId: "conflictingClassnames",
-          data: {
-            classnames: "z-0, z-[var(--some)]",
-          },
-        },
-        {
-          messageId: "conflictingClassnames",
-          data: {
-            classnames: "sm:w-3, sm:w-[40%]",
-          },
-        },
-      ],
+      errors: generateErrors(["z-0 z-[var(--some)]", "sm:w-3 sm:w-[40%]"]),
     },
     {
       code: `<div className={clsx(\`container sm:w-3 sm:w-2 lg:w-6\`)}>clsx</div>`,
@@ -312,14 +255,7 @@ ruleTester.run("no-contradicting-classname", rule, {
           callees: ["clsx"],
         },
       ],
-      errors: [
-        {
-          messageId: "conflictingClassnames",
-          data: {
-            classnames: "sm:w-3, sm:w-2",
-          },
-        },
-      ],
+      errors: generateErrors("sm:w-3 sm:w-2"),
     },
     {
       code: `
@@ -342,37 +278,11 @@ ruleTester.run("no-contradicting-classname", rule, {
         }
       \`)
       `,
-      errors: [
-        {
-          messageId: "conflictingClassnames",
-          data: {
-            classnames: "py-1, py-2",
-          },
-        },
-        {
-          messageId: "conflictingClassnames",
-          data: {
-            classnames: "w-1, w-2",
-          },
-        },
-        {
-          messageId: "conflictingClassnames",
-          data: {
-            classnames: "px-2, px-4",
-          },
-        },
-      ],
+      errors: generateErrors(["py-1 py-2", "w-1 w-2", "px-2 px-4"]),
     },
     {
       code: `ctl(\`\${enabled && "px-2 px-0"}\`)`,
-      errors: [
-        {
-          messageId: "conflictingClassnames",
-          data: {
-            classnames: "px-2, px-0",
-          },
-        },
-      ],
+      errors: generateErrors("px-2 px-0"),
     },
 
     {
@@ -387,14 +297,7 @@ ruleTester.run("no-contradicting-classname", rule, {
         lg:w-4
       \`;`,
       options: [{ tags: ["myTag"] }],
-      errors: [
-        {
-          messageId: "conflictingClassnames",
-          data: {
-            classnames: "w-8, w-12",
-          },
-        },
-      ],
+      errors: generateErrors("w-8 w-12"),
     },
     {
       code: `
@@ -418,88 +321,43 @@ ruleTester.run("no-contradicting-classname", rule, {
       \`
       `,
       options: [{ tags: ["myTag"] }],
-      errors: [
-        {
-          messageId: "conflictingClassnames",
-          data: {
-            classnames: "py-1, py-2",
-          },
-        },
-        {
-          messageId: "conflictingClassnames",
-          data: {
-            classnames: "w-1, w-2",
-          },
-        },
-        {
-          messageId: "conflictingClassnames",
-          data: {
-            classnames: "px-2, px-4",
-          },
-        },
-      ],
+      errors: generateErrors(["py-1 py-2", "w-1 w-2", "px-2 px-4"]),
     },
     {
       code: `myTag\`\${enabled && "px-2 px-0"}\``,
       options: [{ tags: ["myTag"] }],
-      errors: [
-        {
-          messageId: "conflictingClassnames",
-          data: {
-            classnames: "px-2, px-0",
-          },
-        },
-      ],
+      errors: generateErrors("px-2 px-0"),
     },
     {
       code: `
-      <div class="flex-shrink flex-shrink-0 flex-shrink-[inherit] flex-shrink-[initial] flex-shrink-[unset] flex-shrink-[var(--some)] flex-shrink-[0.5] flex-shrink-[5]">
+      <div class="shrink shrink-0 shrink-[inherit] shrink-[initial] shrink-[unset] shrink-[var(--some)] shrink-[0.5] shrink-[5]">
         Arbitrary values for positive integers
       </div>
       `,
       options: config,
-      errors: [
-        {
-          messageId: "conflictingClassnames",
-          data: {
-            classnames:
-              "flex-shrink, flex-shrink-0, flex-shrink-[inherit], flex-shrink-[initial], flex-shrink-[unset], flex-shrink-[var(--some)], flex-shrink-[0.5], flex-shrink-[5]",
-          },
-        },
-      ],
+      errors: generateErrors(
+        "shrink shrink-0 shrink-[inherit] shrink-[initial] shrink-[unset] shrink-[var(--some)] shrink-[0.5] shrink-[5]"
+      ),
     },
     {
       code: `
-      <div class="order-0 -order-1 order-[inherit] order-[initial] order-[unset] order-[var(--some)] order-[2] order-[-3]">
+      <div class="order-2 -order-1 order-[inherit] order-[initial] order-[unset] order-[var(--some)] order-[2] order-[-3]">
         Arbitrary values for order
       </div>
       `,
       options: config,
-      errors: [
-        {
-          messageId: "conflictingClassnames",
-          data: {
-            classnames:
-              "order-0, -order-1, order-[inherit], order-[initial], order-[unset], order-[var(--some)], order-[2], order-[-3]",
-          },
-        },
-      ],
+      errors: generateErrors(
+        "order-2 -order-1 order-[inherit] order-[initial] order-[unset] order-[var(--some)] order-[2] order-[-3]"
+      ),
     },
     {
       code: `
-      <div class="z-0 -z-1 z-[auto] z-[inherit] z-[initial] z-[unset] z-[var(--some)] z-[2] z-[-3]">
-        Arbitrary values for zIndex
+      <div class="z-0 -z-10 z-[auto] z-[inherit] z-[initial] z-[unset] z-[var(--some)] z-[2] z-[-3]">
+        Arbitrary values for zIndex!
       </div>
       `,
       options: config,
-      errors: [
-        {
-          messageId: "conflictingClassnames",
-          data: {
-            classnames: "z-0, -z-1, z-[auto], z-[inherit], z-[initial], z-[unset], z-[var(--some)], z-[2], z-[-3]",
-          },
-        },
-      ],
+      errors: generateErrors("z-0 -z-10 z-[auto] z-[inherit] z-[initial] z-[unset] z-[var(--some)] z-[2] z-[-3]"),
     },
     {
       code: `
@@ -508,14 +366,7 @@ ruleTester.run("no-contradicting-classname", rule, {
       </div>
       `,
       options: config,
-      errors: [
-        {
-          messageId: "conflictingClassnames",
-          data: {
-            classnames: "flex-auto, flex-[2,2,10%], flex-[var(--some)]",
-          },
-        },
-      ],
+      errors: generateErrors("flex-auto flex-[2,2,10%] flex-[var(--some)]"),
     },
     {
       code: `
@@ -524,26 +375,12 @@ ruleTester.run("no-contradicting-classname", rule, {
       </div>
       `,
       options: config,
-      errors: [
-        {
-          messageId: "conflictingClassnames",
-          data: {
-            classnames: "rounded-xl, rounded-[50%/10%], rounded-[10%,30%,50%,70%], rounded-[var(--some)]",
-          },
-        },
-      ],
+      errors: generateErrors("rounded-xl rounded-[50%/10%] rounded-[10%,30%,50%,70%] rounded-[var(--some)]"),
     },
     {
       code: `<div class="aspect-none aspect-w-16 aspect-w-10 aspect-h-9">aspect</div>`,
       options: config,
-      errors: [
-        {
-          messageId: "conflictingClassnames",
-          data: {
-            classnames: "aspect-none, aspect-w-16",
-          },
-        },
-      ],
+      errors: generateErrors("aspect-none aspect-w-16"),
     },
   ],
 });
diff --git a/tests/lib/rules/no-custom-classname.js b/tests/lib/rules/no-custom-classname.js
index e33941f..af4b03a 100644
--- a/tests/lib/rules/no-custom-classname.js
+++ b/tests/lib/rules/no-custom-classname.js
@@ -23,12 +23,316 @@ var parserOptions = {
   },
 };
 
+var generateErrors = (classnames) => {
+  const errors = [];
+  if (typeof classnames === "string") {
+    classnames = classnames.split(" ");
+  }
+  classnames.map((classname) => {
+    errors.push({
+      messageId: "customClassnameDetected",
+      data: {
+        classname: classname,
+      },
+    });
+  });
+  return errors;
+};
+
 var ruleTester = new RuleTester({ parserOptions });
 
 ruleTester.run("no-custom-classname", rule, {
   valid: [
     {
-      code: `<div class="container box-content lg:box-border max-h-24 self-end">Only Tailwind CSS classnames</div>`,
+      code: `<div class="group peer">Hover, Focus, & Other States</div>`,
+    },
+    {
+      code: `<div className="dark">dark should be allowed in class mode</div>`,
+      options: [
+        {
+          config: { darkMode: "class" },
+        },
+      ],
+    },
+    {
+      code: `<div className="[mask-type:luminance] hover:[mask-type:alpha] [--scroll-offset:56px] grid grid-cols-[1fr_500px_2fr]">dark should be allowed in class mode</div>`,
+    },
+    {
+      code: `
+      <section>
+        <h1>Layout utilities</h1>
+        <div class="container">Container</div>
+        <div class="box-content lg:box-border">Box Sizing</div>
+        <div class="inline-block sm:block md:flex lg:table">Display</div>
+        <div class="float-none sm:float-left md:float-right">Floats</div>
+        <div class="clear-left sm:clear-right md:clear-both lg:clear-none">Clear</div>
+        <div class="isolate sm:isolation-auto">Isolation</div>
+        <div class="object-contain sm:object-cover md:object-fill lg:object-none dark:object-scale-down">Object Fit</div>
+        <div class="overflow-auto sm:overflow-scroll">Overflow</div>
+        <div class="overscroll-none md:overscroll-y-auto">Overscroll Behavior</div>
+        <div class="fixed sm:absolute">Position</div>
+        <div class="visible sm:invisible">Visibility</div>
+      </section>`,
+    },
+    {
+      code: `<div class="columns-2 hover:columns-3 lg:columns-[10rem]">Columns</div>`,
+    },
+    {
+      code: `<div class="break-after-auto md:break-after-avoid-page break-before-left break-inside-avoid-column">Break</div>`,
+    },
+    {
+      code: `<div class="box-decoration-clone	sm:box-decoration-slice">Box Decoration Break</div>`,
+    },
+    {
+      code: `<div class="object-right object-[center_bottom]">Object Position</div>`,
+    },
+    {
+      code: `<div class="inset-x-0 top-2 -left-2 bottom-[3px] right-[-3px]">Top / Right / Bottom / Left</div>`,
+    },
+    {
+      code: `<div class="z-0 sm:z-1000 md:-z-1000 lg:z-[100] dark:-z-0 sm:dark:z-1000 md:dark:-z-1000 lg:dark:z-[100] xl:dark:-z-666">Z-Index</div>`,
+      options: [
+        {
+          config: {
+            theme: {
+              extend: {
+                zIndex: {
+                  0: "0",
+                  "-666": "-666",
+                  1000: "1000",
+                },
+              },
+            },
+          },
+        },
+      ],
+    },
+    {
+      code: `
+      <section>
+        <h1>Flexbox & Grid</h1>
+        <div class="basis-[14.2857143%] sm:basis-1">Flex Basis</div>
+        <div class="flex-row">Flex Direction</div>
+        <div class="flex-wrap">Flex Wrap</div>
+        <div class="flex-auto sm:flex-1 flex-[2_2_0%]">Flex</div>
+        <div class="grow sm:grow-0 md:grow-[2]">Flex Grow</div>
+        <div class="shrink sm:shrink-0 md:shrink-[2]">Flex Shrink</div>
+        <div class="order-1 sm:order-[13]">Order</div>
+        <div class="grid-cols-6 sm:grid-cols-[200px_minmax(900px,_1fr)_100px]"></div>
+        <div class="col-auto sm:col-span-1 md:col-[span_1_/_span_3]">Grid Column Start / End</div>
+        <div class="grid-rows-4 sm:grid-rows-[200px_minmax(900px,_1fr)_100px]">Grid Template Rows</div>
+        <div class="row-auto sm:row-span-6 md:row-span-full lg:row-[span_16_/_span_16]">Grid Row Start / End</div>
+        <div class="grid-flow-row-dense">Grid Auto Flow</div>
+        <div class="auto-cols-max sm:auto-cols-[minmax(0,_2fr)]">Grid Auto Columns</div>
+        <div class="auto-rows-max auto-rows-[minmax(0,_2fr)]">Grid Auto Rows</div>
+        <div class="gap-x-0 sm:gap-y-3 gap-[2.75rem]">Gap</div>
+        <div class="justify-end	">Justify Content</div>
+        <div class="justify-items-end	">Justify Items</div>
+        <div class="justify-self-start">Justify Self</div>
+        <div class="content-center">Align Content</div>
+        <div class="items-baseline">Align Items</div>
+        <div class="self-stretch">Align Self</div>
+        <div class="place-content-evenly">Place Content</div>
+        <div class="place-items-center">Place Items</div>
+        <div class="place-self-center">Place Self</div>
+      </section>`,
+    },
+    {
+      code: `
+      <section>
+        <h1>Spacing</h1>
+        <div class="p-1 sm:pr-0 md:px-[5px]">Padding</div>
+        <div class="m-1 sm:mr-0 md:mx-[5px] lg:-ml-1">Margin</div>
+        <div class="space-x-0 sm:space-y-1 md:space-x-reverse lg:space-y-reverse xl:space-y-[5px] dark:-space-x-1 sm:dark:-space-y-1 xl:dark:space-y-[-5px]">Space Between</div>
+      </section>`,
+    },
+    {
+      code: `
+      <section>
+        <h1>Sizing</h1>
+        <div class="w-0 sm:w-px md:w-1/2 lg:w-max xl:w-[32rem]">Width</div>
+        <div class="min-w-0 sm:min-w-full md:min-w-min lg:min-w-max xl:min-w-[50%]">Min-Width</div>
+        <div class="max-w-0 sm:max-w-none md:max-w-2xl lg:max-w-screen-xl xl:max-w-[50%]">Max-Width</div>
+        <div class="h-0 sm:h-px md:h-1/2 lg:h-max xl:h-[32rem]">Height</div>
+        <div class="min-h-0 sm:min-h-full md:min-h-min lg:min-h-max xl:min-h-[50%]">Min-Height</div>
+        <div class="max-h-0 sm:max-h-2 md:max-h-full lg:max-h-screen xl:max-h-[32rem]">Max-Height</div>
+        <div class=""></div>
+      </section>`,
+    },
+    {
+      code: `
+      <section>
+        <h1>Typography</h1>
+        <div class="font-sans sm:font-serif md:font-mono lg:font-['Open_Sans']">Font Family</div>
+        <div class="text-xs sm:text-base md:text-2xl lg:text-[14px]">Font Size</div>
+        <div class="antialiased sm:subpixel-antialiased">Font Smoothing</div>
+        <div class="italic sm:not-italic">Font Style</div>
+        <div class="font-thin sm:font-extralight md:font-light lg:font-normal xl:font-medium dark:font-semibold sm:dark:font-bold md:dark:font-extrabold lg:dark:font-black xl:dark:font-[1100]">Font Weight</div>
+        <div class="ordinal slashed-zero tabular-nums sm:normal-nums md:lining-nums lg:oldstyle-nums xl:proportional-nums 2xl:tabular-nums">Font Variant Numeric</div>
+        <div class="tracking-tighter sm:tracking-tight md:tracking-normal lg:tracking-wide xl:tracking-wider 2xl:tracking-widest dark:tracking-[.25em] sm:dark:-tracking-wide md:dark:-tracking-normal lg:dark:tracking-[-.25em]">Letter Spacing</div>
+        <div class="leading-3 sm:leading-none md:leading-tight lg:leading-snug xl:leading-normal 2xl:leading-relaxed dark:leading-loose sm:dark:leading-[3rem]">Line Height</div>
+        <div class="list-none sm:list-disc md:list-decimal lg:list-[upper-roman]">List Style Type</div>
+        <div class="list-inside sm:list-outside">List Style Position</div>
+        <div class="text-left sm:text-center md:text-right lg:text-justify">Text Alignment</div>
+        <div class="text-inherit sm:text-current md:text-transparent lg:text-black xl:text-white 2xl:text-slate-200 dark:text-[#50d71e] sm:dark:text-[color:var(--yolo)] first:text-black/50 last:text-[#F005] even:text-[#F0F5F6B8] odd:text-[rgba(100,10,140,.5)]">Text Color</div>
+        <div class="underline sm:overline md:line-through lg:no-underline">Text Decoration</div>
+        <div class="decoration-inherit sm:decoration-current md:decoration-transparent lg:text-black xl:decoration-white 2xl:decoration-slate-200 dark:decoration-[#50d71e] sm:dark:decoration-[color:var(--yolo)] first:decoration-black/50 last:decoration-[#F005] even:decoration-[#F0F5F6B8] odd:decoration-[rgba(100,10,140,.5)]">Text Decoration Color</div>
+        <div class="decoration-solid sm:decoration-double md:decoration-dotted lg:decoration-dashed xl:decoration-wavy">Text Decoration Style</div>
+        <div class="decoration-auto sm:decoration-from-font md:decoration-0 lg:decoration-8 xl:decoration-[3px] 2xl:decoration-[length:var(--yolo)]">Text Decoration Thickness</div>
+        <div class="underline-offset-auto sm:underline-offset-0 md:underline-offset-8 underline-offset-[3px]">Text Underline Offset</div>
+        <div class="uppercase sm:lowercase md:capitalize lg:normal-case">Text Transform</div>
+        <div class="truncate sm:text-ellipsis md:text-clip">Text Overflow</div>
+        <div class="indent-0 sm:indent-3 md:indent-[50%] lg:-indent-3 xl:indent-[-10px]">Text Indent</div>
+        <div class="align-baseline sm:align-top md:align-middle lg:align-bottom xl:align-text-top dark:align-text-bottom sm:dark:align-sub md:dark:align-super">Vertical Alignment</div>
+        <div class="whitespace-normal sm:whitespace-nowrap md:whitespace-pre lg:whitespace-pre-line xl:whitespace-pre-wrap">Whitespace</div>
+        <div class="break-normal sm:break-words md:break-all">Word Break</div>
+        <div class="content-none after:content-['_↗'] before:content-[attr(before)] sm:before:content-['Hello_World'] md:before:content-['Hello\_World'] lg:before:content-[url('/icons/link.svg')]">Content</div>
+      </section>`,
+    },
+    {
+      code: `
+      <section>
+        <h1>Backgrounds</h1>
+        <div class="bg-fixed sm:bg-local md:bg-scroll">Background Attachment</div>
+        <div class="bg-clip-border sm:bg-clip-padding md:bg-clip-content lg:bg-clip-text">Background Clip</div>
+        <div class="bg-inherit sm:bg-current md:bg-black lg:bg-lime-900 xl:bg-[#50d71e] 2xl:bg-[color:var(--some)]">Background Color</div>
+        <div class="bg-origin-border sm:bg-origin-padding md:bg-origin-content">Background Origin</div>
+        <div class="bg-bottom sm:bg-center md:bg-left lg:bg-left-bottom xl:bg-left-top 2xl:bg-right dark:bg-right-bottom sm:dark:bg-right-top md:dark:bg-top lg:dark:bg-[center_top_1rem]">Background Position</div>
+        <div class="bg-repeat sm:bg-no-repeat md:bg-repeat-x lg:bg-repeat-y xl:bg-repeat-round 2xl:bg-repeat-space">Background Repeat</div>
+        <div class="bg-auto sm:bg-cover md:bg-contain lg:bg-[length:200px_100px]">Background Size</div>
+        <div class="bg-none sm:bg-gradient-to-tr md:bg-[url('/img/hero-pattern.svg')]">Background Image</div>
+        <div class="from-inherit sm:from-current md:from-transparent lg:from-black xl:from-[#243c5a] 2xl:from-[#243c5a/50] first:from-black/50 last:from-[#F005] even:from-[#F0F5F6B8] odd:from-[rgba(100,10,140,.5)]">Gradient Color Stops</div>
+      </section>`,
+    },
+    {
+      code: `
+      <section>
+        <h1>Borders</h1>
+        <div class="rounded-none sm:rounded-xl md:rounded-t-md lg:rounded-br-3xl xl:rounded-[12px]">Border Radius</div>
+        <div class="border sm:border-0 md:border-x-2 lg:border-y-8 xl:border-r 2xl:border-t-[3px]">Border Width</div>
+        <div class="border-transparent sm:border-rose-500 md:border-t-indigo-500/75 lg:border-x-indigo-500 xl:border-[#243c5a] first:border-black/50 last:border-[#F005] even:border-[#F0F5F6B8] odd:border-[rgba(100,10,140,.5)]">Border Color</div>
+        <div class="border-solid sm:border-dashed md:border-dotted lg:border-double xl:border-hidden 2xl:border-none">Border Style</div>
+        <div class="divide-y-4 sm:divide-x-8 md:divide-y lg:divide-y-reverse xl:divide-x-reverse 2xl:divide-x-[3px]">Divide Width</div>
+        <div class="divide-gray-400/25 sm:divide-amber-400 md:divide-[#243c5a] first:divide-black/50 last:divide-[#F005] even:divide-[#F0F5F6B8] odd:divide-[rgba(100,10,140,.5)]">Divide Color</div>
+        <div class="divide-solid sm:divide-dashed md:divide-dotted lg:divide-double xl:divide-none">Divide Style</div>
+        <div class="outline-0 sm:outline-4 md:outline-[5px]">Outline Width</div>
+        <div class="outline-inherit sm:outline-current md:outline-black lg:outline-lime-900 xl:outline-[#50d71e] 2xl:outline-[color:var(--some)] first:outline-black/50 last:outline-[#F005] even:outline-[#F0F5F6B8] odd:outline-[rgba(100,10,140,.5)]">Outline Color</div>
+        <div class="outline-none sm:outline md:outline-dashed lg:outline-dotted xl:outline-double 2xl:outline-hidden">Outline Style</div>
+        <div class="outline-offset-4 sm:outline-offset-[3px]">Outline Offset</div>
+        <div class="ring-0 sm:ring-4 md:ring-inset lg:ring-[10px]">Ring Width</div>
+        <div class="ring-inherit sm:ring-current md:ring-black lg:ring-lime-900 xl:ring-[#50d71e] 2xl:ring-[color:var(--some)] first:ring-black/50 last:ring-[#F005] even:ring-[#F0F5F6B8] odd:ring-[rgba(100,10,140,.5)]">Ring Color</div>
+        <div class="ring-offset-4 sm:ring-offset-[3px]">Ring Offset Width</div>
+        <div class="ring-offset-inherit sm:ring-offset-current md:ring-offset-black lg:ring-offset-lime-900 xl:ring-offset-[#50d71e] 2xl:ring-offset-[color:var(--some)] first:ring-offset-black/50 last:ring-offset-[#F005] even:ring-offset-[#F0F5F6B8] odd:ring-offset-[rgba(100,10,140,.5)]">Ring Offset Color</div>
+      </section>`,
+    },
+    {
+      code: `
+      <section>
+        <h1>Effects</h1>
+        <div class="shadow sm:shadow-lg md:shadow-inner lg:shadow-none xl:shadow-[0_35px_60px_-15px_rgba(0,0,0,0.3)]">Box Shadow</div>
+        <div class="shadow-inherit sm:shadow-current md:shadow-black lg:shadow-lime-900 xl:shadow-[#50d71e] 2xl:shadow-[color:var(--some)] first:shadow-black/50 last:shadow-[#F005] even:shadow-[#F0F5F6B8] odd:shadow-[rgba(100,10,140,.5)]">Box Shadow Color</div>
+        <div class="opacity-0 sm:opacity-50 md:opacity-[.67]">Opacity</div>
+        <div class="mix-blend-normal sm:mix-blend-multiply md:mix-blend-screen lg:mix-blend-overlay xl:mix-blend-darken 2xl:mix-blend-lighten dark:mix-blend-color-dodge sm:dark:mix-blend-color-burn md:dark:mix-blend-hard-light lg:dark:mix-blend-soft-light xl:dark:mix-blend-difference 2xl:dark:mix-blend-exclusion hover:mix-blend-hue first:mix-blend-saturation last:mix-blend-color focus:mix-blend-luminosity">Mix Blend Mode</div>
+        <div class="bg-blend-normal sm:bg-blend-multiply md:bg-blend-screen lg:bg-blend-overlay xl:bg-blend-darken 2xl:bg-blend-lighten dark:bg-blend-color-dodge focus:bg-blend-color-burn link:bg-blend-hard-light visited:bg-blend-soft-light hover:bg-blend-difference active:bg-blend-exclusion first:bg-blend-hue last:bg-blend-saturation odd:bg-blend-color even:bg-blend-luminosity">Background Blend Mode</div>
+      </section>`,
+    },
+    {
+      code: `
+      <section>
+        <h1>Filters</h1>
+        <div class="blur-none sm:blur md:blur-lg lg:blur-[2px]">Blur</div>
+        <div class="brightness-0 sm:brightness-100 md:brightness-[1.75]">Brightness</div>
+        <div class="contrast-0 sm:contrast-100 md:contrast-[.75]">Contrast</div>
+        <div class="drop-shadow sm:drop-shadow-none md:drop-shadow-xl lg:drop-shadow-[0_35px_35px_rgba(0,0,0,0.25)]">Drop Shadow</div>
+        <div class="grayscale sm:grayscale-0 md:grayscale-[50%]">Grayscale</div>
+        <div class="hue-rotate-0 sm:hue-rotate-90 md:-hue-rotate-15 lg:hue-rotate-[270deg] xl:hue-rotate-[-7deg] 2xl:hue-rotate-[var(--yolo)]">Hue Rotate</div>
+        <div class="invert sm:invert-0 md:invert-[.25]">Invert</div>
+        <div class="saturate-0 sm:saturate-150 md:saturate-[.25]">Saturate</div>
+        <div class="sepia-0 sm:sepia md:sepia-[.25]">Sepia</div>
+        <div class="backdrop-blur sm:backdrop-blur-lg md:backdrop-blur-[2px]">Backdrop Blur</div>
+        <div class="backdrop-brightness-50 sm:backdrop-brightness-200 md:backdrop-brightness-[1.75]">Backdrop Brightness</div>
+        <div class="backdrop-contrast-100 sm:backdrop-contrast-0 md:backdrop-contrast-[.25]">Backdrop Contrast</div>
+        <div class="backdrop-grayscale-0 sm:backdrop-grayscale md:backdrop-grayscale-[.5]">Backdrop Grayscale</div>
+        <div class="-backdrop-hue-rotate-15 sm:backdrop-hue-rotate-15 md:backdrop-hue-rotate-[15deg]">Backdrop Hue Rotate</div>
+        <div class="backdrop-invert-0 sm:backdrop-invert md:backdrop-invert-[.25]">Backdrop Invert</div>
+        <div class="backdrop-opacity-50 sm:backdrop-opacity-25 md:backdrop-opacity-[.15]">Backdrop Opacity</div>
+        <div class="backdrop-saturate-150 sm:backdrop-saturate-50 md:backdrop-saturate-[.25]">Backdrop Saturate</div>
+        <div class="backdrop-sepia sm:backdrop-sepia-0 md:backdrop-sepia-[.25]">Backdrop Sepia</div>
+      </section>`,
+    },
+    {
+      code: `
+      <section>
+        <h1>Tables</h1>
+        <div class="border-collapse md:border-separate">Border Collapse</div>
+        <div class="table-auto sm:table-fixed">Table Layout</div>
+      </section>`,
+    },
+    {
+      code: `
+      <section>
+        <h1>Transitions & Animation</h1>
+        <div class="transition-none sm:transition-all md:transition lg:transition-colors xl:transition-opacity 2xl:transition-shadow dark:transition-transform first:transition-[height]">Transition Property</div>
+        <div class="duration-100 sm:duration-200 md:duration-[2000ms]">Transition Duration</div>
+        <div class="ease-linear sm:ease-in md:ease-out lg:ease-in-out xl:ease-[cubic-bezier(0.95,0.05,0.795,0.035)]">Transition Timing Function</div>
+        <div class="delay-75 sm:delay-500 md:delay-[2000ms]">Transition Delay</div>
+        <div class="animate-none sm:animate-spin md:animate-ping lg:animate-pulse xl:animate-bounce 2xl:animate-[wiggle_1s_ease-in-out_infinite]">Animation</div>
+      </section>`,
+    },
+    {
+      code: `
+      <section>
+        <h1>Transforms</h1>
+        <div class="scale-x-50 sm:scale-y-75 md:scale-0 lg:scale-[1.7] transform-gpu">Scale</div>
+        <div class="rotate-45 sm:-rotate-90 md:rotate-[17deg]">Rotate</div>
+        <div class="translate-x-2.5 sm:translate-y-3 md:-translate-y-10 lg:translate-y-[17rem]">Translate</div>
+        <div class="skew-y-3 skew-x-6 sm:-skew-y-6 md:skew-y-[17deg] lg:skew-y-[-45deg]">Skew</div>
+        <div class="origin-center sm:origin-top md:origin-top-right lg:origin-right xl:origin-bottom-right dark:origin-bottom first:origin-bottom-left last:origin-left odd:origin-top-left even:origin-[33%_75%]">Transform Origin</div>
+      </section>`,
+    },
+    {
+      code: `
+      <section>
+        <h1>Interactivity</h1>
+        <div class="accent-emerald-500/25 sm:accent-violet-300 2xl:accent-[#50d71e] first:accent-black/50 last:accent-[#F005] even:accent-[#F0F5F6B8] odd:accent-[rgba(100,10,140,.5)]">Accent Color</div>
+        <div class="appearance-none">Appearance</div>
+        <div class="cursor-auto sm:cursor-default md:cursor-pointer lg:cursor-wait xl:cursor-text 2xl:cursor-move dark:cursor-help sm:dark:cursor-not-allowed md:dark:cursor-none lg:dark:cursor-context-menu xl:dark:cursor-progress 2xl:dark:cursor-cell dark:focus:cursor-crosshair dark:active:cursor-vertical-text dark:valid:cursor-alias first:cursor-copy last:cursor-no-drop even:cursor-grab odd:cursor-grabbing empty:cursor-all-scroll disabled:cursor-col-resize active:cursor-row-resize visited:cursor-n-resize hover:cursor-e-resize focus:cursor-s-resize link:cursor-w-resize only:cursor-ne-resize focus-visible:cursor-nw-resize disabled:cursor-se-resize checked:cursor-sw-resize required:cursor-ew-resize invalid:cursor-ns-resize valid:cursor-nesw-resize in-range:cursor-nwse-resize out-of-range:cursor-zoom-in open:cursor-zoom-out open:first:cursor-[url(hand.cur),_pointer]">Cursor</div>
+        <div class="caret-emerald-500/25 sm:caret-violet-300 2xl:caret-[#50d71e] first:caret-black/50 last:caret-[#F005] even:caret-[#F0F5F6B8] odd:caret-[rgba(100,10,140,.5)]">Caret Color</div>
+        <div class="pointer-events-none sm:pointer-events-auto">Pointer Events</div>
+        <div class="resize-none sm:resize-y md:resize-x lg:resize">Resize</div>
+        <div class="scroll-auto sm:scroll-smooth">Scroll Behavior</div>
+        <div class="scroll-m-0 sm:scroll-mx-px md:scroll-my-0.5 lg:scroll-mb-1 xl:-scroll-mr-1 2xl:scroll-m-[24rem]">Scroll Margin</div>
+        <div class="scroll-p-0 sm:scroll-px-px md:scroll-py-0.5 lg:scroll-pb-1 xl:scroll-pr-1 2xl:scroll-p-[24rem]">Scroll Padding</div>
+        <div class="snap-start sm:snap-end md:snap-center lg:snap-align-none">Scroll Snap Align</div>
+        <div class="snap-normal sm:snap-always">Scroll Snap Stop</div>
+        <div class="snap-none sm:snap-x md:snap-y lg:snap-both xl:snap-mandatory 2xl:snap-proximity">Scroll Snap Type</div>
+        <div class="touch-auto sm:touch-none md:touch-pan-x lg:touch-pan-left xl:touch-pan-right 2xl:touch-pan-y dark::touch-pan-up first:touch-pan-down last:touch-pinch-zoom focus:touch-manipulation">Touch Action</div>
+        <div class="select-none sm:select-text md:select-all lg:select-auto">User Select</div>
+        <div class="will-change-auto sm:will-change-scroll md:will-change-contents lg:will-change-transform">Will Change</div>
+      </section>`,
+    },
+    {
+      code: `
+      <section>
+        <h1>SVG</h1>
+        <div class="fill-emerald-500 sm:fill-violet-300 2xl:fill-[#50d71e] first:fill-black/50 last:fill-[#F005] even:fill-[#F0F5F6B8] odd:fill-[rgba(100,10,140,.5)]">Fill</div>
+        <div class="stroke-emerald-500 sm:stroke-violet-300 2xl:stroke-[#50d71e] first:stroke-black/50 last:stroke-[#F005] even:stroke-[#F0F5F6B8] odd:stroke-[rgba(100,10,140,.5)]">Stroke</div>
+        <div class="stroke-0 sm:stroke-1 md:stroke-2 lg:stroke-[2px]">Stroke Width</div>
+      </section>`,
+    },
+    {
+      code: `
+      <section>
+        <h1>Accessibility</h1>
+        <div class="sr-only sm:not-sr-only">Screen Readers</div>
+      </section>`,
+    },
+    {
+      code: `
+      <section>
+        <h1>Official Plugins</h1>
+        <div class=""></div>
+      </section>`,
     },
     {
       code: `<template><div class="container box-content lg:box-border max-h-24 self-end">Only Tailwind CSS classnames</div></template>`,
@@ -59,7 +363,6 @@ ruleTester.run("no-custom-classname", rule, {
       options: [
         {
           config: {
-            mode: "jit",
             prefix: "arbitrary-",
           },
         },
@@ -67,13 +370,6 @@ ruleTester.run("no-custom-classname", rule, {
     },
     {
       code: `<div class="dark:focus:hover:bg-black md:dark:disabled:focus:hover:bg-gray-400">Stackable variants</div>`,
-      options: [
-        {
-          config: {
-            mode: "jit",
-          },
-        },
-      ],
     },
     {
       code: `<div class="bg-custom-color">Using dash in custom color name</div>`,
@@ -113,14 +409,6 @@ ruleTester.run("no-custom-classname", rule, {
         },
       ],
     },
-    {
-      code: `<div className="dark">dark should be allowed in class mode</div>`,
-      options: [
-        {
-          config: { darkMode: "class" },
-        },
-      ],
-    },
     {
       code: `
       <div class="group border-indigo-500 hover:bg-white hover:shadow-lg hover:border-transparent">
@@ -162,7 +450,7 @@ ruleTester.run("no-custom-classname", rule, {
     {
       code: `
       <div class="text-red-700 border-2 border-current bg-current p-10">
-        <input class="bg-gray-500 text-white placeholder-current" placeholder="placeholder-current" />
+        <input class="bg-gray-500 text-white placeholder:text-black" placeholder="placeholder color" />
         <div class="text-yellow-400">
           <div class="divide-current divide-y-4">
             <button class="ring-2 p-2 focus:ring-current ring-offset-current ring-offset-2 outline-none">button with ringColor</button>
@@ -187,13 +475,6 @@ ruleTester.run("no-custom-classname", rule, {
         <p class="text-yellow-400 border-2 border-green-600 border-t-current p-2">border-t-current</p>
       </div>
       `,
-      options: [
-        {
-          config: {
-            mode: "jit",
-          },
-        },
-      ],
     },
     {
       code: `
@@ -215,11 +496,9 @@ ruleTester.run("no-custom-classname", rule, {
       export interface FakePropsInterface {
         readonly name?: string;
       }
-      
       function Fake({
         name = 'yolo'
       }: FakeProps) {
-      
         return (
           <>
             <h1 className={"w-12 my-custom"}>Welcome {name}</h1>
@@ -227,59 +506,28 @@ ruleTester.run("no-custom-classname", rule, {
           </>
         );
       }
-      
       export default Fake;
       `,
       parser: require.resolve("@typescript-eslint/parser"),
-      errors: [
-        {
-          messageId: "customClassnameDetected",
-          data: {
-            classname: "my-custom",
-          },
-        },
-      ],
+      errors: generateErrors("my-custom"),
+    },
+    {
+      code: `<input class="bg-gray-500 text-white placeholder-current" placeholder="placeholder-current not valid anymore" />`,
+      errors: generateErrors("placeholder-current"),
     },
     {
       code: `<div class="w-12 my-custom">my-custom is not defined in Tailwind CSS!</div>`,
-      errors: [
-        {
-          messageId: "customClassnameDetected",
-          data: {
-            classname: "my-custom",
-          },
-        },
-      ],
+      errors: generateErrors("my-custom"),
     },
     {
       code: `<template><div class="w-12 my-custom">my-custom is not defined in Tailwind CSS!</div></template>`,
-      errors: [
-        {
-          messageId: "customClassnameDetected",
-          data: {
-            classname: "my-custom",
-          },
-        },
-      ],
+      errors: generateErrors("my-custom"),
       filename: "test.vue",
       parser: require.resolve("vue-eslint-parser"),
     },
     {
       code: `<div class="hello world">2 classnames are not defined in Tailwind CSS!</div>`,
-      errors: [
-        {
-          messageId: "customClassnameDetected",
-          data: {
-            classname: "hello",
-          },
-        },
-        {
-          messageId: "customClassnameDetected",
-          data: {
-            classname: "world",
-          },
-        },
-      ],
+      errors: generateErrors("hello world"),
     },
     {
       code: `
@@ -293,20 +541,7 @@ ruleTester.run("no-custom-classname", rule, {
         flex
         lg:w-4
       \`);`,
-      errors: [
-        {
-          messageId: "customClassnameDetected",
-          data: {
-            classname: "hello",
-          },
-        },
-        {
-          messageId: "customClassnameDetected",
-          data: {
-            classname: "world",
-          },
-        },
-      ],
+      errors: generateErrors("hello world"),
     },
     {
       code: `<div class="hello tw-container tw-box-content lg_tw-box-border world">Only Tailwind CSS classnames</div>`,
@@ -315,20 +550,7 @@ ruleTester.run("no-custom-classname", rule, {
           config: { prefix: "tw-", separator: "_" },
         },
       ],
-      errors: [
-        {
-          messageId: "customClassnameDetected",
-          data: {
-            classname: "hello",
-          },
-        },
-        {
-          messageId: "customClassnameDetected",
-          data: {
-            classname: "world",
-          },
-        },
-      ],
+      errors: generateErrors("hello world"),
     },
     {
       code: `<div class="arbitrary-inset-[123px]">No arbitrary value support without JIT</div>`,
@@ -340,14 +562,7 @@ ruleTester.run("no-custom-classname", rule, {
           },
         },
       ],
-      errors: [
-        {
-          messageId: "customClassnameDetected",
-          data: {
-            classname: "arbitrary-inset-[123px]",
-          },
-        },
-      ],
+      errors: generateErrors("arbitrary-inset-[123px]"),
     },
     {
       code: `<div className={clsx(\`hello-world flex w-full\`)}>clsx</div>`,
@@ -356,14 +571,7 @@ ruleTester.run("no-custom-classname", rule, {
           callees: ["clsx"],
         },
       ],
-      errors: [
-        {
-          messageId: "customClassnameDetected",
-          data: {
-            classname: "hello-world",
-          },
-        },
-      ],
+      errors: generateErrors("hello-world"),
     },
     {
       code: `
@@ -389,26 +597,7 @@ ruleTester.run("no-custom-classname", rule, {
         }
       \`)
       `,
-      errors: [
-        {
-          messageId: "customClassnameDetected",
-          data: {
-            classname: "custom-2",
-          },
-        },
-        {
-          messageId: "customClassnameDetected",
-          data: {
-            classname: "custom-3",
-          },
-        },
-        {
-          messageId: "customClassnameDetected",
-          data: {
-            classname: "custom-1",
-          },
-        },
-      ],
+      errors: generateErrors("custom-2 custom-3 custom-1"),
     },
     {
       code: `<div className="flex skin-summer custom-2 custom-not-whitelisted">incomplete whitelist</div>`,
@@ -417,25 +606,11 @@ ruleTester.run("no-custom-classname", rule, {
           whitelist: ["skin\\-(summer|xmas)", "custom\\-[1-3]"],
         },
       ],
-      errors: [
-        {
-          messageId: "customClassnameDetected",
-          data: {
-            classname: "custom-not-whitelisted",
-          },
-        },
-      ],
+      errors: generateErrors("custom-not-whitelisted"),
     },
     {
       code: `ctl(\`\${enabled && "px-2 yo flex"}\`)`,
-      errors: [
-        {
-          messageId: "customClassnameDetected",
-          data: {
-            classname: "yo",
-          },
-        },
-      ],
+      errors: generateErrors("yo"),
     },
     {
       code: `
@@ -448,14 +623,7 @@ ruleTester.run("no-custom-classname", rule, {
         )}
       />
       `,
-      errors: [
-        {
-          messageId: "customClassnameDetected",
-          data: {
-            classname: "azerty",
-          },
-        },
-      ],
+      errors: generateErrors("azerty"),
     },
     {
       code: `<div className="dark">dark is invalid without darkMode in class</div>`,
@@ -464,14 +632,7 @@ ruleTester.run("no-custom-classname", rule, {
           config: { darkMode: "media" },
         },
       ],
-      errors: [
-        {
-          messageId: "customClassnameDetected",
-          data: {
-            classname: "dark",
-          },
-        },
-      ],
+      errors: generateErrors("dark"),
     },
     {
       code: `
@@ -486,20 +647,7 @@ ruleTester.run("no-custom-classname", rule, {
         lg:w-4
       \`;`,
       options: [{ tags: ["myTag"] }],
-      errors: [
-        {
-          messageId: "customClassnameDetected",
-          data: {
-            classname: "hello",
-          },
-        },
-        {
-          messageId: "customClassnameDetected",
-          data: {
-            classname: "world",
-          },
-        },
-      ],
+      errors: generateErrors("hello world"),
     },
     {
       code: `
@@ -526,41 +674,34 @@ ruleTester.run("no-custom-classname", rule, {
       \`
       `,
       options: [{ tags: ["myTag"] }],
-      errors: [
-        {
-          messageId: "customClassnameDetected",
-          data: {
-            classname: "custom-2",
-          },
-        },
-        {
-          messageId: "customClassnameDetected",
-          data: {
-            classname: "custom-3",
-          },
-        },
-        {
-          messageId: "customClassnameDetected",
-          data: {
-            classname: "custom-1",
-          },
-        },
-      ],
+      errors: generateErrors("custom-2 custom-3 custom-1"),
     },
     {
       code: `
       <div class="bg-red-600 p-10">
-        <p class="text-yellow-400 border-2 border-green-600 border-t-current p-2">border-t-current</p>
+        <p class="text-yellow-400 border-2 border-green-600 border-t-nada p-2">border-t-nada</p>
       </div>
       `,
-      errors: [
+      errors: generateErrors("border-t-nada"),
+    },
+    {
+      code: `<div class="z-0 sm:z-1000 md:-z-1000 lg:z-[100] xl:z-666 dark:-z-0 sm:dark:z-1000 md:dark:-z-1000 lg:dark:z-[100] xl:dark:-z-666">Z-Index</div>`,
+      options: [
         {
-          messageId: "customClassnameDetected",
-          data: {
-            classname: "border-t-current",
+          config: {
+            theme: {
+              extend: {
+                zIndex: {
+                  0: "0",
+                  "-666": "-666",
+                  1000: "1000",
+                },
+              },
+            },
           },
         },
       ],
+      errors: generateErrors("xl:z-666"),
     },
   ],
 });