-// =============================================================================
diff --git a/src/custom/_globals.scss b/src/custom/_globals.scss
deleted file mode 100644
index 90a5358..0000000
--- a/src/custom/_globals.scss
+++ /dev/null
@@ -1,152 +0,0 @@
-//
-// Custom Global Variables
-// =============================================================================
-
-
-//
-// Base
-// ----
-
-// Non-responsive website
-// $non-responsive: true !default;
-
-// Transition duration
-// $transition-duration: 150ms;
-
-// Breakpoints
-// $bp-extra-small: 30em;
-// $bp-small: 48em;
-// $bp-medium: 60em;
-// $bp-large: 70em;
-// $bp-extra-large: 80em;
-
-// Base Size (used in unitSize() for proportions)
-// $base-unit: 8;
-
-// Spacing
-// $spacing-xs: unitSize(1);
-// $spacing-s: unitSize(2);
-// $spacing-m: unitSize(3);
-// $spacing-l: unitSize(4);
-// $spacing-xl: unitSize(5);
-
-
-//
-// Grid
-// ----
-
-// Prefix for the attributes, you can use 'data-' to make your markup valid
-// $prefix: "";
-
-// Max width for container
-// $container-width: 1200px;
-
-// Gutter size in pixels (without the unit we can do math easily)
-// $gutter: 30;
-
-// Number of columns in a row
-// $num-columns: 12;
-
-// If you only want to use the mixins for "semantic grids" set this to true
-// $only-semantic: false;
-
-
-//
-// Typography
-// ----------
-
-// $font-family: "Helvetica", "Arial", sans-serif;
-// $font-family-headings: "Helvetica", "Arial", sans-serif;
-// $font-family-print: "Georgia", "Times New Roman", "Times", serif;
-// $font-family-mono: "Consolas", monospace;
-// $font-base-size: 16;
-
-
-//
-// Heading sizes
-// ----------
-
-// $h1-size: 48;
-// $h2-size: 36;
-// $h3-size: 28;
-// $h4-size: 18;
-// $h5-size: 16;
-// $h6-size: 14;
-// $giga-size: 80;
-// $mega-size: 64;
-// $kilo-size: 52;
-
-
-//
-// Color Palette
-// -------------
-
-// Colors
-// $colors: (
-// base: (
-// "primary": #4591aa,
-// "selection": #d6d6d6,
-// "lines": #e0e0e0
-// ),
-//
-// text: (
-// "primary": #666,
-// "secondary": #aaa,
-// "heading": #222,
-// "ui": white
-// ),
-//
-// background: (
-// "dark": #282E31,
-// "light": #f5f5f5,
-// "body": white
-// ),
-//
-// state: (
-// "muted": #aaa,
-// "primary": #4591aa,
-// "success": #45ca69,
-// "warning": #ffb800,
-// "error": #ca4829
-// ),
-//
-// blue: (
-// "darker": #495b61,
-// "dark": #447281,
-// "base": #4591aa,
-// "light": #5ab0cc,
-// "lighter": #74cbe8
-// ),
-//
-// green: (
-// "darker": #3b6e6e,
-// "dark": #3b8686,
-// "base": #37a1a1,
-// "light": #2dbaba,
-// "lighter": #69d1d1
-// ),
-//
-// cream: (
-// "darker": #c47858,
-// "dark": #e29372,
-// "base": #ecac91,
-// "light": #f9c2ab,
-// "lighter": #fdd5c3
-// ),
-//
-// red: (
-// "darker": #653131,
-// "dark": #b73333,
-// "base": #da3c3c,
-// "light": #f25a5a,
-// "lighter": #fa8181
-// ),
-//
-// gray: (
-// "darker": #333333,
-// "dark": #4d4d4d,
-// "base": #666666,
-// "light": #808080,
-// "lighter": #999999
-// )
-// );
diff --git a/src/index.js b/src/index.js
new file mode 100644
index 0000000..ded43e2
--- /dev/null
+++ b/src/index.js
@@ -0,0 +1,25 @@
+const postcss = require('postcss');
+const autoprefixer = require('autoprefixer');
+const nested = require('postcss-nested');
+const ifMedia = require('postcss-if-media');
+const stripComments = require('postcss-strip-inline-comments');
+const mediaMinMax = require('postcss-media-minmax');
+const customMedia = require('postcss-custom-media');
+const imports = require('postcss-easy-import');
+
+// Custom modules
+const lh = require('./lib/lh');
+const typeScale = require('./lib/type-scale');
+
+module.exports = postcss.plugin('concise', () => {
+ return postcss()
+ .use(imports())
+ .use(stripComments())
+ .use(nested())
+ .use(ifMedia())
+ .use(customMedia())
+ .use(mediaMinMax())
+ .use(lh())
+ .use(typeScale())
+ .use(autoprefixer())
+})
diff --git a/src/lib/lh.js b/src/lib/lh.js
new file mode 100644
index 0000000..99e3ff1
--- /dev/null
+++ b/src/lib/lh.js
@@ -0,0 +1,45 @@
+const postcss = require('postcss')
+
+const defaults = {
+ rootSelector: ':root',
+ unit: 'lh',
+ lineHeight: 1.5
+}
+
+module.exports = postcss.plugin('lh', (opts = defaults) => {
+ const options = Object.assign(defaults, opts)
+
+ return css => {
+ const lineHeight = getLineHeight(css, options)
+ const lhReg = new RegExp('\\d*\\.?\\d+' + options.unit, 'gi')
+
+ css.replaceValues(lhReg, { fast: options.unit }, (val) => {
+ return lhToRem(parseFloat(val), lineHeight)
+ })
+ }
+})
+
+function getLineHeight (css, opts) {
+ // Start with the default line-height
+ let lineHeight = opts.lineHeight
+
+ // Walk over all the root selectors
+ css.walkRules(opts.rootSelector, rule => {
+ // Omit the process if the selector is inside a print media query
+ if (rule.parent && rule.parent.params === 'print') return
+
+ // Walk over all the font or line-height properties
+ rule.walkDecls(/font$|line-height/, decl => {
+ // Matches {$1:font-size}{$2:unit}/{$3:line-height} when the property is 'font'
+ const fontProps = decl.value.match(/(\d+|\d+?\.\d+)(r?em|px|%)(?:\s*\/\s*)(\d+|\d+?\.\d+)\s+/) || []
+
+ lineHeight = fontProps[3] || decl.value
+ })
+ })
+
+ return lineHeight
+}
+
+function lhToRem(val, lineHeight) {
+ return parseFloat((lineHeight * val).toFixed(3)) + 'rem'
+}
diff --git a/src/lib/type-scale.js b/src/lib/type-scale.js
new file mode 100644
index 0000000..356fc07
--- /dev/null
+++ b/src/lib/type-scale.js
@@ -0,0 +1,43 @@
+const postcss = require('postcss')
+
+const defaults = {
+ rootSelector: ':root',
+ typeRatio: 1.2,
+ ratioProperty: '--type-ratio'
+}
+
+module.exports = postcss.plugin('type-scale', (opts = defaults) => {
+ const options = Object.assign(defaults, opts)
+
+ return css => {
+ const typeRatio = getTypeRatio(css, options)
+
+ css.walkDecls('font-size', decl => {
+ // Replace only if it's a unitless value
+ if (/\d+$/.test(decl.value)) decl.value = getSize(decl.value, typeRatio)
+ })
+ }
+})
+
+function getTypeRatio (css, opts) {
+ // Start with the default ratio
+ let typeRatio = opts.typeRatio
+
+ // Walk over all the root selectors
+ css.walkRules(opts.rootSelector, rule => {
+
+ // Omit the process if the selector is inside a print media query
+ if (rule.parent && rule.parent.params === 'print') return
+
+ // Walk over all the font-size rules
+ rule.walkDecls(opts.ratioProperty, decl => {
+ typeRatio = parseFloat(decl.value)
+ })
+ })
+
+ return typeRatio
+}
+
+function getSize(val, ratio) {
+ return parseFloat(Math.pow(ratio, parseInt(val) - 2).toFixed(4)) + 'rem'
+}
diff --git a/test/fixtures/customMedia/customMedia.css b/test/fixtures/customMedia/customMedia.css
new file mode 100644
index 0000000..ffd5683
--- /dev/null
+++ b/test/fixtures/customMedia/customMedia.css
@@ -0,0 +1,23 @@
+@media (max-width: 768px) {
+ .element {
+ width: 20%;
+ }
+}
+
+@media (min-width: 768px) and (max-width: 992px) {
+ .element {
+ width: 30%;
+ }
+}
+
+@media (min-width: 992px) and (max-width: 1200px) {
+ .element {
+ width: 40%;
+ }
+}
+
+@media (min-width: 1200px) {
+ .element {
+ width: 50%;
+ }
+}
diff --git a/test/fixtures/customMedia/customMedia.pcss b/test/fixtures/customMedia/customMedia.pcss
new file mode 100644
index 0000000..4bd882b
--- /dev/null
+++ b/test/fixtures/customMedia/customMedia.pcss
@@ -0,0 +1,28 @@
+@custom-media --only-extra-small (width <= 768px);
+@custom-media --only-small (768px <= width <= 992px);
+@custom-media --only-medium (992px <= width <= 1200px);
+@custom-media --only-large (width >= 1200px);
+
+@media (--only-extra-small) {
+ .element {
+ width: 20%;
+ }
+}
+
+@media (--only-small) {
+ .element {
+ width: 30%;
+ }
+}
+
+@media (--only-medium) {
+ .element {
+ width: 40%;
+ }
+}
+
+@media (--only-large) {
+ .element {
+ width: 50%;
+ }
+}
diff --git a/test/fixtures/mediaMinMax/mediaMinMax.css b/test/fixtures/mediaMinMax/mediaMinMax.css
new file mode 100644
index 0000000..90522f0
--- /dev/null
+++ b/test/fixtures/mediaMinMax/mediaMinMax.css
@@ -0,0 +1,3 @@
+@media (max-width: 30em) {
+ .element {
+ width: 50%; } }
diff --git a/test/fixtures/mediaMinMax/mediaMinMax.pcss b/test/fixtures/mediaMinMax/mediaMinMax.pcss
new file mode 100644
index 0000000..861c54d
--- /dev/null
+++ b/test/fixtures/mediaMinMax/mediaMinMax.pcss
@@ -0,0 +1,7 @@
+@custom-media --small-viewport (width <= 30em);
+
+@media (--small-viewport) {
+ .element {
+ width: 50%;
+ }
+}
diff --git a/test/fixtures/verticalRhythm/verticalRhythm.css b/test/fixtures/verticalRhythm/verticalRhythm.css
new file mode 100644
index 0000000..bba9c1c
--- /dev/null
+++ b/test/fixtures/verticalRhythm/verticalRhythm.css
@@ -0,0 +1,20 @@
+:root {
+ font: 16px / 1.5 "Helvetica", "Arial", sans-serif;
+}
+
+@media (max-width: 500px) {
+ :root {
+ font-size: 14px
+ }
+}
+
+@media print {
+ :root {
+ font: 11pt / 1.3 "Georgia", "Times New Roman", "Times", serif;
+ }
+}
+
+p {
+ margin-bottom: 1.5rem;
+ padding-top: 0.75rem;
+}
diff --git a/test/fixtures/verticalRhythm/verticalRhythm.pcss b/test/fixtures/verticalRhythm/verticalRhythm.pcss
new file mode 100644
index 0000000..5f6cad4
--- /dev/null
+++ b/test/fixtures/verticalRhythm/verticalRhythm.pcss
@@ -0,0 +1,18 @@
+:root {
+ font: 16px / 1.5 "Helvetica", "Arial", sans-serif;
+
+ @media (max-width: 500px) {
+ font-size: 14px;
+ }
+}
+
+@media print {
+ :root {
+ font: 11pt / 1.3 "Georgia", "Times New Roman", "Times", serif;
+ }
+}
+
+p {
+ margin-bottom: 1lh;
+ padding-top: .5lh;
+}
diff --git a/test/index.js b/test/index.js
new file mode 100644
index 0000000..5a6e9e1
--- /dev/null
+++ b/test/index.js
@@ -0,0 +1,46 @@
+const fs = require("fs")
+const path = require('path')
+const test = require('tape')
+const postcss = require('postcss')
+const concise = require('../src/index.js')
+
+;(() => {
+ const actual = async file => {
+ const sourcePath = path.join(__dirname,`fixtures/${file}/${file}.pcss`)
+ const fileContent = fs.readFileSync(sourcePath, 'utf8')
+
+ const result = await postcss([concise]).process(fileContent, { from: sourcePath })
+
+ return result.css.replace(/\s+/g, '')
+ }
+
+ const expected = (file) =>
+ fs.readFileSync(
+ path.join(__dirname, `fixtures/${file}/${file}.css`),
+ 'utf8'
+ ).replace(/\s+/g, '')
+
+
+ test('Media queries', async (t) => {
+ t.equal(
+ await actual('customMedia'),
+ expected('customMedia'),
+ 'Custom media queries')
+
+ t.equal(
+ await actual('mediaMinMax'),
+ expected('mediaMinMax'),
+ 'Ranges in media queries')
+
+ t.end()
+ })
+
+ test('Units', async (t) => {
+ t.equal(
+ await actual('verticalRhythm'),
+ expected('verticalRhythm'),
+ 'lh')
+
+ t.end()
+ })
+})()
diff --git a/test/test.html b/test/test.html
deleted file mode 100644
index 4004956..0000000
--- a/test/test.html
+++ /dev/null
@@ -1,980 +0,0 @@
-
-
-
-
-
-
-
- Concise CSS
-
-
-
-
-
- Giga Helper text
- Mega Helper text
- Kilo Helper text
-
-
- Heading 2 Helper text
- Heading 3 Helper text
- Heading 4 Helper text
- Heading 5 Helper text
- Heading 6 Helper text
-
- Lorem ipsum dolor sit amet , sadipscing elitr , sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.
-
- At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet . Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
-
- Left text
-
- Center text
-
- Right text
-
-
-
-
- This is a blockquote.
-
-
-
-
-
- This is a reverse blockquote.
-
- John Doe
-
-
- .class {
- background-color: #ccc;
-}
-
- .class {
- background-color: #ccc;
-}
-
-
- List Item
- List Item
- List Item
- List Item
-
- List Item
- List Item
-
-
-
-
- List Item
-
-
-
- List Item
- List Item
-
- List Item
-
- List Item
-
-
-
-
- List Item
-
-
-
- List item
- List item
- List item
-
-
-
- List item
- List item
- List item
-
-
-
- Definition
- Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.
-
- List
- Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.
-
-
-
- Definition
- Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.
-
- List
- Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 4
-
-
-
- 4
-
-
-
- 4
-
-
-
-
-
- 3
-
-
-
- 3
-
-
-
- 3
-
-
-
- 3
-
-
-
-
-
- 2
-
-
-
- 2
-
-
-
- 2
-
-
-
- 2
-
-
-
- 2
-
-
-
- 2
-
-
-
-
-
-
- Extra Small Button
- Small Button
- Default Button
- Large Button
- Extra Large Button
-
- Success Button
- Muted Button
- Error Button
- Warning Button
- Collapsible Button
-
- Bordered Button
- Bordered Success Button
- Bordered Muted Button
- Bordered Error Button
- Bordered Warning Button
-
-
-
- Prefix Button
-
-
-
- Affix Button
-
-
-
-
-
- Prefix Button
-
-
-
- Affix Button
-
-
-
- Flat Button
- Disabled Flat Button
- Disabled Button
-
- Full-width Button
-
-
-
-
- #
- First Name
- Last Name
-
-
-
-
-
- Total Users:
- 2
-
-
-
-
-
-
- 1
- John
- Doe
-
-
-
- 2
- Jane
- Doe
-
-
-
-
-
-
-
-
- #
- First Name
- Last Name
-
-
-
-
-
- 1
- John
- Doe
-
-
-
- 2
- Jane
- Doe
-
-
-
-
-
-
-
-
- #
- First Name
- Last Name
-
-
-
-
-
- 1
- John
- Doe
-
-
-
- 2
- Jane
- Doe
-
-
-
-
-
-
-
- #
- First Name
- Last Name
-
-
-
-
-
- 1
- John
- Doe
-
-
-
- 2
- Jane
- Doe
-
-
-
-
-
-
-
- #
- First Name
- Last Name
-
-
-
-
-
- 1
- John
- Doe
-
-
-
- 2
- Jane
- Doe
-
-
-
-
-
-
-
- #
- First Name
- Last Name
-
-
-
-
-
- 1
- John
- Doe
-
-
-
- 2
- Jane
- Doe
-
-
-
-
-
-
-
- #
- First Name
- Last Name
-
-
-
-
-
- 1
- John
- Doe
-
-
-
- 2
- Jane
- Doe
-
-
-
- 3
- John
- Doe
-
-
-
-
-
-
-
- #
- First Name
- Last Name
-
-
-
-
-
- 1
- John
- Doe
-
-
-
- 2
- Jane
- Doe
-
-
-
- 3
- John
- Doe
-
-
-
-
-
-
-
- Username:
-
- Password:
-
-
-
-
-
-
-
- Name:
-
-
-
-
-
-
Here is some help text
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis eget bibendum eros. Integer rhoncus pretium orci ut sagittis. Proin sollicitudin sapien eu dui imperdiet, et viverra enim dignissim.
-
-
-
-
-
-
-
-
-
-
-
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis eget bibendum eros. Integer rhoncus pretium orci ut sagittis. Proin sollicitudin sapien eu dui imperdiet, et viverra enim dignissim.
-
-
-
-
-
-
-
-
-
-
-
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis eget bibendum eros. Integer rhoncus pretium orci ut sagittis. Proin sollicitudin sapien eu dui imperdiet, et viverra enim dignissim.
-
-
-
-
-
-
-
-
-
-
-
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis eget bibendum eros. Integer rhoncus pretium orci ut sagittis. Proin sollicitudin sapien eu dui imperdiet, et viverra enim dignissim.
-
-
-
-
-
-
-
-
-
-
-
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis eget bibendum eros. Integer rhoncus pretium orci ut sagittis. Proin sollicitudin sapien eu dui imperdiet, et viverra enim dignissim.
-
-
-
-
-
-
- Open Modal
-
- Open Small Modal
-
- Open Large Modal
-
- Open Full Modal
-
- Open Flat Modal
-
- Label
- 25
-
- Top tooltip
-
- Right tooltip
-
- Bottom tooltip
-
- Left tooltip
-
- Persistent Tooltip
-
-
-
-
-
-
-
×
-
-
Warning! This is a warning for your application.
-
-
-
-
×
-
-
Error! This is an error for your application.
-
-
-
-
-
-
-
Card Title
-
-
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat.
-
-
-
-
-
-
-
-
-
-
-
Card Title
-
-
-
-
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat.
-
-
-
-
-
-
-
-
-
-
-
- Collection Item
-
-
-
- Active Collection Item
-
-
-
- Collection Item
-
-
-
-
-
-
-
-
-
-
- 50%
-
-
-
- 25%
-
-
-
- 75%
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Dropdown
-
- Home
- Account
- Settings
-
-
-
-
-
-
- Dropdown Small
-
- Home
- Account
- Settings
-
-
-
-
-
-
- Dropdown Large
-
- Home
- Account
- Settings
-
-
-
-
-
-
- Dropdown Top
-
- Home
- Account
- Settings
-
-
-
-
-
-
- Dropdown Content
-
-
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy.
-
-
-
-
-
-
- Dropdown Hover
-
-
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy.
-
-
-
-