+/// ---
+/// @requires {mixin} ex
+/// ---
+/// @param {bool} $extend (true)
+/// Extend placeholder in the current breakpoint if true,
+/// include rules if false.
+/// ---
+@mixin fluid-embed($extend: true){
+ @if $extend {
+ @include ex(fluid-embed){
+ @include fluid-embed($extend: false);
+ }
+ }
+ @else {
+ // 1. Hide items exceeding the wrapper's width.
+ // 2. Provide context for stretched elements.
+ // 3. !important to nuke inline styling.
+ @include bl-style-adjust {
+ @include mb(setting(embed-space));
+ }
+ overflow: hidden; // [1]
+ position: relative; // [2]
+
+ #{setting(embed-el)} {
+ width: 100% !important; // [3]
+ }
+ }
+}
+
+/// Give embeded elements a responsive
+/// intrinsic ratio.
+/// Should be applied to the parent element
+/// of the embedded content.
+/// E.g.
+///
<-- This class gets the mixin
+///
+///
+/// ---
+/// @requires {mixin} ex
+/// @requires {mixin} fluid-embed
+/// ---
+/// @param {bool} $extend (true)
+/// Extend placeholder in the current breakpoint if true,
+/// include rules if false.
+/// ---
+@mixin ratio-embed($extend: true){
+ @if $extend {
+ @include ex(ratio-embed) {
+ @include ratio-embed($extend: false);
+ }
+ }
+ @else {
+ // 1. Use a padding bottom to create a flexible height
+ // which is at a set ratio of the width.
+ // 2. Make sure whatever the element affected it
+ // can accept width and height propreties.
+ // 3. !important to nuke inline styling.
+ // 4. Ensure no spacing is inherited so that element
+ // is guarantied to fill it parent entierly
+ @include fluid-embed;
+ padding-bottom: (1 / setting(intrinsic-ratio)) * 100%; // [1]
+ height: 0;
+
+ #{setting(embed-el)} {
+ display: block; // [2]
+ height: 100% !important; // [3]
+ left: 0;
+ margin: 0; // [4]
+ padding: 0; // [4]
+ position: absolute;
+ top: 0;
+ }
+ }
+}
diff --git a/objects/extenders/_o.ex.island.scss b/objects/extenders/_o.ex.island.scss
new file mode 100644
index 0000000..bcb6781
--- /dev/null
+++ b/objects/extenders/_o.ex.island.scss
@@ -0,0 +1,42 @@
+// *************************************
+//
+// #ISLAND EXTENDERS
+// -> Mixins to generate and extend
+// a placeholder class for the
+// island object
+//
+////
+/// @group Layout
+////
+//
+// *************************************
+
+/// Force fluidity on embeded content.
+/// ---
+/// @requires {mixin} rex
+/// ---
+/// @param {list} $from-bps (null)
+/// list of min-width breakpoint to extend in
+/// @param {list} $to-bps (null)
+/// list of max-width breakpoint to extend in
+///
+/// @param {bool} $extend (true)
+/// Extend placeholder in the current breakpoint if true,
+/// include rules if false.
+/// ---
+@mixin island($from-bps: null, $to-bps: null, $extend: true){
+ @if $extend {
+ @include rex(island, $from-bps, $to-bps){
+ @include island($extend: false);
+ }
+ }
+ @else {
+ @include bl-style-adjust {
+ @include rem(padding, space(setting(island-space)));
+ }
+ display: block;
+ & > :last-child {
+ margin-bottom: 0;
+ }
+ }
+}
diff --git a/objects/extenders/_o.ex.lists.scss b/objects/extenders/_o.ex.lists.scss
new file mode 100644
index 0000000..f78ff1d
--- /dev/null
+++ b/objects/extenders/_o.ex.lists.scss
@@ -0,0 +1,130 @@
+// *************************************
+//
+// #List extenders
+// -> Mixins to generate and extend
+// List-related placeholder classes
+//
+////
+/// @group Lists
+////
+//
+// *************************************
+
+/// Remove indents and bullets from lists
+/// ---
+/// @requires {mixin} ex
+/// ---
+/// @param {bool} $extend (true)
+/// Extend placeholder in the current breakpoint if true,
+/// include rules if false.
+/// ---
+@mixin bare-list($extend: true){
+ @if $extend {
+ @include ex(bare-list){
+ @include bare-list($extend: false);
+ }
+ }
+ @else {
+ margin-right:0;
+ padding-right:0;
+ list-style:none;
+ }
+}
+
+/// Creates blocky lists, separated by lines.
+/// ---
+/// @requires {mixin} ex
+/// ---
+/// @param {bool} $extend (true)
+/// Extend placeholder in the current breakpoint if true,
+/// include rules if false.
+/// ---
+@mixin ui-list($extend: true){
+ @if $extend {
+ @include ex(ui-list){
+ @include ui-list($extend: false);
+ }
+ }
+ @else {
+ @include bl-style-adjust {
+ @include mb(setting(ui-list, margin-bottom));
+ @include trailing-border(setting(ui-list, border-width),
+ setting(ui-list, trailer-lines),
+ setting(ui-list, border-style));
+ }
+ }
+}
+
+
+/// Removes border and margin-bottom
+/// from last item of a ui-list.
+/// ---
+/// @requires {mixin} ex
+/// ---
+/// @param {bool} $extend (true)
+/// Extend placeholder in the current breakpoint if true,
+/// include rules if false.
+/// ---
+@mixin ui-list-last($extend: true){
+ @if $extend {
+ @include ex(ui-list-last){
+ @include ui-list-last($extend: false);
+ }
+ }
+ @else {
+ &:last-child {
+ border-bottom: 0;
+ margin-bottom: 0;
+ padding-bottom: 0
+ }
+ }
+}
+
+
+/// Make lists horizontal
+/// ---
+/// @requires {mixin} ex
+/// ---
+/// @param {bool} $extend (true)
+/// Extend placeholder in the current breakpoint if true,
+/// include rules if false.
+/// ---
+@mixin inline-list($extend: true){
+ @if $extend {
+ @include rex(inline-list) {
+ @include inline-list($extend: false);
+ }
+ }
+ @else {
+ @include bidi(padding-right, 0);
+ list-style: none;
+ > li {
+ &, > a {
+ display: inline-block;
+ }
+ }
+ }
+}
+
+
+/// Give inline-lists a separator.
+/// ---
+/// @requires {mixin} ex
+/// ---
+/// @param {bool} $extend (true)
+/// Extend placeholder in the current breakpoint if true,
+/// include rules if false.
+/// ---
+@mixin inline-list--sep($extend: true){
+ @if $extend {
+ @include rex(inline-list--sep) {
+ @include inline-list--sep($extend: false);
+ }
+ }
+ @else {
+ > li + li:before {
+ @include ms(setting(inline-list, separator-space));
+ content: quote(setting(inline-list, separator-char));
+ }
+ }
+}
diff --git a/settings/_s.settings.scss b/settings/_s.settings.scss
new file mode 100644
index 0000000..1772c43
--- /dev/null
+++ b/settings/_s.settings.scss
@@ -0,0 +1,683 @@
+// *************************************
+//
+// #SETTINGS
+// -> Default settings maps
+//
+////
+/// @group Settings
+////
+//
+// *************************************
+
+
+/// Buttons settings
+/// ---
+/// @type map
+/// ---
+/// @prop {number} btn-radius
+/// Buttons' default border radius
+/// @prop {color} btn-bg
+/// Buttons' default background color
+/// @prop {color} btn-hover
+/// Buttons' default background color on hover
+/// @prop {color} btn-color
+/// Buttons' default color
+/// @prop {number | string} btn-font-weight
+/// Buttons' default font-weight
+/// @prop {string | list | number} btn-padding.base
+/// Buttons' base padding
+/// @prop {string | list | number} btn-padding.tight
+/// Tight buttons' padding
+/// @prop {string | list | number} btn-padding.loose
+/// Loose buttons' padding
+/// @prop {string | list | number} btn-padding.inline
+/// Inline buttons' padding
+/// ---
+/// @group Settings
+/// @group UI
+/// ---
+$s-buttons: (
+ btn-radius: "",
+ btn-bg: "",
+ btn-hover: "",
+ btn-color: "",
+ btn-font-weight: "",
+ btn-padding: (
+ base: (),
+ tight: (),
+ loose: (),
+ inline: (),
+ ),
+ btn-center: false,
+ btn-full: false,
+ btn-inline: false,
+ btn-normal: false,
+ btn-tight: false,
+ btn-loose: false,
+ btn-large: false,
+ btn-huge: false,
+ btn-mega: false,
+ btn-inactive: false,
+ btn-negative: false,
+ btn-positive: false,
+ btn-sales: false,
+ btn-fb: false,
+ btn-tw: false,
+ btn-gplus: false,
+ btn-soft: false,
+ btn-hard: false,
+ btn-text: false,
+) !default;
+
+
+
+/// Color classes settings
+/// ---
+/// @type map
+/// ---
+/// @prop {map} color-classes.[name]
+/// Name of the class to generate, excluding the prefix
+/// (c- for color, bg- for background)
+/// @prop {color} color-classes.[name].color
+/// The color value to use in the generated class(es)
+/// @prop {bool} color-classes.[name].bg-class
+/// generate a background-color helper class?
+/// @prop {bool} color-classes.[name].color-class
+/// generate a color helper class?
+/// ---
+/// @group Settings
+/// @group Color
+/// ---
+$s-color-classes: (
+ color-classes: (
+ ),
+) !default;
+
+
+
+/// Embeded elements settings
+/// ---
+/// @type map
+/// ---
+/// @prop {string} embed-space
+/// The named amount of space after an embed element.
+/// Can be one of [base | double | three-quarts | half | quarter ]
+/// @prop {number} intrinsic-ratio
+/// The aspect ratio for intrinsic-ratio elements.
+/// @prop {string} embed-el
+/// The child elements that will be affected
+/// ---
+/// @group Settings
+/// ---
+$s-embed: (
+ embed-space: "",
+ intrinsic-ratio: 16/9,
+ embed-el: '> embed, > iframe, > object',
+ vid-chrome-30: false,
+) !default;
+
+
+
+/// Turn webfonts on/off
+/// ---
+/// @type map
+/// ---
+/// @prop {map} webfonts
+/// @prop {map} webfonts.[font-name]
+/// ---
+/// @group Settings
+/// @group Typography
+$s-webfonts: (
+ webfonts: (
+ ),
+) !default;
+
+
+
+/// form settings
+/// ---
+/// @prop {list} select-font-stack
+/// Font-stack to use in select elements (to fix a bug with webfonts in Chrome)
+/// @prop {color} input-props.focus
+/// The border color of form elements on focus
+/// @prop {list} input-props.focus-shadow
+/// Box-shadow values for focused inputs.
+/// @prop {string} input-props.padding
+/// Named spacing unit for the inner padding of inputs
+/// Can be one of [base | double | three-quarts | half | quarter]
+/// @prop {number} input-props.radius
+/// The base border radius of inputs.
+/// @prop {list} input-props.border-style
+/// The base border style (e.g. solid #f0f) of inputs
+/// @prop {number} input-props.width
+/// The base border width of input elements.
+/// @prop {map | bool} input-props.placeholder
+/// Generate styles according to
+/// nested keys, if not false.
+/// @prop {string} form-field-space.base
+/// The named spacing unit to use as margin bottom on base form-field wrapper elements.
+/// Can be one of [base | double | three-quarts | half | quarter]
+/// @prop {string} form-field-space.loose
+/// The named spacing unit to use as margin loose on base form-field wrapper elements.
+/// Can be one of [base | double | three-quarts | half | quarter]
+/// ---
+/// @type map
+/// ---
+/// @group Settings
+/// @group Forms
+/// ---
+$s-form: (
+ select-font-stack: (),
+ input-props: (
+ focus: "",
+ focus-shadow: "",
+ padding: "",
+ radius: "",
+ border-style: (),
+ width: "",
+ placeholder: (
+ color: "",
+ weight: "",
+ ),
+ ),
+ form-field-space: (
+ base: "",
+ loose: "",
+ ),
+
+ form-tight: false,
+ form-flush: false,
+ form-field-loose: flase,
+ form-field-flush: false,
+) !default;
+
+
+
+/// Grid settings
+/// ---
+/// @prop {number} grid-cols
+/// The maximun number of grid columns available.
+/// @prop {number} grid-gutter
+/// The basic gutter between grid__cells
+/// @prop {number} grid-gutter-t
+/// The amount of gutter between grid__cells in tight grids
+/// @prop {number} grid-gutter-xt
+/// The amount of gutter between grid__cells in x-tight grids
+/// @prop {number} grid-gutter-xxt
+/// The amount of gutter between grid__cells in xx-tight grids
+/// @prop {number} grid-gutter-l
+/// The amount of gutter between grid__cells in loose grids
+/// ---
+/// @type map
+/// ---
+/// @group Settings
+/// @group Layout
+$s-grid: (
+ grid-cols: 1,
+ grid-gutter: "",
+ grid-gutter-t: "",
+ grid-gutter-xt: "",
+ grid-gutter-xxt: "",
+ grid-gutter-l: "",
+ grid-center: false,
+ grid-left: false,
+ grid-right: false,
+ grid-rev: false,
+ grid-middle: false,
+ grid-bottom: false,
+ grid-loose: false,
+ grid-tight: false,
+ grid-xtight: false,
+ grid-xxtight: false,
+ grid-flush: false,
+ grid-rules: false,
+ grid-rules--b: false,
+
+ g-cell-center: false,
+) !default;
+
+
+
+/// Inclusion/exclusion rules for helper classes
+/// Booleans to determine which helper classes will be generated.
+/// ---
+/// @type map
+/// @group Settings
+$s-helpers: (
+ h-group: false,
+ h-vis-hidden: false,
+
+ h-hidden: (
+ base: false,
+ from-m: false,
+ from-l: false,
+ from-xl: false,
+ to-m: false,
+ to-l: false,
+ to-xl: false,
+ ),
+
+ h-shown: (
+ block: (
+ base: false,
+ from-m: false,
+ from-l: false,
+ from-xl: false,
+ to-m: false,
+ to-l: false,
+ to-xl: false,
+ ),
+ inline-block: (
+ base: false,
+ from-m: false,
+ from-l: false,
+ from-xl: false,
+ to-m: false,
+ to-l: false,
+ to-xl: false,
+ ),
+ inline: (
+ base: false,
+ from-m: false,
+ from-l: false,
+ from-xl: false,
+ to-m: false,
+ to-l: false,
+ to-xl: false,
+ ),
+ ),
+
+ legacy-display: false,
+ login-hide: false,
+ opacity: false,
+ floats: false,
+ position: false,
+ text-alignment: false,
+ borders: false,
+ h-animable: false,
+ h-ellipsis: false,
+) !default;
+
+
+
+
+/// Island object settings
+/// ---
+/// @type map
+/// ---
+/// @prop {string} island-space
+/// The named spacing unit to use for spacing Island objects
+/// Can be one of [base | three-quarts | half | quarter]
+/// @prop {string} island-loose-space
+/// The named spacing unit to use for spacing loose Island objects
+/// Can be one of [base | three-quarts | half | quarter]
+/// @prop {string} islet-space
+/// The named spacing unit to use for spacing Islet objects
+/// Can be one of [base | three-quarts | half | quarter]
+/// ---
+/// @group Settings
+/// ---
+$s-island: (
+ island-space: "",
+ island-loose-space: "",
+ islet-space: "",
+
+ island-flush: false,
+ islet: false,
+ islet-flush: false,
+ island-loose: false,
+ island-loose-flush: false,
+) !default;
+
+
+
+/// Lists settings
+/// ---
+/// @type map
+/// ---
+/// @group Settings
+/// @group Lists
+$s-lists: (
+ bare-list: false,
+ ui-list: (
+ generate: false,
+ border-width: "",
+ border-style: (),
+ trailer-lines: "",
+ margin-bottom: "",
+ ),
+ ui-list--tight: (
+ generate: false,
+ margin-bottom: "",
+ ),
+ inline-list: (
+ base: false,
+ separated: false,
+ separator-char: '|',
+ separator-space: "",
+ ),
+) !default;
+
+
+
+/// Media-object settings
+/// ---
+/// @prop {string} media-space
+/// A named spacing unit to be used for spacing
+/// media__fig from media__content
+/// Can be one of [base | double | three-quarts | half | quarter ]
+/// @prop {string} media-space-l
+/// A named spacing unit to be used for spacing
+/// media__fig from media__content on media--large objects
+/// Can be one of [base | double | three-quarts | half | quarter ]
+/// @prop {string} media-space-s
+/// A named spacing unit to be used for spacing
+/// media__fig from media__content on media--small objects
+/// Can be one of [base | double | three-quarts | half | quarter ]
+/// ---
+/// @type map
+/// ---
+/// @group Settings
+/// ---
+$s-media: (
+ media-space: "",
+ media-space-l: "",
+ media-space-s: "",
+ media-rev: false,
+ media-large: false,
+ media-small: false,
+ media-flush: false,
+ media-bottom: false,
+ media-middle: false,
+) !default;
+
+
+
+/// Modal settings
+/// ---
+/// @prop {color} modal-wrapper-color
+/// The background color of the modal-wrapper
+/// @prop {number} modal-wrapper-z
+/// @prop {color} modal-color
+/// The default background color of a modal
+/// @prop {list} modal-shadow
+/// Values for the default shadow of a modal
+/// @prop {list} modal-border
+/// Values for modals' default border
+/// @prop {number} modal-radius
+/// Modals' default border-radius
+/// ---
+/// @type map
+/// ---
+/// @group Settings
+/// ---
+$s-modal: (
+ modal-wrapper-color: "",
+ modal-wrapper-z: "",
+ modal-color: "",
+ modal-shadow: (),
+ modal-border: false,
+ modal-radius: "",
+
+ modal-fixed: false,
+) !default;
+
+
+
+/// Inclusion/exclusion settings for spacing helper classes.
+/// ---
+/// @prop {map} [type-directon]
+/// Can be on of [margin-[top|bottom|left|right|sides|ends]] or
+/// [padding-[top|bottom|left|right|sides|ends]]
+/// @prop {map} [type-directon].[breakpoint-name]
+/// determines which spacing classes will be
+/// generated for each [type-direction] at each breakpoint.
+/// Boolean keys are: `base`, `flush`, `tight`, `xtight`, `xxtight` and `loose`
+/// ---
+/// @type map
+/// ---
+/// @group Settings
+$s-spacing: (
+ // margins
+ margin-top: (
+ // name: (
+ // base: false,
+ // flush: false,
+ // tight: false,
+ // xtight: false,
+ // xxtight: false,
+ // loose: false,
+ // ),
+ ),
+
+ margin-bottom: (
+ ),
+
+ margin-left: (
+ ),
+
+ margin-ends: (
+ ),
+
+ margin-sides: (
+ ),
+
+ // ----- PADDING ----- //
+ padding-top: (
+ ),
+
+ padding-right: (
+ ),
+
+ padding-bottom: (
+ ),
+
+ padding-left: (
+ ),
+
+ padding-ends: (
+ ),
+
+ padding-sides: (
+ ),
+) !default;
+
+
+
+
+/// Typographic settings
+/// ---
+/// @type map
+/// ---
+/// @prop {bool} type.body-hack
+/// Enables/disables a hack that overrides
+/// styles from the CM's WYSIWYG editor
+/// @prop {map} type.map
+/// class-name for the `tag-name` map.
+///
+/// @prop {bool | list} type.micro-bps
+/// A list of breakpoint for which
+/// responsive modifiers of .t-micro
+/// will be generated for.
+/// @prop {bool | list} type.milli-bps
+/// A list of breakpoint for which
+/// responsive modifiers of .t-milli
+/// will be generated for.
+/// @prop {bool | list} type.zeta-bps
+/// A list of breakpoint for which
+/// responsive modifiers of .t-zeta
+/// will be generated for.
+/// @prop {bool | list} type.epsilon-bps
+/// A list of breakpoint for which
+/// responsive modifiers of .t-epsilon
+/// will be generated for.
+/// @prop {bool | list} type.delta-bps
+/// A list of breakpoint for which
+/// responsive modifiers of .t-delta
+/// will be generated for.
+/// @prop {bool | list} type.gamma-bps
+/// A list of breakpoint for which
+/// responsive modifiers of .t-gamma
+/// will be generated for.
+/// @prop {bool | list} type.beta-bps
+/// A list of breakpoint for which
+/// responsive modifiers of .t-beta
+/// will be generated for.
+/// @prop {bool | list} type.alpha-bps
+/// A list of breakpoint for which
+/// responsive modifiers of .t-alpha
+/// will be generated for.
+/// @prop {bool | list} type.kilo-bps
+/// A list of breakpoint for which
+/// responsive modifiers of .t-kilo
+/// will be generated for.
+/// @prop {bool | list} type.mega-bps
+/// A list of breakpoint for which
+/// responsive modifiers of .t-mega
+/// will be generated for.
+/// @prop {bool | list} type.giga-bps
+/// A list of breakpoint for which
+/// responsive modifiers of .t-giga
+/// will be generated for.
+///
+/// @prop {number} ellipsis.width
+/// Width of the [...] block.
+///
+/// @prop {map} ellipsis.[bp-name]
+/// Names of breakpoints for which to create
+/// line-delimited classes.
+/// @prop {bool | list} ellipsis.[bp-name].[size-name]
+/// A list of unitless numbers, each representing
+/// a hight in line numbers.
+/// e.g
+/// ```
+/// ellipsis.s.milli: (3,5)
+/// ```
+/// Will cause the generation of :
+/// `.t-milli--3lines` and `t-milli--5lines`
+/// ---
+/// @group Settings
+/// ---
+$s-typography: (
+ type: (
+ body-hack: false,
+ map: (
+ // zeta: h6,
+ ),
+ micro-bps: false,
+ milli-bps: false,
+ // list example: zeta-bps: l xl,
+ zeta-bps: false,
+ epsilon-bps: false,
+ delta-bps: false,
+ gamma-bps: false,
+ beta-bps: false,
+ alpha-bps: false,
+ kilo-bps: false,
+ mega-bps: false,
+ giga-bps: false,
+ ),
+ ellipsis-width: "",
+ ellipsis: (
+ s: (
+ micro: false,
+ // list example: milli: (2, 3,),
+ milli: false,
+ base: false,
+ zeta: false,
+ epsilon: false,
+ delta: false,
+ gamma: false,
+ beta: false,
+ alpha: false,
+ kilo: false,
+ mega: false,
+ giga: false,
+ ),
+ m: (
+ micro: false,
+ milli: false,
+ base: false,
+ zeta: false,
+ epsilon: false,
+ delta: false,
+ gamma: false,
+ beta: false,
+ alpha: false,
+ kilo: false,
+ mega: false,
+ giga: false,
+ ),
+ l: (
+ micro: false,
+ milli: false,
+ base: false,
+ zeta: false,
+ epsilon: false,
+ delta: false,
+ gamma: false,
+ beta: false,
+ alpha: false,
+ kilo: false,
+ mega: false,
+ giga: false,
+ ),
+ xl: (
+ micro: false,
+ milli: false,
+ base: false,
+ zeta: false,
+ epsilon: false,
+ delta: false,
+ gamma: false,
+ beta: false,
+ alpha: false,
+ kilo: false,
+ mega: false,
+ giga: false,
+ ),
+ ),
+) !default;
+
+
+/// Card element settings
+/// ---
+/// type map
+/// ---
+/// @prop {color} card-bg
+/// Sets the default background color of cards.
+/// @prop {color} card-hr-color
+/// Sets the default color of cards' section hr.
+/// @prop {number} card-hr-height
+/// Sets the default height of cards' section hr.
+/// @prop {list | null} card-shadow
+/// Sets the default box-shadow of cards if list.
+/// Avoid generating box-shadow property if null.
+/// @prop {list | null} card-shadow--hover
+/// Sets the default box-shadow of hovered cards if list.
+/// Avoid generating box-shadow property if null.
+/// @prop {number} card-padding
+/// Sets the default padding of cards.
+/// @prop {map} card-sizes
+/// Holds names and values of spacing modifiers to produce.
+/// @prop {string} card-sizes.name
+/// Strings to be used as suffixees in spacing modifiers.
+/// @prop {number} card-sizes.value
+/// The amount of padding to apply to a spacing modifier.
+/// ---
+$s-card: (
+ card-bg: '',
+ card-container-bg: '',
+ card-hr-color: '',
+ card-hr-height: '',
+ card-shadow: '',
+ card-shadow--hover: '',
+ card-padding: '',
+ card-sizes: (
+ // loose: space(double),
+ // tight: space(three-quarts),
+ // xtight: space(half),
+ // xxtight: space(quarter),
+ // flush: 0,
+ )
+) !default;
diff --git a/trumps/_t.helper.scss b/trumps/_t.helper.scss
new file mode 100644
index 0000000..1f61b5d
--- /dev/null
+++ b/trumps/_t.helper.scss
@@ -0,0 +1,550 @@
+// *************************************
+//
+// #Helpers
+// -> Helper classes and placeholder-selectors
+//
+// A series of helper classes to use arbitrarily.
+// Only use a helper class if an
+// element/component doesn’t already have a class
+// to which you could apply this styling, e.g.
+// if you need to float `.main-nav` left then
+// add `float:left;` to that ruleset as opposed
+// to adding the `.float--left` class to the markup.
+//
+////
+/// @group Helpers
+////
+//
+// *************************************
+
+// -------------------------------------
+// CLEARFIX
+// -------------------------------------
+
+@if ( setting(h-group) ) {
+ .h-group {
+ @include group;
+ }
+
+}
+
+
+
+
+// -------------------------------------
+// VISIBILITY
+// -------------------------------------
+
+// Hide elements visually, while remaining
+// available for screenreaders
+// ---
+@if ( setting(h-vis-hidden) ) {
+ .h-visually-hidden{
+ @include is-vis-hidden;
+ }
+ // Allow visually-hidden elements to be focusable when
+ // navigated to by adding `.is-focusable` to them in the markup
+ .is-focusable:active, .is-focusable:focus {
+ clip: auto !important;
+ height: auto !important;
+ margin: 0 !important;
+ overflow: visible !important;
+ position: static !important;
+ width: auto !important;
+ }
+}
+
+
+
+ // Hide element
+@if (setting(h-hidden, base)) {
+ .h-hidden {
+ @include is-hidden;
+ }
+}
+
+// hide element on small bp
+@if (setting(h-hidden, to-m)) {
+ @include bp($until: m) {
+ .h-hidden--s,
+ .h-hidden--to-m {
+ @include is-hidden;
+ }
+ }
+}
+
+// hide element on small and medium bps
+@if (setting(h-hidden, to-l)) {
+ @include bp($until: l) {
+ .h-hidden--s-and-m,
+ .h-hidden--to-l {
+ @include is-hidden;
+ }
+ }
+}
+
+// Hide element on medium and wider bps
+@if (setting(h-hidden, from-m)) {
+ @include bp(m) {
+ .h-hidden--m {
+ @include is-hidden;
+ }
+ }
+}
+
+// Hide element on large and wider bps
+@if (setting(h-hidden, from-l)) {
+ @include bp(l) {
+ .h-hidden--l {
+ @include is-hidden;
+ }
+ }
+}
+
+// Hide element on extra-large bps
+@if (setting(h-hidden, from-xl)) {
+ @include bp(xl) {
+ .h-hidden--xl {
+ @include is-hidden;
+ }
+ }
+}
+
+// Hide element in all bps except xl
+@if (setting(h-hidden, to-xl)) {
+ @include bp($until: xl) {
+ .h-hidden--to-xl {
+ @include is-hidden;
+ }
+ }
+}
+
+
+// Show as block
+@if ( setting(h-shown, block, base) ) {
+ .h-shown--block {
+ @include is-shown(block);
+ }
+}
+
+// show element as block on small bp
+@if (setting(h-shown, block, from-m)) {
+ @include bp(m) {
+ .h-shown--block--m {
+ @include is-shown(block);
+ }
+ }
+}
+
+// show element as block on small and medium bps
+@if (setting(h-shown, block, to-l)) {
+ @include bp($until: l) {
+ .h-shown--block--s-and-m {
+ @include is-shown(block);
+ }
+ }
+}
+
+// show element as block on medium and wider bps
+@if (setting(h-shown, block, to-m)) {
+ @include bp($until: m) {
+ .h-shown--block--s {
+ @include is-shown(block);
+ }
+ }
+}
+
+// show element as block on large and wider bps
+@if (setting(h-shown, block, from-l)) {
+ @include bp(l) {
+ .h-shown--block--l {
+ @include is-shown(block);
+ }
+ }
+}
+
+// show element as block on extra-large bps
+@if (setting(h-shown, block, from-xl)) {
+ @include bp(xl) {
+ .h-shown--block--xl {
+ @include is-shown(block);
+ }
+ }
+}
+
+// show element as block in all bps except xl
+@if (setting(h-shown, block, to-xl)) {
+ @include bp($until: xl) {
+ .h-shown--block--to-xl {
+ @include is-shown(block);
+ }
+ }
+}
+
+
+// Show as inline-block
+@if ( setting(h-shown, inline-block, base) ) {
+ .h-shown--inline-block {
+ @include is-shown(inline-block);
+ }
+}
+
+// show element as inline-block on small bp
+@if (setting(h-shown, inline-block, from-m)) {
+ @include bp(m) {
+ .h-shown--inline-block--m {
+ @include is-shown(inline-block);
+ }
+ }
+}
+
+// show element as inline-block on small and medium bps
+@if (setting(h-shown, inline-block, to-l)) {
+ @include bp($until: l) {
+ .h-shown--inline-block--s-and-m {
+ @include is-shown(inline-block);
+ }
+ }
+}
+
+// show element as inline-block on medium and wider bps
+@if (setting(h-shown, inline-block, to-m)) {
+ @include bp($until: m) {
+ .h-shown--inline-block--s {
+ @include is-shown(inline-block);
+ }
+ }
+}
+
+// show element as inline-block on large and wider bps
+@if (setting(h-shown, inline-block, from-l)) {
+ @include bp(l) {
+ .h-shown--inline-block--l {
+ @include is-shown(inline-block);
+ }
+ }
+}
+
+// show element as inline-block on extra-large bps
+@if (setting(h-shown, inline-block, from-xl)) {
+ @include bp(xl) {
+ .h-shown--inline-block--xl {
+ @include is-shown(inline-block);
+ }
+ }
+}
+
+// show element as inline-block in all bps except xl
+@if (setting(h-shown, inline-block, to-xl)) {
+ @include bp($until: xl) {
+ .h-shown--inline-block--to-xl {
+ @include is-shown(inline-block);
+ }
+ }
+}
+
+
+// Show as inline
+@if ( setting(h-shown, inline, base) ) {
+ .h-shown--inline {
+ @include is-shown(inline);
+ }
+}
+
+// show element as inline on small bp
+@if (setting(h-shown, inline, from-m)) {
+ @include bp(m) {
+ .h-shown--inline--m {
+ @include is-shown(inline);
+ }
+ }
+}
+
+// show element as inline on small and medium bps
+@if (setting(h-shown, inline, to-l)) {
+ @include bp($until: l) {
+ .h-shown--inline--s-and-m {
+ @include is-shown(inline);
+ }
+ }
+}
+
+// show element as inline on medium and wider bps
+@if (setting(h-shown, inline, to-m)) {
+ @include bp($until: m) {
+ .h-shown--inline--s {
+ @include is-shown(inline);
+ }
+ }
+}
+
+// show element as inline on large and wider bps
+@if (setting(h-shown, inline, from-l)) {
+ @include bp(l) {
+ .h-shown--inline--l {
+ @include is-shown(inline);
+ }
+ }
+}
+
+// show element as inline on extra-large bps
+@if (setting(h-shown, inline, from-xl)) {
+ @include bp(xl) {
+ .h-shown--inline--xl {
+ @include is-shown(inline);
+ }
+ }
+}
+
+// show element as inline in all bps except xl
+@if (setting(h-shown, inline, to-xl)) {
+ @include bp($until: xl) {
+ .h-shown--inline--to-xl {
+ @include is-shown(inline);
+ }
+ }
+}
+
+
+
+// ----- Legacy methods ----- //
+@if ( setting(legacy-display) ) {
+ // Display inline
+ .h-di {
+ @include is-shown(inline);
+ }
+
+ // Display block
+ .h-db {
+ @include is-shown(block);
+ }
+
+ // Display inline-block
+ .h-dib {
+ @include is-shown(inline-block);
+ }
+
+ // Display none
+ .h-dn,
+ .hide {
+ @include is-hidden;
+ }
+}
+
+
+
+// ----- Hide on login ----- //
+@if ( setting(login-hide) ) {
+ .h-login-hidden {
+ .user-paying &,
+ .user-registered & {
+ @include is-hidden;
+ }
+ }
+}
+
+
+
+// ----- Opacity ----- //
+@if ( setting(opacity) ) {
+ .h-op0 {
+ opacity: 0;
+ }
+
+ .h-op1 {
+ opacity: 1;
+ }
+}
+
+
+
+
+// -------------------------------------
+// FLOATS
+// -------------------------------------
+
+@if ( setting(floats) ) {
+ .h-fl {
+ float: left;
+ }
+
+ .h-fr {
+ float: right;
+ }
+
+ .h-cb {
+ clear: both;
+ }
+}
+
+
+
+
+
+// -------------------------------------
+// $POSITION
+// -------------------------------------
+@if ( setting(position) ) {
+ .h-posr {
+ position: relative !important;
+ }
+
+ .h-posa {
+ position: absolute !important;
+ }
+
+ .h-posf {
+ position: fixed !important;
+ transform: translateZ(0);
+ }
+}
+
+
+
+
+
+// -------------------------------------
+// TEXT ALIGNMENT
+// -------------------------------------
+
+@if ( setting(text-alignment) ) {
+ .h-tal{
+ text-align: left;
+ }
+
+ .h-tar{
+ text-align: right;
+ }
+
+ .h-tac{
+ text-align: center;
+ }
+}
+
+
+
+
+
+// -------------------------------------
+// BORDERS
+// -------------------------------------
+@if ( setting(borders) ) {
+ .h-bl{
+ border-left: get($ui, border, default);
+ }
+
+ .h-br{
+ border-right: get($ui, border, default);
+ }
+
+ .h-brad{
+ border-radius: radius(base);
+ }
+}
+
+
+
+
+
+// -------------------------------------
+// Animations
+// -------------------------------------
+
+@if ( setting(h-animable) ) {
+ .h-animable {
+ @include is-animable;
+ }
+}
+
+
+// Vertical / Horizontal Sliders
+@if ( setting(slide-anim) ) {
+ %h-slider{
+ overflow: hidden;
+ visibility: visible;
+ transition: all anim(duration, base) anim(easing, swift-out);
+ }
+
+ // Slide an element in and out vertically
+ .h-slider-v{
+ @extend %h-slider;
+
+ &.h-slider--closed{
+ max-height: 0;
+ }
+ }
+
+ // Slide an element in and out horizontally
+ .h-slider-h{
+ @extend %h-slider;
+
+ &.h-slider--closed{
+ max-width: 0;
+ }
+ }
+
+ .h-slider--closed{
+ border-width: 0;
+ margin: 0;
+ overflow: hidden;
+ padding: 0;
+ visibility: hidden;
+ }
+}
+
+
+
+
+// -------------------------------------
+// MISC
+// -------------------------------------
+
+// Multiline ellipsis
+// Needs an accompanying line number delimiter class
+@if ( setting(h-ellipsis) ) {
+ .h-ellipsis {
+ overflow: hidden;
+ &:before {
+ @include bidi(float, right);
+ @include rem(width, space(quarter));
+ content:"";
+ }
+
+ > *:first-child {
+ @include bidi(margin-right, -1 * space(quarter));
+ @include bidi(float, left);
+ width: 100%;
+ }
+
+ &:after {
+ @include bidi(padding-left, space(quarter));
+ @include bidi(float, left);
+ @include bidi(text-align, left);
+ @include bidi(background,
+ linear-gradient(
+ to left,
+ rgba(color(bg), 0),
+ color(bg) 50%, color(bg)));
+ @include bidi(right, 100%);
+ box-sizing: content-box;
+ content: "\02026";
+ position: relative;
+ width: setting(ellipsis-width);
+ }
+ }
+}
+
+ .blink {
+ animation: blink 1s steps(5, start) infinite;
+ -webkit-animation: blink 1s steps(5, start) infinite;
+ }
+ @keyframes blink {
+ to {
+ visibility: hidden;
+ }
+ }
+ @-webkit-keyframes blink {
+ to {
+ visibility: hidden;
+ }
+ }
diff --git a/trumps/_t.spacing.scss b/trumps/_t.spacing.scss
new file mode 100644
index 0000000..57814f1
--- /dev/null
+++ b/trumps/_t.spacing.scss
@@ -0,0 +1,111 @@
+// *************************************
+//
+// #SPACING
+// -> Margin and padding helper classes
+//
+// .h-(m|p)(t|r|b|l|e|s)--[spacing modifiers]--[breakpoint]
+// Meaning:
+// (margin/padding)
+// (top/right/bottom/left/vertical ends/ horizontal sides)
+// [tight/xtight/xxtight/loose]
+// [breakpoint-name]
+//
+////
+/// @group Layout
+////
+//
+// *************************************
+
+// -------------------------------------
+// SETUP
+// -------------------------------------
+
+/// Bi-dimensional list of spacer names
+/// and values to iterate over
+/// ---
+/// @type list
+/// ---
+/// @access private
+/// ---
+$private-spacing-helpers-modifiers: base base,
+ flush flush,
+ tight three-quarts,
+ xtight half,
+ xxtight quarter,
+ loose double;
+
+/// private mixin to fire up the correct spacer mixin
+/// inside the spacing-helprs mixin.
+/// ---
+/// @see spacing-helpers.
+/// ---
+/// @access private
+/// ---
+@mixin private-spacing-helpers-util ($type, $side, $amount, $extend: true) {
+ @if $type == margin {
+ @if $side == top { @include mt($amount, $extend); }
+ @else if $side == right { @include mr($amount, $extend); }
+ @else if $side == bottom { @include mb($amount, $extend); }
+ @else if $side == left { @include ml($amount, $extend); }
+ @else if $side == ends { @include me($amount, $extend); }
+ @else if $side == sides { @include ms($amount, $extend); }
+ }
+ @if $type == padding {
+ @if $side == top { @include pt($amount, $extend); }
+ @else if $side == right { @include pr($amount, $extend); }
+ @else if $side == bottom { @include pb($amount, $extend); }
+ @else if $side == left { @include pl($amount, $extend); }
+ @else if $side == ends { @include pe($amount, $extend); }
+ @else if $side == sides { @include ps($amount, $extend); }
+ }
+}
+
+/// Generates spacer classes (padding and margin)
+/// defined in $settings.
+/// Can generate:
+/// .h-(m|p)(t|r|b|l|e|s)--[spacing modifiers]--[breakpoint]
+/// Meaning:
+/// (margin/padding)
+/// (top/right/bottom/left/vertical ends/ horizontal sides)
+/// [tight/xtight/xxtight/loose]
+/// [breakpoint-name]
+/// ---
+/// @requires {variables} $settings
+/// ---
+/// @group Layout
+/// ---
+@mixin spacing-helpers($extend: true) {
+
+ $sides: top, right, bottom, left, ends, sides;
+
+ @each $type in margin, padding {
+ @each $side in $sides {
+ @each $bp, $width in $bp-breakpoints {
+ $resp: if( $bp == s, false, true );
+ @each $name, $amount in $private-spacing-helpers-modifiers {
+ @if ( setting($type+'-'+$side, $bp, $name) ) {
+ $selector: if( $type == margin, h-m, h-p );
+ $selector: $selector + str-slice($side, 1,1);
+ $selector: if($name == base, $selector, $selector+"--"+$name);
+ @if $resp {
+ @include bp($bp) {
+ $selector: if( $bp == s, $selector, $selector+"--"+$bp);
+ .#{$selector} {
+ @include private-spacing-helpers-util($type, $side, $amount, $extend);
+ }
+ }
+ }
+ @else {
+ .#{$selector} {
+ @include bl-style-adjust {
+ @include private-spacing-helpers-util($type, $side, $amount);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
diff --git a/utils/_u.bidisass.scss b/utils/_u.bidisass.scss
new file mode 100644
index 0000000..055ea9f
--- /dev/null
+++ b/utils/_u.bidisass.scss
@@ -0,0 +1,404 @@
+// *************************************
+//
+// #BidiSASS
+// -> Painless bidirectional style authoring
+//
+////
+/// @group BidiSASS
+////
+//
+// *************************************
+
+
+
+// -------------------------------------
+// SETTINGS
+// -------------------------------------
+
+/// Settings for the bidiSASS mixins and functions
+/// can be dynamically changed using the bidi() function.
+/// e.g:
+/// $bidi-settings: bidi(output, both);
+/// $bidi-settings: bidi(rem, if($rhythm-unit == rem, true, false));
+/// $bidi-settings: bidi(parent-selector, ".is-" + bidi-opposite(bidi(base)) );
+/// ---
+/// @prop {string} base (ltr)
+/// The base direction in which styles are authored.
+/// Can be [rtl | ltr]
+/// @prop {string} output (base)
+/// can be one of [base \ ltr \ rtl \ both]
+/// @prop {string | null} parent-selector (null)
+/// The selector used for qualifying opposite direction styles.
+/// If 'null', [dir = {rtl | ltr]
+/// @prop {bool} rem (true);
+/// Convert values to rem
+/// ---
+/// @type map
+$bidi-settings: (
+ base: ltr,
+ output: base,
+ parent-selector: null,
+ rem: true,
+) !default;
+
+
+
+
+
+// -------------------------------------
+// ASSIGN PROPERTIES FOR REVERSAL
+// -------------------------------------
+
+/// Assign properties to be evaluated for reversal.
+///
+/// Register styles for later reversal if
+/// `$bidi-settings.output` is set to `both`
+///
+/// Reverse styles if `$bidi-settings.output` is set
+/// to the opposite of `$bidi-settings.base`
+/// ---
+/// @param {string} $property
+/// @param {string | number | list | color} $values
+/// @param {string} $mq ('all')
+/// The media query in which the property lives cannot be automatically
+/// evaluated, so must be explicitly specified.
+/// ---
+/// @requires {function} bidi-is
+/// @requires {function} bidi-output
+/// @requires {function} bidi-opposite
+/// @requires {function} bidi-str-replace
+/// ---
+/// @example scss
+/// .selector {
+/// @include bidi(padding-left, 6px);
+/// }
+///
+/// @example css - CSS Output
+/// .selector {
+/// padding-left: 6px;
+/// }
+/// // Or
+/// .selector {
+/// padding-right: 6px;
+/// }
+/// ---
+@mixin bidi($property, $values, $mq: 'all', $rem: bidi(rem)) {
+ // Make sure we have a property and values to work with
+ @if ( $values == null ) {
+ @error "bidiSASS needs values to work with. I'm getting `null` for #{$property}";
+ }
+ @else if ( $property == null ) {
+ @error "You've given me #{$values} as `$values` to work with, but `$property` is `null`. There's nothing bidiSASS can do for you without a property. "
+ }
+ // Make sure $bidi-private exists on the global scope
+ @if not global-variable-exists(bidi-private){
+ $bidi-private: () !global;
+ }
+
+ // Make sure a separate nested map for each media query
+ // exists inside $bidi-private on the global scope
+ @if not map-has-key($bidi-private, $mq) {
+ $bidi-private: map-merge($bidi-private, (quote(#{$mq}): ()) );
+ }
+
+ // Stringify gradient $values
+ @if ( str-index($values+"", gradient) ) {
+ $values: unquote($values+"");
+ }
+
+ // Save the original property and values.
+ $_property: $property;
+ $_values: $values;
+
+ // Print styles if bidi-output() returns 'base' or 'both'
+ @if bidi-is(bidi-output(), base both) {
+ @include bidi-print-private($property, $values, $rem);
+ }
+
+ // ----- PROPERTY / VALUE CHANGES ----- //
+ // If $values is a list of four items,
+ // switch between left (#2) and right (#4).
+ @if length($values) == 4 {
+ $values: nth($values, 1) nth($values, 4) nth($values, 3) nth($values, 2);
+ }
+ // If '$property' contains 'left' change it to 'right'.
+ @else if (str-index($property, 'left')) {
+ $property: bidi-str-replace($property, left, right);
+ }
+ // If '$property' contains 'right' change it to 'left'.
+ @else if (str-index($property, 'right')) {
+ $property: bidi-str-replace($property, right, left);
+ }
+ // If '$values' contains 'left' change it to 'right'.
+ @else if (str-index($values, 'left')) {
+ $values: bidi-str-replace($values, left, right);
+ }
+ // If '$values' contains 'right' change it to 'left'.
+ @else if (str-index($values, 'right')) {
+ $values: bidi-str-replace($values, right, left);
+ }
+ // Return opposite of $values if it is left, right, rtl or ltr
+ @else if bidi-is($values, rtl ltr left right) {
+ $values: bidi-opposite($values);
+ }
+ @else {
+ @include bidi-print-private($property, $values, $rem);
+ @warn "#{$property}: #{$values} in ${$selector} isn't direction related. Leaving it as is"
+ }
+
+ // ----- RECORD CHANGES ----- //
+ @if ($property != $_property) or ($values != $_values) {
+ // Print styles if bidi-output() returns 'reverse'
+ @if bidi-output() == reverse {
+ @include bidi-print-private($property, $values, $rem);
+ }
+
+ // Ensure the current media-query has its own sub-map
+ @if not map-has-key($bidi-private, $mq) {
+ $mq-map: ($mq: () );
+ $bidi-private: map-merge($bidi-private, $mq-map) !global;
+ }
+
+ $mq: quote($mq);
+ // Extract the selector from the context the mixin was executed in.
+ $selector: selector-parse(&)+"";
+ // Create (property: value) map.
+ $properties: ($property: $values);
+
+ // Backup data currently stored in the media-query sub-map
+ $mq-current: map-get($bidi-private, $mq);
+
+ // If there is already data stored for the current selector
+ // in the current media-query, merge the new property with the old ones
+ @if map-has-key($mq-current, $selector) {
+ $selector-current: map-get($mq-current, $selector);
+ $properties: map-merge($selector-current, $properties);
+ }
+
+ $selector: ($selector: $properties);
+ $mq-current: map-merge($mq-current, $selector);
+
+ $bidi-private: map-merge($bidi-private, ($mq: $mq-current) ) !global;
+ }
+}
+
+
+
+
+
+// -------------------------------------
+// DUPLICATE STYLES IN OPPOSITE DIRECTION
+// -------------------------------------
+
+/// Print reversed styles if both original and reversed are required.
+/// ---
+/// @requires {function} bidi
+/// @requires {function} bidi-output
+/// @requires {function} bidi-opposite
+/// @requires {variable} $bidi-settings
+/// ---
+/// @param {string} $mq ("all")
+/// The media query in which the mixin is executed in.
+/// Defaults to printing styles @at-root.
+@mixin bidi-print($mq: "all", $rem: bidi(rem)) {
+
+ // Check if style manipulation is required
+ @if bidi-output() == both and map-get($bidi-private, $mq) {
+
+ // Set-up parent selector.
+ $dir: bidi-opposite(bidi(base));
+ %bidi-dir--#{$mq} {}
+ [dir = #{$dir}] {
+ @extend %bidi-dir--#{$mq} !optional;
+ }
+ // Initialize variable.
+ $bidi-parent-selector: "";
+ // Populate variable.
+ @if bidi(parent-selector) {
+ $bidi-parent-selector: bidi(parent-selector);
+ }
+ @else {
+ $bidi-parent-selector: "%bidi-dir--#{$mq}";
+ }
+
+ #{$bidi-parent-selector}{
+ $bidi-mq-selectors: map-get($bidi-private, $mq);
+ @each $selector, $properties in $bidi-mq-selectors {
+ #{$selector} {
+ $properties: map-get($bidi-mq-selectors, $selector);
+ @each $property, $values in $properties {
+ @include bidi-print-private($property, $values, $rem: bidi(rem));
+ }
+ }
+ }
+ }
+
+ }
+}
+
+
+
+
+// ----- Utility Mixin ----- //
+
+/// Does the actual printing of styles
+/// ---
+/// @access private
+/// ---
+@mixin bidi-print-private($property, $values, $rem) {
+ // Check if the rem mixin exists, and use it to convert
+ // values to rem if `$rem` is indeed `rem`
+ @if mixin-exists(rem) and $rem {
+ @include rem($property, $values)
+ }
+ // else, print value as provided.
+ @else {
+ #{$property}: $values;
+ }
+}
+
+
+
+
+
+// -------------------------------------
+// UTILITY FUNCTIONS
+// -------------------------------------
+
+/// Check if a `$value` is any
+/// of the words provided in a `$list`
+/// ---
+/// @param {string} $value
+/// The string to check for.
+/// @param {list} $list
+/// The list of words to check for the string in.
+/// ---
+/// @returns {bool}
+/// ---
+@function bidi-is($value, $list) {
+ @return not not index($list, $value);
+}
+
+
+/// Find and replace a substring inside a string
+/// ---
+/// @param {string} $string
+/// The string to search in
+/// @param {string} $old
+/// The substring to search for
+/// @param {string} $new
+/// The substring to replace with
+/// @param {bool} $case-sensitive
+/// ---
+/// @link http://hugogiraudel.com/2014/01/13/sass-string-replacement-function/
+/// Based on Hugo Giraudel's string replacement function.
+/// ---
+@function bidi-str-replace($string, $old, $new: "", $case-sensitive: true) {
+ // Check that all arguments are strings
+ @if type-of($string) != string {
+ @warn "#{$string} is not a string.";
+ @return $string;
+ }
+ @else if type-of($old) != string {
+ @warn "#{$old} is not a string.";
+ @return $string;
+ }
+ @else if type-of($new) != string {
+ @warn "#{$new} is not a string.";
+ @return $string;
+ }
+
+ // Prevent infinite recursion
+ @if str-index($new, $old) != null {
+ @warn "#{old} contains #{new}, which will cause infinite recursion. Abort ship";
+ @return $string;
+ }
+
+ // Handle case sensitivity
+ $index: if(not $case-sensitive,
+ str-index(to-lower-case($string), to-lower-case($old)),
+ str-index($string, $old));
+
+ @if $index != null and $new != $old {
+ $new-string: quote(str-slice($string, 1, $index - 1));
+ @for $i from $index through str-length($string) {
+ @if $i < $index or $i >= $index + str-length($old) {
+ $new-string: $new-string + str-slice($string, $i, $i);
+ }
+ }
+ @return quote(bidi-str-replace(str-insert($new-string, $new, $index), $old, $new, $case-sensitive));
+ }
+
+ @return $string;
+}
+
+
+/// Get or set bidi settings
+/// ---
+/// @requires {map} $bidi-settings
+/// ---
+/// @param {string} $key
+/// @param {string | null} $value
+/// Used for setting
+/// ---
+/// @return {string | map}
+/// ---
+@function bidi($key, $value: null){
+ // Getter
+ @if not $value { @return map-get($bidi-settings, $key); }
+ // Setter
+ @else { @return map-merge($bidi-settings, ($key: $value)); }
+}
+
+
+/// Return the opposite of a direction.
+/// ---
+/// @requires {function} bidi-is
+/// ---
+/// @param {string} $direction
+/// One of [left, right, ltr, rtl]
+/// ---
+/// @throws '#{$direction} is not a horizontal direction. Could not convert.'
+/// ---
+/// @returns {string}
+/// Returns the opposite of the direction provided in the argument.
+/// ---
+@function bidi-opposite($direction) {
+ $opposites: (left: right, right: left, ltr: rtl, rtl: ltr);
+ @if bidi-is($direction, left right ltr rtl){
+ @return map-get($opposites, $direction);
+ }
+ @else {
+ @warn '#{$direction} is not a horizontal direction. Could not convert.';
+ @return $direction;
+ }
+}
+
+
+/// Check if style manipulation is required
+/// ---
+/// @requires {function} bidi
+/// @requires {function} bidi-is
+/// ---
+/// @throws #{bidi(output)} is an illegal value for `$bidi-settings.output`. Allowed valued are [base | both | rtl | ltr]
+/// ---
+/// @returns {string}
+/// ---
+/// @access private
+/// ---
+@function bidi-output(){
+ @if bidi-is(bidi(output), base both rtl ltr) {
+ @if bidi-is(bidi(output), bidi(base) base) {
+ @return 'base';
+ }
+ @else if bidi(output) == both {
+ @return 'both';
+ }
+ @else {
+ @return 'reverse';
+ }
+ }
+ @else {
+ @warn '#{bidi(output)} is an illegal value for `$bidi-settings.output`. Allowed valued are [base | both | rtl | ltr]'
+ }
+}
diff --git a/utils/_u.bp.scss b/utils/_u.bp.scss
new file mode 100644
index 0000000..2d7da6f
--- /dev/null
+++ b/utils/_u.bp.scss
@@ -0,0 +1,482 @@
+// *************************************
+//
+// #MEDIA-QUERIES
+// -> Media-queries related mixins and functions.
+//
+////
+/// @group Media-queries
+////
+//
+// *************************************
+
+
+// -------------------------------------
+// SETTINGS AND VARIABLES
+// -------------------------------------
+
+/// Determine weather media queries are active or not.
+/// If false only non queried styles and the defined
+/// fallback query will be generated.
+/// ---
+/// @type bool
+$bp-responsive: true !default;
+
+/// Breakpoints' names and min-width
+/// ---
+/// @prop {number} s - small bp
+/// @prop {number} m - medium bp
+/// @prop {number} l - large bp
+/// @prop {number} xl - extra-large bp
+/// ---
+/// @type map
+$bp-breakpoints: (
+ s: 0px,
+ m: 728px,
+ l: 1009px,
+ xl: 1150px,
+) !default;
+
+/// The default breakpoint
+/// ---
+/// @type string
+$bp-default-breakpoint: s !default;
+
+/// The current breakpoint
+/// ---
+/// @type string
+$bp-current-breakpoint: $bp-default-breakpoint;
+
+/// Common custom rules for media queries
+/// ---
+/// @type map
+$bp-custome: () !default;
+
+/// Fallbak breakpoint for browsers without media-queries support.
+/// ---
+/// @type string
+$bp-static-breakpoint: l !default;
+
+/// Display currently active breakpoint in the top right corner of the site.
+/// To enable, add the breakpoints specified in $bp-breakpoints
+/// to this list, ordered by width, e.g. (s, m, l).
+/// ---
+/// @type list
+$bp-show-breakpoints: () !default;
+
+
+
+
+
+// -------------------------------------
+// FUNCTIONS
+// -------------------------------------
+
+/// Convert Pixel values to ems, based on the browser's default font-size.
+/// ---
+/// @param {number} $px
+/// pixel values to be converted to ems.
+/// @param {number} $base-context (16px)
+/// The browser's assumed font size.
+/// ---
+/// @returns {number}
+/// Converts the number provided in $px to ems according th the context from
+/// $base-context
+/// ---
+/// @throws Warning: Value of `$px` must be specified in pixels. Trying to convert.
+/// @throws Error: Value of `$px` must be in pixels
+@function bp-px2em($px, $base-context: 16px) {
+ @if (unitless($px)) {
+ @warn "Value of `$px` must be specified in pixels. Trying to convert.";
+ @return bp-px2em($px + 0px); // That may fail.
+ } @else if (unit($px) != px) {
+ @error "$px must be in pixels"
+ }
+ @return ($px / $base-context) * 1em;
+}
+
+
+/// Get values of named breakpoint
+/// ---
+/// @param {string} $name
+/// Name of a breakpoint defined in `$bp-breakpoints`
+/// ---
+/// @requires {function} get
+///
+/// @requires {variable} $bp-breakpoints
+/// ---
+/// @returns {number}
+/// ---
+/// @throws The breakpoint you defined does not exist in `$bp-breakpoints`
+/// ---
+@function bp-get-breakpoint-width($name) {
+ @if(map-has-key($bp-breakpoints, $name)) {
+ @return get($bp-breakpoints, $name);
+ } @else {
+ @error $name + " does not exist in `$bp-breakpoints`";
+ }
+}
+
+
+/// Add a breakpoint
+/// ---
+/// @param {string} $name
+/// Name of the new breakpoint
+///
+/// @param {number} $breakpoint
+/// Breakpoint's min-width, in pixels (e.g. '1200px')
+/// ---
+/// @requires {map} $bp-breakpoints
+/// ---
+/// @example scss
+/// $bp-breakpoints: bp-add-breakpoint(tvscreen, 1920px);
+/// ---
+/// @returns {map}
+/// New breakpoint map
+
+@function bp-add-breakpoint($name, $breakpoint) {
+ $new-breakpoint: (#{$name}: $breakpoint);
+ @return map-merge($bp-breakpoints, $new-breakpoint);
+}
+
+
+
+
+
+// -------------------------------------
+// MIXINS
+// -------------------------------------
+
+/// Output Media Queries
+/// ---
+/// @param {string} $from
+/// Defines min-width. Inclusive.
+///
+/// @param {string} $until
+/// Defines max-width. Exclusive.
+///
+/// @param {string} $and
+/// Defines custom rules (e.g. orientation: landscape)
+///
+/// @param {string} $to
+/// DEPRECATED. Same as `$until`
+/// ---
+/// @requires {variable} $bp-responsive
+/// media-queries on and off.
+///
+/// @requires {variable} $bp-static-breakpoint
+///
+/// @requires {map} $bp-breakpoints
+/// Breakpoints' names and min-widths
+///
+/// @requires {map} $bp-custome
+/// Common custom rules
+///
+/// @requires {map} $bl-baseline-context
+/// Font-size and line-height values for responsive baselines.
+///
+/// @requires {function} bp-px2em
+/// Converts pixel values to ems
+///
+/// @requires {function} bp-get-breakpoint-width
+///
+/// @requires {mixin} adjust-baseline
+/// Sets contextual baselines inside media queries.
+/// ---
+/// @throws '$to is deprecated, you should use $until instead'
+///
+/// @throws 'You are using $until and $to together. $to is deprecated and has been ignored. You should/ remove it.'
+///
+/// @throws 'No static styles will be output, $static-breakpoint-width is not in $bp-breakpoints'
+/// ---
+/// @example scss
+/// .el{
+/// @include bp(s){
+/// color:blue;
+/// }
+/// @include bp(m){
+/// color:pink;
+/// }
+/// @include bp($until: l){
+/// color:lime;
+/// }
+/// @include bp(l,xl){
+/// color:teal;
+/// }
+/// @include bp($and: '(-webkit-min-device-pixel-ratio: 1.5), (min-resolution: 1.5dppx)'){
+/// color:red;
+/// }
+/// }
+///
+/// @example css - CSS Output
+/// .el {
+/// color: blue;
+/// }
+/// @media all and (min-width: 37.5em) {
+/// .el {
+/// color: pink;
+/// }
+/// }
+/// @media all and (min-width: 37.5em) and (max-width: 62.49em) {
+/// .el {
+/// color: lime;
+/// }
+/// }
+/// @media all and (min-width: 62.5em) and (max-width: 71.865em) {
+/// .el {
+/// color: teal;
+/// }
+/// }
+/// @media all and (-webkit-min-device-pixel-ratio: 1.5), (min-resolution: 1.5dppx) {
+/// .el {
+/// color: red;
+/// }
+/// }
+@mixin bp($from: false, $until: false, $and: false, $to: null) {
+
+ // Deprecate use of $to for $until, because $until implies the exclusive
+ // boundary that is in place, whereas $to is unclear.
+ @if $to {
+ @if not $until {
+ $until: $to;
+ } @else {
+ @warn 'You are using $until and $to together. Using the value in $until';
+ }
+ }
+
+ @if ( $from == s-and-m ) {
+ @warn '#DEPRECATION WARNING # s-and-m is obsolete, and will be deprecated in future versions on the bp mixin. Use `$until: l` instead.';
+ @if ( not $until ) {
+ $from: false;
+ $until: l;
+ }
+ }
+
+ // Initialize variables
+ $min-width: 0em;
+ $max-width: 0em;
+ $mediaQuery: '';
+
+ // Store current breakpoint in $bp-current-breakpoint.
+ @if $from and $until {
+ $bp-current-breakpoint: $from + "-to-" + $until !global;
+ } @else {
+ @if $from {
+ $bp-current-breakpoint: $from !global;
+ }
+ @if $until {
+ $bp-current-breakpoint: 'until-'+$until !global;
+ }
+ }
+
+ // From: this breakpoint (inclusive)
+ @if $from {
+ @if type-of($from) == number {
+ $min-width: bp-px2em($from);
+ } @else {
+ $min-width: bp-px2em(bp-get-breakpoint-width($from));
+ }
+ }
+
+ // Until: that breakpoint (exclusive)
+ @if $until {
+ @if type-of($until) == number {
+ $max-width: bp-px2em($until);
+ } @else {
+ $max-width: bp-px2em(bp-get-breakpoint-width($until)) - .01em;
+ }
+ }
+
+ // Responsive support is disabled, rasterize the output outside @media blocks
+ // The browser will rely on the cascade itself.
+ @if (not $bp-responsive) {
+ $static-breakpoint-width: bp-get-breakpoint-width($bp-static-breakpoint);
+ @if type-of($static-breakpoint-width) == number {
+ $target-width: bp-px2em($static-breakpoint-width);
+ // Output only rules that start at or span our target width
+ @if ($and == false and ($min-width <= $target-width) and (($until == false) or ($max-width >= $target-width))) {
+ @content;
+ }
+ } @else {
+ // Throw a warning if $bp-static-breakpoint is not in the $bp-breakpoints list
+ @warn "No static styles will be output, " + $static-breakpoint-width +
+ " is not in $bp-breakpoints";
+ }
+ }
+
+ // Responsive support is enabled, output rules inside @media queries
+ @else {
+ @if $min-width != 0em { $mediaQuery: $mediaQuery" and (min-width: "$min-width")"; }
+ @if $max-width != 0em { $mediaQuery: $mediaQuery" and (max-width: "$max-width")"; }
+ @if $and { $mediaQuery: $mediaQuery" and "$and; }
+
+ $mediaQuery: unquote(#{$mediaQuery});
+
+ // Use as a makeshift alternative to @break in order to only
+ // detect the first instance.
+ $bp-detected: false !global;
+
+ @if (($min-width == 0em) and ($max-width == 0em) and ($and == false)) {
+
+ @content;
+
+ // Break
+ $bp-detected: true !global;
+
+ } @else {
+
+ @media all #{$mediaQuery} {
+
+ @each $bp, $val in $bp-breakpoints{
+
+ $val: bp-px2em($val);
+
+ @if (
+ (not $bp-detected) and (
+ ($min-width <= $val) and (
+ (not $until) or ($max-width >= $val) ) ) ){
+
+ @if (map-has-key($bl-baseline-context, $bp)){
+ @include adjust-baseline($bp) {
+ @content;
+ }
+ }
+ @else {
+ @content;
+ }
+
+ // Break
+ $bp-detected: true !global;
+
+ }
+ @else if (
+ (not $bp-detected) and (
+ (not map-has-key($bl-baseline-context, $bp))
+ or (
+ ($max-width >= $val) and (
+ (not $from) or ($min-width <= $val) ) )
+ or ($and != false) ) ) {
+
+ @content;
+
+ // Break
+ $bp-detected: true !global
+ }
+
+ } //@each ends
+
+ } // @media ends
+
+ } // @else ends
+ } // Responsive mode @else ends
+
+ $bp-current-breakpoint: $bp-default-breakpoint !global;
+
+} // @mixin ends
+
+
+
+// Show the active breakpoint in the top right corner of the viewport
+@if (length($bp-show-breakpoints) > 0) {
+ body:before {
+ background-color: #FCF8E3;
+ border-bottom: 1px solid #FBEED5;
+ border-left: 1px solid #FBEED5;
+ color: #C09853;
+ font: small-caption;
+ padding: 3px 6px;
+ position: fixed;
+ right: 0;
+ top: 0;
+ z-index: 100;
+
+ // Loop through the breakpoints that should be shown
+ @each $show-breakpoint in $bp-show-breakpoints {
+ $width: bp-get-breakpoint-width($show-breakpoint);
+ @include bp($show-breakpoint) {
+ content: $show-breakpoint + " ≥ " + $width + " " bp-px2em($width);
+ }
+ }
+ }
+}
+
+
+
+/// Generate an automatic retina version of a background image
+/// ---
+/// @requires {function} get
+///
+/// @requires {function} img-url
+/// From compass/helpers
+///
+/// @requires {function} img-width
+/// From compass/helpers
+///
+/// @requires {function} img-height
+/// From compass/helpers
+/// ---
+/// @param {string} $img-name
+/// An img name (without extension)
+///
+/// @param {string} $img-ext (png)
+/// One of [png | gif | jpg/jpeg | svg]
+///
+/// @param {string} $dimensions (both)
+/// One of [both | none | height | width ]
+///
+/// @param {bool} $retina (true)
+/// ---
+/// @example scss
+/// .logo{
+/// @include bg-image(logo, jpg)
+/// }
+///
+/// .header{
+/// @include bg-image(header-bg, $dimensions: none)
+/// height: 32px;
+/// width: 100%;
+/// }
+/// ---
+/// @example css - CSS Output
+/// .logo {
+/// background-image: images/logo.jpg;
+/// background-size: 240px 60px;
+/// height: 60px;
+/// width: 240px;
+/// @media (-webkit-min-device-pixel-ratio: 1.5), (min-resolution: 1.3dppx) {
+/// background-image: images/logo@2x.jpg;
+/// background-size: 240px 60px;
+/// }
+/// }
+///
+/// .header {
+/// background-image: images/header-bg.png;
+/// background-size: 1920px 32px;
+/// @media (-webkit-min-device-pixel-ratio: 1.5), (min-resolution: 1.3dppx) {
+/// background-image: images/header-bg@2x.jpg;
+/// background-size: 1920px 32px;
+/// }
+/// height: 32px;
+/// width: 100%;
+/// }
+/// ---
+@mixin bg-image($img-name, $img-ext:png, $dimensions:both, $retina: true) {
+ background-image: image-url($img-name+"."+$img-ext);
+ background-size: image-width($img-name+"."+$img-ext) image-height(img+"."+$img-ext);
+
+ @if $dimensions == both {
+ height: image-height($img-name+"."+$img-ext);
+ width: image-width($img-name+"."+$img-ext);
+ } @else if $dimensions == height {
+ height: image-height($img-name+"."+$img-ext);
+ } @else if $dimensions == width {
+ width: image-width($img-name+"."+$img-ext);
+ }
+
+ @if ($retina and $bp-responsive) {
+ @include bp($and: get(bp-custome, retina)) {
+ background-image: image-url($img-name+"@2x."+$img-ext);
+ background-size: image-width($img-name+"@2x."+$img-ext) / 2
+ image-height(img-name+"@2x."+$img-ext) / 2;
+ }
+ }
+}
diff --git a/utils/_u.color.scss b/utils/_u.color.scss
new file mode 100644
index 0000000..fdbc29a
--- /dev/null
+++ b/utils/_u.color.scss
@@ -0,0 +1,352 @@
+// *************************************
+//
+// #COLOR
+// -> Color helper functions and mixins
+//
+////
+/// @group Color
+////
+//
+// *************************************
+
+// -------------------------------------
+// VARIABLES
+// -------------------------------------
+
+/// Project-wide predefined colors
+/// ---
+/// @type map
+/// ---
+/// @see {function} color
+/// @see {mixin} color
+$color: () !default;
+
+
+/// Project-wide color stacks
+/// ---
+/// @type map
+/// ---
+/// @see {function} stack-get
+/// @see {function} stack-set
+/// @see {mixin} color
+$color-stacks: ();
+
+
+
+
+
+// -------------------------------------
+// TINT and SHADE
+// -------------------------------------
+
+/// Tint a color by a given amount
+/// ---
+/// @param {color} $color
+/// @param {number} $amount
+/// ---
+/// @returns {color}
+@function tint($color, $amount){
+ @return mix(#fff, $color, $amount);
+}
+
+
+/// Shade a color by a given amount
+/// ---
+/// @param {color} $color
+/// @param {number} $amount
+/// ---
+/// @returns {color}
+@function shade($color, $amount){
+ @return mix(#000, $color, $amount);
+}
+
+
+
+
+
+
+// -------------------------------------
+// COLOR SET/GET
+// -------------------------------------
+
+/// Get a color value from a map of colors, predefined in
+/// `$color` or add a new one to the map.
+/// Supports deep nesting.
+/// ---
+/// @requires {map} $color
+/// The predefined list of colors.
+/// @requires {function} get
+/// @requires {function} stack-set
+/// ---
+/// @param {string | list} $name
+/// String for a setter or a flat hierarchy getter.
+/// Flat list for an hierarchical getter.
+/// @param {color | map} $value
+/// @param {bool} $stack (false)
+/// Determine whether to automatically generate a color stack
+/// using the stack-set() function.
+/// ---
+/// @example scss - Setters
+/// // setter
+/// $color: color(primary, #f00);
+/// // Will return:
+/// // $color: (
+/// // primary: #f00,
+/// // );
+///
+/// // Hierarchical setter
+/// $color: color(primary, (base: #f00, hover: #800,));
+/// // Will return:
+/// // $color: (
+/// // primary: (
+/// // base: #f00,
+/// // hover: #800,
+/// // ),
+/// // );
+///
+/// // Stack setter
+/// $color: color(neutral, #8080, true);
+/// // Will return (based on definitions in `$stack-steps`):
+/// // $color: (
+/// // neutral: (
+/// // '+2': #606060, // shade
+/// // '+1': #737373, // shade
+/// // base: #808080, // specified color
+/// // '-1': #8c8c8c, // tint
+/// // '-2': #9f9f9f, // tint
+/// // ),
+/// // );
+///
+/// @example scss - Getters
+/// $color: (
+/// primary: ('-2', #f00),
+/// text: #555;
+/// );
+///
+/// .selector {
+/// // getter
+/// color: color(text);
+/// // hierarchical getter
+/// border-color: color((primary '-2'));
+/// // output: border-color: #f00;
+/// }
+/// ---
+/// @returns {map}
+/// ---
+/// @group Getters
+/// @group Setters
+/// @group Color
+@function color($name, $value: null, $stack: false){
+ // ----- Getter ----- //
+ @if $value == null {
+ // Make sure `$color` exists in the global scope
+ @if global-variable-exists(color) {
+ $hierarchy: ();
+ @each $item in $name {
+ $hierarchy: append($hierarchy, $item, comma);
+ }
+ @return get($color, $hierarchy);
+ }
+ @else {
+ @if type-of($name) == color {
+ @warn '`$color` is not defined, returning #{$name}';
+ @return $name;
+ }
+ }
+ }
+
+ // ----- Setter ----- //
+ @if $value {
+ // Make sure `$color` exists in the global scope
+ @if not global-variable-exists(color) {
+ $color: () !global;
+ }
+ $value-type: type-of($value);
+ @if $value-type == color {
+ // Stack
+ @if $stack{
+ @return map-merge($color-stacks, ($name: stack-set($value)));
+ }
+ // Non-hierarchical
+ @else {
+ @return map-merge($color, ($name: $value));
+ }
+ }
+ // Hierarchical
+ @else if $value-type == map {
+ $last: nth($value, length($value));
+ $last-type: type-of($last);
+
+ @if $stack {
+ @warn "Stacks can only be created from single colors, #{$value} is a map. Using the map instead of creating a stack";
+ }
+ @return map-merge($color, ($name: $value));
+ }
+ @else {
+ @error "`$value` in color() can only be a map or a color, You are trying to set `#{$value}`, which is a #{$value-type}";
+ }
+ }
+
+}
+
+/// Add a new color to the list of colors defined in `$color`
+/// ---
+/// @requires {function} color
+/// ---
+/// @param {string} $name
+/// @param {color | map} $value
+/// @param {bool} $stack (false)
+/// Determine whether to automatically generate a color stack
+/// using the stack-set() function.
+/// ---
+/// @example scss - Setters
+/// // setter
+/// @include color(primary, #f00);
+///
+/// // Hierarchical setter
+/// @include color(primary, (base: #f00, hover: #800,));
+///
+/// // Stack setter
+/// @include color(neutral, #8080, true);
+/// ---
+/// @example css - CSS Output
+/// // setter
+/// $color: (
+/// primary: #f00,
+/// );
+///
+/// // Hierarchical setter
+/// $color: (
+/// primary: (
+/// base: #f00,
+/// hover: #800,
+/// ),
+/// );
+///
+/// // Stack setter
+/// // based on definitions in `$stack-steps`
+/// $color-stacks: (
+/// neutral: (
+/// 'shade2': #606060, // shade
+/// 'shade1': #737373, // shade
+/// base: #808080, // specified color
+/// 'tint1': #8c8c8c, // tint
+/// 'tint2': #9f9f9f, // tint
+/// ),
+/// );
+/// ---
+/// @group Color
+/// @group Setters
+/// @group Getters
+@mixin color($name, $value, $stack: false) {
+ @if $stack {
+ @if not global-variable-exists(color-stacks) {
+ $color-stacks: () !global;
+ }
+ $color-stacks: color($name, $value, $stack) !global;
+ }
+ @else {
+ @if not global-variable-exists(color) {
+ $color: () !global;
+ }
+ $color: color($name, $value) !global;
+ }
+}
+
+
+
+
+// -------------------------------------
+// STACKS
+// -------------------------------------
+
+/// Defines the steps in a color stack
+/// ---
+/// @type map
+/// ---
+/// @prop {list} shade
+/// Shade steps
+/// @prop {list} tint
+/// Tint steps
+$stack-steps: (
+ shade: (),
+ tint: (),
+) !default;
+
+
+/// Create a color-stack
+/// ---
+/// @param {color} $color
+/// Base color for the stack
+/// @param {list} $shade-steps ($stack-steps.shade)
+/// A flat list of the shade steps of the stack.
+/// e.g. $shade-steps: (10% 25% 50%)
+/// @param {list} $tint-steps ($stack-steps.tint)
+/// A flat list of the tint steps of the stack.
+/// e.g. $tint-steps: (10% 25% 50%)
+/// ---
+/// @return {function} shade
+/// @return {function} tint
+/// @requires {map} $stack-steps
+/// ---
+/// @returns {map}
+/// ---
+/// @group Setters
+/// @group Color
+@function stack-set($color, $shade-steps: null, $tint-steps: null) {
+ $stack: ();
+ @if $shade-steps == null {
+ $shade-steps: map-get($stack-steps, shade);
+ }
+ @if $tint-steps == null {
+ $tint-steps: map-get($stack-steps, tint);
+ }
+
+ // Shades
+ @if $shade-steps {
+ @for $i from 1 through length($shade-steps){
+ $shade: shade($color, nth($shade-steps, $i));
+ $stack: map-merge($stack, ( "shade" + $i: $shade));
+ }
+ }
+
+ // Base
+ $stack: map-merge($stack, (base: $color));
+
+ // Tints
+ @if $tint-steps {
+ @for $i from 1 through length($tint-steps){
+ $tint: tint($color, nth($tint-steps, $i));
+ $stack: map-merge($stack, ( "tint" + $i: $tint));
+ }
+ }
+
+ @return $stack;
+}
+
+/// Get a value from a color stack
+/// ---
+/// @param {string} $color
+/// A name of a color stack
+/// @param {string} $step (base)
+/// The color step to get from the stack. Can be one of [base | tintN | shadeN]
+/// ---
+/// @group Getters
+/// @group Color
+@function stack-get($color, $step: 'base') {
+ @if global-variable-exists(color-stacks)
+ and map-has-key($color-stacks, $color) {
+
+ @if not map-has-key(map-get($color-stacks, $color), $step) {
+ @error "#{$step} isn't defined in #{$color}. \a The available steps are: \a"
+ + inspect(map-keys(map-get($color-stacks, $color)));
+ }
+
+ @return get($color-stacks, $color, $step);
+
+ }
+ @else {
+ @warn '`$color-stack` does not have `#{$color}` defined in it. returning #{$color}';
+ @return $color;
+ }
+}
diff --git a/utils/_u.function.scss b/utils/_u.function.scss
new file mode 100644
index 0000000..12c5815
--- /dev/null
+++ b/utils/_u.function.scss
@@ -0,0 +1,452 @@
+// *************************************
+//
+// #FUNCTION
+// -> General utility functions
+//
+////
+/// @group General
+////
+//
+// *************************************
+
+
+// -------------------------------------
+// MATH
+// -------------------------------------
+
+/// @param {number} $number
+/// ---
+/// @returns {number}
+/// ---
+@function quarter($number) {
+ @return round($number * 0.25);
+}
+
+/// @param {number} $number
+/// ---
+/// @returns {number}
+/// ---
+@function halve($number) {
+ @return round($number * 0.5);
+}
+
+/// @param {number} $number
+/// ---
+/// @returns {number}
+/// ---
+@function three-quarts($number) {
+ @return round($number * 0.75);
+}
+
+
+/// @param {number} $number
+/// ---
+/// @returns {number}
+/// ---
+@function double($number) {
+ @return round($number * 2);
+}
+
+/// @param {number} $number
+/// ---
+/// @returns {number}
+/// ---
+@function quadruple($number) {
+ @return round($number * 4);
+}
+
+
+
+
+
+// -------------------------------------
+// GETTERS / SETTERS
+// -------------------------------------
+
+// ----- Animation ----- //
+/// Get a predefined value for animations and transitons
+/// ---
+/// @requires {map} $animation
+/// @requires {function} map-get-deep
+/// ---
+/// @param {arglist} $keys
+/// A key to get a value off, or a list of keys denoting nested maps.
+/// ---
+/// @example scss
+/// .selector{
+/// transition: anim(duration, base); anim(easing, swift-out);
+/// }
+/// ---
+/// @group Getters
+/// ---
+@function anim($keys...) {
+ @return map-get-deep($animation, $keys...);
+}
+
+
+// ----- Border-radius ----- //
+/// Get a predefined shadow value.
+/// ---
+/// @param {string} $key
+/// ---
+/// @example scss
+/// .sel {
+/// border-radius: radius(base);
+/// }
+/// ---
+/// @returns {list}
+/// ---
+/// @group Getters
+/// @group UI
+/// ---
+@function radius($key) {
+ @if global-variable-exists(ui) {
+ @if map-has-key($ui, radius) {
+ $radius: map-get($ui, radius);
+ @if map-has-key($radius, $key) {
+ @return map-get($radius, $key);
+ }
+ @else {
+ @error '#{$key} is not defined in $ui -> radius. \a available values are #{map-keys($radius)}';
+ }
+ }
+ @else {
+ @error 'the $ui map does not have a key by the name of radius. \a Cannot retrieve values.'
+ }
+ }
+ @else {
+ @error 'The $ui map, where border-radiuses are defined, does not exist in the global scope. \a Cannot return a value.'
+ }
+}
+
+
+// ----- Settings ----- //
+/// Get a settings value
+/// ---
+/// @param {arglist} $keys
+/// A key to get a value off, or a list of keys
+/// denoting hierarchy in nested maps.
+/// ---
+/// @requires {map} $settings
+/// @requires {function} get
+/// ---
+/// @example scss
+/// $settings: (
+/// border-box: true,
+/// media: (
+/// large: false,
+/// ),
+/// );
+///
+/// @if setting(media, large) {
+/// // This will be false.
+/// }
+/// @else if setting(border-box) {
+/// // This will be true
+/// }
+/// ---
+/// @returns {bool}
+/// ---
+/// @group Getters
+/// @group Settings
+/// ---
+@function setting($keys...) {
+ @if global-variable-exists(settings) {
+ @return get($settings, $keys...)
+ }
+ @else {
+ @error 'The $settings map does not exist in the global scope. \a Cannot return a value.'
+ }
+}
+
+
+
+// ----- Shadow ----- //
+/// Get a predefined shadow value.
+/// ---
+/// @param {string} $key
+/// ---
+/// @example scss
+/// .sel {
+/// box-shadow: shadow(base);
+/// }
+/// ---
+/// @returns {list}
+/// ---
+/// @group Getters
+/// @group UI
+/// ---
+@function shadow($key) {
+ @if global-variable-exists(ui) {
+ @if map-has-key($ui, shadow) {
+ $shadow: map-get($ui, shadow);
+ @if map-has-key($shadow, $key) {
+ @return map-get($shadow, $key);
+ }
+ @else {
+ @error '#{$key} is not defined in $ui -> shadow. \a available values are #{map-keys($shadow)}';
+ }
+ }
+ @else {
+ @error 'the $ui map does not have a key by the name of shadow. \a Cannot retrieve values.'
+ }
+ }
+ @else {
+ @error 'The $ui map, where shadows are defined, does not exist in the global scope. \a Cannot return a value.'
+ }
+}
+
+
+
+
+
+// -------------------------------------
+// MAPS
+// -------------------------------------
+/// Turn map-get-deep()'s warnings on or off
+/// ---
+/// @type bool
+/// ---
+/// @access private
+/// ---
+$map-deep-suppress-warnings: false !global;
+
+/// Get value of a key from a map, including in nested maps.
+/// Nesting can go as deep as needed, where keys are separated by commas.
+/// ---
+/// @requires {variable} $mgd-warn
+/// ---
+/// @param {map} $map
+/// The map to get the value from
+/// @param {string | list} $keys
+/// A key to get a value off, or a list of keys denoting nested maps.
+/// ---
+/// @example scss
+/// h2{
+/// font-size: get($scale, small-screen, h2, fs)
+/// }
+/// ---
+/// @returns {*} Returns a value associated with the last key provided.
+/// ---
+/// @throws $map + " is not a map"
+/// @throws "map has no key named" $keys
+/// ---
+/// @alias get
+/// ---
+@function map-get-deep($map, $keys...){
+ @if length($keys) == 1 {
+ $keys: nth($keys, 1);
+ }
+ $warn: "#{nth($keys, 1)}";
+ $length: length($keys);
+ $get: map-get($map, nth($keys, 1));
+
+ @if $length > 1 {
+ @for $i from 2 through $length {
+ @if $get != null and type-of($get) == 'map' {
+ $warn: $warn + "->#{nth($keys, $i)}";
+ $get: map-get($get, nth($keys, $i));
+
+ @if $get == null {
+ @return map-deep-warning($warn, $get, $map);
+ }
+ }
+ @else {
+ @return map-deep-warning($warn, $get, $map);
+ }
+ }
+ }
+
+ @return $get;
+}
+
+
+/// Set a key to a value inside a map
+/// ---
+/// @param {map} $map
+/// @param {string} $key
+/// @param {any} $value
+/// ---
+/// @returns {map}
+/// ---
+@function map-set($map, $key, $value) {
+ @return map-merge($map, ($key: $value));
+}
+
+
+/// Set a value of a key in a nested map.
+/// Nesting can go as deep as needed.
+/// ---
+/// @requires map-get-deep
+/// @requires get-keys
+/// ---
+/// @param {map} $map
+/// The parent map in which keys and values will be set in.
+/// @param {list} $key
+/// A flat list, e.g ('key' 'key2'), to denote nesting hierarchy.
+/// @param {any} $value
+/// The value to set
+/// ---
+/// @example scss
+/// map-set-deep($map-to-set-in, ('key1' 'key2' 'key3'), value-to-set);
+/// ---
+/// @returns {map}
+/// ---
+@function map-set-deep($map, $keys, $value) {
+ $map-deep-suppress-warnings: true !global;
+ $length: length($keys);
+ $get-keys: ();
+ $map-level: ();
+
+
+ @if $length > 1 {
+ $get-keys: get-keys($keys, $length);
+ $map-level: map-get-deep($map, $get-keys);
+ }
+ $merge: (nth($keys, $length): $value);
+ @if $map-level {
+ $merge: map-merge($map-level, $merge);
+ }
+ @for $i from ($length * -1 + 1) through -1 {
+ $j: abs($i);
+ $key: nth($keys, $j);
+ // @debug $get-keys;
+ @if $j > 1 {
+ $get-keys: get-keys($keys, $j);
+ $map-level: map-get-deep($map, $get-keys);
+ @if $map-level {
+ $merge: map-merge($map-level, ($key: $merge));
+ }
+ @else {
+ $merge: ($key: $merge);
+ }
+ }
+ @else {
+ $merge: ($key: $merge);
+ }
+ }
+ $map: map-merge($map, $merge);
+
+ $map-deep-suppress-warnings: false !global;
+ @return $map;
+}
+
+
+
+// ----- Private utility functions ----- //
+
+/// Private function for map-get-deep() to throw error messages.
+/// ---
+/// @access private
+@function map-deep-warning($warn, $get, $map) {
+ @if not $map-deep-suppress-warnings {
+ @if $get == null {
+ @warn "Map has no value for key search `#{$warn}`";
+ }
+ @else if type-of($get) != 'map' {
+ @warn "Non-map value found for key search `#{$warn}`";
+ }
+ }
+ @return null;
+}
+
+
+/// Private function for map-set-deep() to get keys from a list
+/// ---
+/// @access private
+/// ---
+@function get-keys($keys, $counter) {
+ $return: ();
+ @for $i from 1 to $counter {
+ $return: append($return, nth($keys, $i));
+ }
+ @return $return;
+}
+
+
+
+// ----- Aliases ----- //
+
+/// Get value of a key from a map, including in nested maps.
+/// Nesting can go as deep as needed, where keys are separated by commas.
+/// ---
+/// @requires map-get-deep
+/// ---
+/// @alias map-get-deep
+/// ---
+@function get($map, $keys...){
+ @return map-get-deep($map, $keys...);
+}
+
+
+/// Set value of a key in a map, including inside nested maps.
+/// Nesting can go as deep as needed.
+/// ---
+/// @requires {function} map-set
+/// @requires {function} map-set-deep
+/// ---
+/// @param {map} $map
+/// The parent map in which keys and values will be set in.
+/// @param {string | list} $key
+/// A string for a flat map or
+/// a flat list, e.g ('key' 'key2') to denote nesting hierarchy.
+/// @param $value
+/// The value to set
+/// ---
+/// @example scss
+/// // Set a first-level key by providing a string
+/// map-set-deep($map-to-set-in, key-to-set, value-to-set);
+/// // Set a nested value by providing keys as a flat list
+/// map-set-deep($map-to-set-in, ('key1' 'key2' 'key3'), value-to-set);
+/// ---
+/// @returns {map}
+/// ---
+@function set($map, $keys, $value){
+ @if type-of($keys) == string {
+ @return map-set($map, $keys, $value);
+ } @else {
+ @return map-set-deep($map, $keys, $value);
+ }
+}
+
+
+
+
+
+// -------------------------------------
+// MISC
+// -------------------------------------
+
+/// Check if a $value is any of
+/// the words provided in a list.
+/// ---
+/// @param {string} $value
+/// The string to check for.
+/// @param {list} $list
+/// The list of words to check for the string in.
+/// ---
+/// @returns {bool}
+/// ---
+@function is($value, $list) {
+ @return not not index($list, $value);
+}
+
+
+/// Convert Pixel values to ems.
+/// ---
+/// @param {number} $px
+/// pixel values to be converted to ems.
+/// @param {number} $base-context ($base-font-size)
+/// The browser's assumed font size.
+/// ---
+/// @returns {number}
+/// ---
+@function em($px, $context: $base-font-size) {
+ @if (unitless($px)) {
+ @warn "Value of `$px` must be specified in pixels. Trying to convert.";
+ @return em($px + 0px); // That may fail.
+ } @else if (unit($px) != px) {
+ @error "$px must be in pixels"
+ }
+ @return ($px / $context) * 1em;
+}
diff --git a/utils/_u.layout.scss b/utils/_u.layout.scss
new file mode 100644
index 0000000..ad31635
--- /dev/null
+++ b/utils/_u.layout.scss
@@ -0,0 +1,206 @@
+// *************************************
+//
+// #Layout
+// -> Layout related utilities.
+//
+////
+/// @group Layout
+////
+//
+// *************************************
+
+// -------------------------------------
+// Variables
+// -------------------------------------
+
+/// Predefined spacing values.
+/// By default, provides $spacing.[base | double | three-quarts | half | quarter]
+/// ---
+/// @type map
+/// ---
+/// @example scss
+/// $spacing:(base: 24px, double: 48px,);
+/// ---
+/// @see {function} space
+/// @see {mixin} set-spacing-system
+/// ---
+$spacing: () !default;
+
+
+/// Predefined max and min widths.
+/// ---
+/// @type map
+/// ---
+/// @see {function} width
+/// ---
+$l-widths: () !default;
+
+
+/// A nested, hierarchical representation of the stacking order
+/// ---
+/// @type map
+/// ---
+/// @example scss
+/// context-a: 10000,
+/// context-b: (
+/// base: 9000,
+/// child1: 100,
+/// child2: 90,
+/// ),
+/// )
+/// ---
+/// @see {function} z
+/// ---
+$z-layers: () !default;
+
+
+
+
+
+// -------------------------------------
+// Functions
+// -------------------------------------
+
+/// Get a spacing length from a list of predefined spacing units
+/// or add a new one to the list
+/// ---
+/// @requires {map} $spacing
+/// ---
+/// @param {string} $key
+/// A key to get a value off
+/// @param {number} $value
+/// Length of the new spacing unit, in pixels
+/// ---
+/// @example scss - getter
+/// .modal{
+/// margin-bottom: space(base);
+/// }
+///
+/// @example scss - setter
+/// $spacing: space(new-key, 16px);
+/// ---
+/// @returns {map | number}
+/// ---
+/// @group Getters
+/// @group Setters
+/// @group Layout
+/// ---
+@function space($key, $value: null) {
+ // Setter
+ @if type-of($value) == number {
+ @if ( unitless($value) and $value != 0 ) {
+ @warn "Assuming pixel value for #{$key}, trying to convert";
+ $value: $value + 0px;
+ @return map-merge($spacing, ($key: $value));
+ }
+ @else if ( unit($value) != px and $value != 0 ) {
+ @error "$value for #{$key} must be defined in pixels";
+ }
+ @else {
+ @return map-merge($spacing, ($key: $value));
+ }
+ }
+ // Getter
+ @else {
+ @return map-get($spacing, $key);
+ }
+}
+
+
+/// Get a predefined layout width
+/// ---
+/// @param {string} $key
+/// ---
+/// @example scss
+/// .sel {
+/// max-width: width(max);
+/// }
+/// ---
+/// @returns {number}
+/// ---
+/// @group Getters
+/// @group Layout
+/// ---
+@function l-width($key) {
+ @if global-variable-exists(l-widths) {
+ @if map-has-key($l-widths, $key) {
+ @return map-get($l-widths, $key);
+ }
+ @else {
+ @error '#{$key} is not defined in $l-width. \a Available values are #{map-keys($l-width)}';
+ }
+ }
+ @else {
+ @error 'The $l-width map does not exist in the global scope. \a Cannot return a value.'
+ }
+}
+
+
+/// Get the stacking value of an element according to
+/// a name predefined in the global stacking order
+/// ---
+/// @requires {map} $z-layers
+/// @requires {function} map-get-deep
+/// ---
+/// @param {string | list} $keys
+/// A key to get a value off, or a list of keys denoting nested maps.
+/// ---
+/// @example scss
+/// .modal{
+/// z-index: z(context);
+/// .modal__item{
+/// z-index: z(context, sub-context);
+/// }
+/// }
+/// ---
+/// @returns {number}
+/// ---
+/// @group Getters
+/// @group Layout
+/// ---
+@function z($keys...){
+ @return map-get-deep($z-layers, $keys...);
+}
+
+
+
+
+
+// -------------------------------------
+// Mixins
+// -------------------------------------
+
+/// Automatically setup a coherent spacing system
+/// provides: $spacing.[base | double | three-quarts | half | quarter | flush]
+/// ---
+/// @requires {function} space
+/// @requires {variable} $base-line-height
+/// @requires {variable} $base-font-size
+/// ---
+/// @param {number} $spacer ($base-line-height * lines-for-font-size($base-font-size))
+/// The basic spacing unit, in pixels.
+/// ---
+/// @throws Value of `$spacer` must be specified in pixels. Trying to convert.
+/// @throws Could not set up a spacing system. #{spacer} is not a number in pixels
+/// ---
+@mixin set-spacing-system($spacer: $base-line-height * lines-for-font-size($base-font-size)){
+ @if not global-variable-exists(spacing) {
+ $spacing: () !global;
+ }
+ @if type-of($spacer) == number {
+ @if ( unitless($spacer) and $space != 0 ) {
+ @warn "Value of `$spacer` must be specified in pixels. Trying to convert.";
+ $spacer: $spacer + 0px;
+ } @else if ( unit($spacer) != px and $spacer != 0 ) {
+ @error "could not set up a spacing system. #{spacer} is not a number in pixels"
+ }
+ $spacing: space(base, $spacer) !global;
+ $spacing: space(double, $spacer * 2) !global;
+ $spacing: space(three-quarts, $spacer * 0.75) !global;
+ $spacing: space(half, $spacer * 0.5) !global;
+ $spacing: space(quarter, $spacer * 0.25) !global;
+ $spacing: space(flush, 0) !global;
+ } @else {
+ @error "Could not set up a spacing system. #{spacer} is not a number in pixels"
+ }
+}
diff --git a/utils/_u.placeholders.scss b/utils/_u.placeholders.scss
new file mode 100644
index 0000000..966fb90
--- /dev/null
+++ b/utils/_u.placeholders.scss
@@ -0,0 +1,621 @@
+// *************************************
+//
+// #PLACEHOLDERS
+// -> Mixins to generate and extend
+// placeholder classes
+//
+// *************************************
+
+
+// -------------------------------------
+// VISIBILITY
+// -------------------------------------
+
+// ----- HIDE ----- //
+
+/// Hide elements visually and from screen readers
+/// ---
+/// @requires {mixin} rex
+/// ---
+/// @param {list} $from-bps (null)
+/// list of min-width breakpoint to extend in
+/// @param {list} $to-bps (null)
+/// list of max-width breakpoint to extend in
+///
+/// @param {bool | string} $class (false)
+/// [false | true | both | from | until | to]
+/// Generate an accompanying classes if set to `true` or `both`
+/// Generate accompanying min-width classes if set to `from`
+/// Generate accompanying max-width classes if set to `until` or `to`
+///
+/// @param {bool} $extend (true)
+/// Extend placeholder in the current breakpoint if true,
+/// include rules if false.
+/// ---
+/// @group Layout
+/// ---
+
+@mixin is-hidden($from-bps: null, $to-bps: null, $class: false, $extend: true){
+ @if $extend {
+ @include rex(is-hidden, $from-bps, $to-bps, $class){
+ @include is-hidden($extend: false);
+ }
+ }
+ @else {
+ display: none !important;
+ visibility: hidden !important;
+ }
+}
+
+
+/// Hide elements visually, while remaining
+/// available for screenreaders
+/// Allow to be focusable when navigated to
+/// by adding `.is-focusable` to them in the markup
+/// ---
+/// @requires {mixin} rex
+/// ---
+/// @param {list} $from-bps (null)
+/// list of min-width breakpoint to extend in
+/// @param {list} $to-bps (null)
+/// list of max-width breakpoint to extend in
+///
+/// @param {bool | string} $class (false)
+/// [false | true | both | from | until | to]
+/// Generate an accompanying classes if set to `true` or `both`
+/// Generate accompanying min-width classes if set to `from`
+/// Generate accompanying max-width classes if set to `until` or `to`
+///
+/// @param {bool} $extend (true)
+/// Extend placeholder in the current breakpoint if true,
+/// include rules if false.
+/// ---
+/// @group Layout
+/// ---
+@mixin is-vis-hidden($from-bps: null, $to-bps: null, $class: false, $extend: true){
+ @if $extend {
+ @include rex(is-vis-hidden, $from-bps, $to-bps, $class){
+ @include is-vis-hidden($extend: false);
+ }
+ }
+ @else {
+ border:0 !important;
+ clip:rect(0 0 0 0) !important;
+ height:1px !important;
+ margin:-1px !important;
+ overflow:hidden !important;
+ padding:0 !important;
+ position:absolute !important;
+ width:1px !important;
+ }
+}
+
+
+
+// ----- SHOW ----- //
+
+/// Show hidden elements
+/// ---
+/// @requires {mixin} rex
+/// ---
+/// @param {string} $display (block)
+/// [block | inline-block | inline ]
+/// The display in which the element will be shown
+///
+/// @param {list} $from-bps (null)
+/// list of min-width breakpoint to extend in
+/// @param {list} $to-bps (null)
+/// list of max-width breakpoint to extend in
+///
+/// @param {bool | string} $class (false)
+/// [false | true | both | from | until | to]
+/// Generate an accompanying classes if set to `true` or `both`
+/// Generate accompanying min-width classes if set to `from`
+/// Generate accompanying max-width classes if set to `until` or `to`
+///
+/// @param {bool} $extend (true)
+/// Extend placeholder in the current breakpoint if true,
+/// include rules if false.
+/// ---
+/// @group Layout
+/// ---
+@mixin is-shown($display: block, $from-bps: null, $to-bps: null, $class: false, $extend: true){
+ @if $extend {
+ @include rex(is-shown--#{$display}, $from-bps, $to-bps, $class){
+ @include is-shown($display, $extend: false);
+ }
+ }
+ @else {
+ display: $display !important;
+ visibility: visible !important;
+ }
+}
+
+
+
+
+
+// -------------------------------------
+// SPACING
+// -------------------------------------
+
+/// Limit elements' width to the site's max and center them.
+/// ---
+/// @requires {mixin} rex
+/// @requires {mixin} rem
+/// From Compass
+/// ---
+/// @param {list} $from-bps (null)
+/// list of min-width breakpoint to extend in
+/// @param {list} $to-bps (null)
+/// list of max-width breakpoint to extend in
+///
+/// @param {bool | string} $class (false)
+/// [false | true | both | from | until | to]
+/// Generate an accompanying classes if set to `true` or `both`
+/// Generate accompanying min-width classes if set to `from`
+/// Generate accompanying max-width classes if set to `until` or `to`
+///
+/// @param {bool} $extend (true)
+/// Extend placeholder in the current breakpoint if true,
+/// include rules if false.
+/// ---
+/// @group Layout
+/// ---
+
+@mixin l-max-width($from-bps: null, $to-bps: null, $class: false, $extend: true){
+ @if $extend {
+ @include rex(l-max-width, $from-bps, $to-bps, $class){
+ @include l-max-width($extend: false);
+ }
+ }
+ @else {
+ @include rem(max-width, $max-width);
+ margin-left: auto;
+ margin-right:auto;
+ }
+}
+
+
+/// Set consistent margin-top
+/// When used to modify existing styles in the same or
+/// higher breakpoint, use with `$extend: false`, so that
+/// styles are generated instead of extend, and avoid cascade
+/// order issues.
+/// ---
+/// @requires {map} $spacing
+/// @requires {function} space
+/// ---
+/// @param {string} $amount (base)
+/// [quarter | half | three-quarts | base | double]
+///
+/// @param {bool} $extend (true)
+/// Extend placeholder in the current breakpoint if true,
+/// include rules if false.
+/// ---
+/// @group Layout
+/// ---
+@mixin mt($amount: base, $extend: true){
+ @if $extend {
+ @include ex-cur-bp(mt--#{$amount}) {
+ @include mt($amount, $extend: false);
+ }
+ }
+ @else {
+ @include rem(margin-top, space($amount));
+ }
+}
+
+
+/// Set consistent margin-right
+/// When used to modify existing styles in the same or
+/// higher breakpoint, use with `$extend: false`, so that
+/// styles are generated instead of extend, and avoid cascade
+/// order issues.
+/// ---
+/// @requires {map} $spacing
+/// @requires {function} space
+/// ---
+/// @param {string} $amount (base)
+/// [quarter | half | three-quarts | base | double]
+///
+/// @param {bool} $extend (true)
+/// Extend placeholder in the current breakpoint if true,
+/// include rules if false.
+/// ---
+/// @group Layout
+/// ---
+@mixin mr($amount: base, $extend: true){
+ @if $extend {
+ @include ex-cur-bp(mr--#{$amount}) {
+ @include mr($amount, $extend: false);
+ }
+ }
+ @else {
+ @include rem(margin-right, space($amount));
+ }
+}
+
+
+/// Set consistent margin-bottom
+/// When used to modify existing styles in the same or
+/// higher breakpoint, use with `$extend: false`, so that
+/// styles are generated instead of extend, and avoid cascade
+/// order issues.
+/// ---
+/// @requires {map} $spacing
+/// @requires {function} space
+/// ---
+/// @param {string} $amount (base)
+/// [quarter | half | three-quarts | base | double]
+///
+/// @param {bool} $extend (true)
+/// Extend placeholder in the current breakpoint if true,
+/// include rules if false.
+/// ---
+/// @group Layout
+/// ---
+@mixin mb($amount: base, $extend: true){
+ @if $extend {
+ @include ex-cur-bp(mb--#{$amount}) {
+ @include mb($amount, $extend: false);
+ }
+ }
+ @else {
+ @include rem(margin-bottom, space($amount));
+ }
+}
+
+
+/// Set consistent margin-left
+/// When used to modify existing styles in the same or
+/// higher breakpoint, use with `$extend: false`, so that
+/// styles are generated instead of extend, and avoid cascade
+/// order issues.
+/// ---
+/// @requires {map} $spacing
+/// @requires {function} space
+/// ---
+/// @param {string} $amount (base)
+/// [quarter | half | three-quarts | base | double]
+///
+/// @param {bool} $extend (true)
+/// Extend placeholder in the current breakpoint if true,
+/// include rules if false.
+/// ---
+/// @group Layout
+/// ---
+@mixin ml($amount: base, $extend: true){
+ @if $extend {
+ @include ex-cur-bp(ml--#{$amount}) {
+ @include ml($amount, $extend: false);
+ }
+ }
+ @else {
+ @include rem(margin-left, space($amount));
+ }
+}
+
+
+/// Set consistent margin on both ends (vertically)
+/// When used to modify existing styles in the same or
+/// higher breakpoint, use with `$extend: false`, so that
+/// styles are generated instead of extend, and avoid cascade
+/// order issues.
+/// ---
+/// @requires {map} $spacing
+/// @requires {function} space
+/// ---
+/// @param {string} $amount (base)
+/// [quarter | half | three-quarts | base | double]
+///
+/// @param {bool} $extend (true)
+/// Extend placeholder in the current breakpoint if true,
+/// include rules if false.
+/// ---
+/// @group Layout
+/// ---
+@mixin me($amount: base, $extend: true){
+ @if $extend {
+ @include ex-cur-bp(me--#{$amount}) {
+ @include me($amount, $extend: false);
+ }
+ }
+ @else {
+ @include rem(margin-top, space($amount));
+ @include rem(margin-bottom, space($amount));
+ }
+}
+
+
+/// Set consistent margin on both sides (horizontally)
+/// When used to modify existing styles in the same or
+/// higher breakpoint, use with `$extend: false`, so that
+/// styles are generated instead of extend, and avoid cascade
+/// order issues.
+/// ---
+/// @requires {map} $spacing
+/// @requires {function} space
+/// ---
+/// @param {string} $amount (base)
+/// [quarter | half | three-quarts | base | double]
+///
+/// @param {bool} $extend (true)
+/// Extend placeholder in the current breakpoint if true,
+/// include rules if false.
+/// ---
+/// @group Layout
+/// ---
+@mixin ms($amount: base, $extend: true){
+ @if $extend {
+ @include ex-cur-bp(ms--#{$amount}) {
+ @include ms($amount, $extend: false);
+ }
+ }
+ @else {
+ @include rem(margin-right, space($amount));
+ @include rem(margin-left, space($amount));
+ }
+}
+
+
+/// Set consistent padding-top
+/// When used to modify existing styles in the same or
+/// higher breakpoint, use with `$extend: false`, so that
+/// styles are generated instead of extend, and avoid cascade
+/// order issues.
+/// ---
+/// @requires {map} $spacing
+/// @requires {function} space
+/// ---
+/// @param {string} $amount (base)
+/// [quarter | half | three-quarts | base | double]
+///
+/// @param {bool} $extend (true)
+/// Extend placeholder in the current breakpoint if true,
+/// include rules if false.
+/// ---
+/// @group Layout
+/// ---
+@mixin pt($amount: base, $extend: true){
+ @if $extend {
+ @include ex-cur-bp(pt--#{$amount}) {
+ @include pt($amount, $extend: false);
+ }
+ }
+ @else {
+ @include rem(padding-top, space($amount));
+ }
+}
+
+
+/// Set consistent padding-right
+/// When used to modify existing styles in the same or
+/// higher breakpoint, use with `$extend: false`, so that
+/// styles are generated instead of extend, and avoid cascade
+/// order issues.
+/// ---
+/// @requires {map} $spacing
+/// @requires {function} space
+/// ---
+/// @param {string} $amount (base)
+/// [quarter | half | three-quarts | base | double]
+///
+/// @param {bool} $extend (true)
+/// Extend placeholder in the current breakpoint if true,
+/// include rules if false.
+/// ---
+/// @group Layout
+/// ---
+@mixin pr($amount: base, $extend: true){
+ @if $extend {
+ @include ex-cur-bp(pr--#{$amount}) {
+ @include pr($amount, $extend: false);
+ }
+ }
+ @else {
+ @include rem(padding-right, space($amount));
+ }
+}
+
+
+/// Set consistent padding-bottom
+/// When used to modify existing styles in the same or
+/// higher breakpoint, use with `$extend: false`, so that
+/// styles are generated instead of extend, and avoid cascade
+/// order issues.
+/// ---
+/// @requires {map} $spacing
+/// @requires {function} space
+/// ---
+/// @param {string} $amount (base)
+/// [quarter | half | three-quarts | base | double]
+///
+/// @param {bool} $extend (true)
+/// Extend placeholder in the current breakpoint if true,
+/// include rules if false.
+/// ---
+/// @group Layout
+/// ---
+@mixin pb($amount: base, $extend: true){
+ @if $extend {
+ @include ex-cur-bp(pb--#{$amount}) {
+ @include pb($amount, $extend: false);
+ }
+ }
+ @else {
+ @include rem(padding-bottom, space($amount));
+ }
+}
+
+
+/// Set consistent padding-left
+/// When used to modify existing styles in the same or
+/// higher breakpoint, use with `$extend: false`, so that
+/// styles are generated instead of extend, and avoid cascade
+/// order issues.
+/// ---
+/// @requires {map} $spacing
+/// @requires {function} space
+/// ---
+/// @param {string} $amount (base)
+/// [quarter | half | three-quarts | base | double]
+///
+/// @param {bool} $extend (true)
+/// Extend placeholder in the current breakpoint if true,
+/// include rules if false.
+/// ---
+/// @group Layout
+/// ---
+@mixin pl($amount: base, $extend: true){
+ @if $extend {
+ @include ex-cur-bp(pl--#{$amount}) {
+ @include pl($amount, $extend: false);
+ }
+ }
+ @else {
+ @include rem(padding-left, space($amount));
+ }
+}
+
+
+/// Set consistent padding on both ends (vertically)
+/// When used to modify existing styles in the same or
+/// higher breakpoint, use with `$extend: false`, so that
+/// styles are generated instead of extend, and avoid cascade
+/// order issues.
+/// ---
+/// @requires {map} $spacing
+/// @requires {function} space
+/// ---
+/// @param {string} $amount (base)
+/// [quarter | half | three-quarts | base | double]
+///
+/// @param {bool} $extend (true)
+/// Extend placeholder in the current breakpoint if true,
+/// include rules if false.
+/// ---
+/// @group Layout
+/// ---
+@mixin pe($amount: base, $extend: true){
+ @if $extend {
+ @include ex-cur-bp(pe--#{$amount}) {
+ @include pe($amount, $extend: false);
+ }
+ }
+ @else {
+ @include rem(padding-top, space($amount));
+ @include rem(padding-bottom, space($amount));
+ }
+}
+
+
+/// Set consistent padding on both sides (horizontally)
+/// When used to modify existing styles in the same or
+/// higher breakpoint, use with `$extend: false`, so that
+/// styles are generated instead of extend, and avoid cascade
+/// order issues.
+/// ---
+/// @requires {map} $spacing
+/// @requires {function} space
+/// ---
+/// @param {string} $amount (base)
+/// [quarter | half | three-quarts | base | double]
+///
+/// @param {bool} $extend (true)
+/// Extend placeholder in the current breakpoint if true,
+/// include rules if false.
+/// ---
+/// @group Layout
+/// ---
+@mixin ps($amount: base, $extend: true){
+ @if $extend {
+ @include ex-cur-bp(ps--#{$amount}) {
+ @include ps($amount, $extend: false);
+ }
+ }
+ @else {
+ @include rem(padding-right, space($amount));
+ @include rem(padding-left, space($amount));
+ }
+}
+
+
+/// Create placeholder selectors for all
+/// predefined spacing values in each break
+/// as means to stay in control of the cascade
+/// and have styles for higher bps later in
+/// the cascade, and therefore take precedence.
+@mixin generate-spacing-placeholders {
+ @each $bp, $value in $bp-breakpoints {
+ @include bp($bp) {
+ %spacing-placeholder-private-#{$bp} {
+ @each $name, $value in $spacing {
+ @include me($name);
+ @include ms($name);
+ @include mt($name);
+ @include mr($name);
+ @include mb($name);
+ @include ml($name);
+ @include pe($name);
+ @include ps($name);
+ @include pt($name);
+ @include pr($name);
+ @include pb($name);
+ @include pl($name);
+ }
+ }
+ }
+ }
+}
+
+
+
+
+
+// -------------------------------------
+// MISC
+// -------------------------------------
+
+/// Make elements animatable
+/// ---
+/// @requires {mixin} ex
+/// ---
+/// @param {bool} $extend (true)
+/// Extend placeholder if true, include rules if false
+/// ---
+@mixin is-animable($extend: true) {
+ @if $extend {
+ @include ex(is-animable) {
+ @include is-animable(false);
+ }
+ }
+ @else {
+ transition: all anim(duration, base);
+ }
+}
+
+
+/// Clearfix
+/// ---
+/// @requires {mixin} ex
+/// ---
+/// @param {bool} $extend (true)
+/// Extend placeholder if true, include rules if false
+/// ---
+/// @group Layout
+/// ---
+@mixin group($extend: true) {
+ @if $extend {
+ @include ex(group) {
+ @include group(false);
+ }
+ }
+ @else {
+ &:after{
+ clear:both;
+ content: '';
+ display: table;
+ }
+ }
+}
diff --git a/utils/_u.rhythm.scss b/utils/_u.rhythm.scss
new file mode 100644
index 0000000..6ecb490
--- /dev/null
+++ b/utils/_u.rhythm.scss
@@ -0,0 +1,758 @@
+//*************************************
+//
+// #VERTICAL RHYTHM
+//
+// -> REM based vertical rhythm
+// system with PX fallback
+//
+////
+/// @group Vertical-Rhythm
+////
+//
+// *************************************
+
+// -------------------------------------
+// Dependencies
+// -------------------------------------
+
+@import "compass/typography/units";
+
+
+
+
+
+// -------------------------------------
+// Debug
+// -------------------------------------
+
+/// Show a background image that can be used to debug your alignments.
+/// As this is a development feature, this mixin never outputs pixel fallbacks
+/// for rem output.
+
+@mixin debug-vertical-alignment {
+ $debug-baseline-grid-size: if($round-to-nearest-half-line, rhythm(1/2), rhythm(1));
+ background: linear-gradient(#aaa, #fff 1px);
+ background-size: 100% $debug-baseline-grid-size;
+ background-position: left top;
+}
+
+
+
+
+
+// -------------------------------------
+// Project-wide Variables
+// -------------------------------------
+
+// The following variables should be set in
+// the project-wide variables file.
+// Uncomment here with care only if working without
+// a project wide var file
+
+// Absolute height of body text, in pixels
+// $base-font-size:16px !default;
+
+// Absolute height of one line of type, in pixels
+// $base-line-height:6px !default;
+
+
+
+
+
+// -------------------------------------
+// Variables
+// -------------------------------------
+
+/// The length unit in which to output rhythm values.
+/// Supported values: PX, EM, REM.
+/// Percent units not supported
+$rhythm-unit: em !default;
+
+/// Output fallback values in px when using rem as the rhythm-unit?
+$rem-with-px-fallback: true !default;
+
+/// Default width of rhythm borders.
+$default-rhythm-border-width: 1px !default;
+
+/// Default style of rhythm-borders.
+/// Supports style alone, eg. `solid`,
+/// or list of style and color eg. `solid #aaa`;
+$default-rhythm-border-style: solid !default;
+
+/// Allows the `adjust-font-size-to` mixin and the `lines-for-font-size` function
+/// to round the line height to the nearest half line height instead of the
+/// nearest integral line height to avoid large spacing between lines.
+$round-to-nearest-half-line:false !default;
+
+/// Ensure there is at least this many pixels
+/// of vertical padding above and below the text.
+$min-line-padding:2px !default;
+
+/// Evaluates whether the rhythm output is in absolute units (px)
+/// or relative ones (em, rem)
+/// ---
+/// @access private
+/// ---
+$relative-font-sizing: if($rhythm-unit == px, false, true);
+
+// Validate units
+@if unit($base-font-size) != 'px' { @warn "$base-font-size must resolve to a pixel unit."; }
+@if unit($base-line-height) != 'px' { @warn "$base-line-height must resolve to a pixel unit."; }
+@if $rhythm-unit != 'px' and $rhythm-unit != 'em' and $rhythm-unit != 'rem' {
+ @warn "$rhythm-unit must be `px`, `em` or `rem`.";
+}
+
+
+
+
+
+// -------------------------------------
+// Constants
+// -------------------------------------
+
+/// The leader is the amount of whitespace in a line.
+/// It might be useful in your calculations.
+$base-leader: convert-length($base-line-height - $base-font-size, $rhythm-unit, $base-font-size);
+
+/// The half-leader is the amount of whitespace above and below a line.
+/// It might be useful in your calculations.
+$base-half-leader: $base-leader / 2;
+
+
+
+
+
+// -------------------------------------
+// Functions
+// -------------------------------------
+
+// ----- Rhythm ----- //
+/// Return the height of n baselines.
+/// Defaults to $rhythm-unit.
+/// ---
+/// @param {number} $lines (1)
+/// The number of baselines to return
+/// @param {string} $output-unit ($rhythm-unit)
+/// The unit in which to return the value
+/// @param {number} $font-size ($base-font-size)
+/// The context for calculations, only change when
+/// $output-unit == em.
+/// Must always be defined in pixels
+/// @param {number} $offset (0)
+/// Amount to offset the value by
+/// ---
+/// @requires {variable} $base-line-height
+/// @requires {function} convert-length
+/// From compass/typography/units
+/// ---
+/// @returns {number}
+/// The equivalent of n $lines in the $output-unit
+/// ---
+@function rhythm($lines: 1, $output-unit: $rhythm-unit, $font-size: $base-font-size, $offset: 0) {
+ $rhythm: convert-length($lines * $base-line-height - $offset, $output-unit, $font-size);
+ @if unit($rhythm) == px {
+ $rhythm: floor($rhythm);
+ }
+ @return $rhythm;
+}
+
+
+// ----- Lines per font size ----- //
+/// Calculate the number of baselines required to
+/// accommodate a given pixel-based font size.
+/// ---
+/// @param {number} $font-size
+/// ---
+/// @requires {variable} $base-line-height
+/// ---
+/// @returns {number}
+/// ---
+@function lines-for-font-size($font-size) {
+ $lines: if($round-to-nearest-half-line,
+ ceil(2 * $font-size / $base-line-height) / 2,
+ ceil($font-size / $base-line-height));
+ // Add extra leading if lines are too crampped
+ @if $lines * $base-line-height - $font-size < $min-line-padding * 2 {
+ $lines: $lines + if($round-to-nearest-half-line, 0.5, 1);
+ }
+ @return $lines;
+}
+
+
+
+
+
+// -------------------------------------
+// Mixins
+// -------------------------------------
+
+/// Helper mixin to be used inside other mixins
+/// in order to outputs rhythm values.
+/// ---
+/// @param {string} $property
+/// The property name.
+/// @param {number} $values
+/// The value of $property
+/// @param {string} $unit ($rhythm-unit)
+/// The unit in which the length of $property should be in.
+/// @param {number} $font-size ($base-font-size)
+/// The font-size of the current element, for context.
+/// Should only be changed when output is in EMs.
+/// ---
+/// @requires {mixin} rem
+/// ---
+/// @access private
+/// ---
+@mixin output-rhythm(
+ $property,
+ $values,
+ $unit: $rhythm-unit,
+ $font-size:$base-font-size) {
+ @if $unit == rem and $rem-with-px-fallback {
+ @include rem($property, $values);
+ }
+ @else {
+ $output: ();
+ @each $value in $values {
+ @if unit($value) == px {
+ // Ensure all pixel values are rounded to the nearest pixel.
+ $value: round($value);
+ @if $unit == em {$value: convert-length($value, em, $font-size);}
+ $output: join($output, $value);
+ }
+ @else {
+ @if $unit == em {$value: convert-length($value, em, $font-size);}
+ $output: join($output, $value);
+ }
+ }
+ #{$property}: $output;
+ }
+}
+
+
+/// Outputs values based on number of lines.
+/// Can generate pixel fallback for rem values
+/// ---
+/// @param {string} $property
+/// The property name.
+/// @param {number} $lines (1)
+/// The number of vertical-rhythm lines the length of $property should be.
+/// @param {string} $unit ($rhythm-unit)
+/// The unit in which the length of $property should be in.
+/// @param {number} $font-size ($base-font-size)
+/// The font-size of the current element, for context.
+/// Should only be changed when output is in EMs.
+/// ---
+/// @requires {mixin} rem
+/// ---
+@mixin rhythm-values(
+ $property,
+ $lines:1,
+ $unit:$rhythm-unit,
+ $font-size:$base-font-size) {
+
+ @if $unit == rem and $rem-with-px-fallback {
+ $output:();
+ @each $line in $lines {
+ $output: join($output, rhythm($line, $output-unit:rem));
+ }
+ @include rem($property, $output);
+ }
+
+ @else {
+ $output: ();
+ @each $line in $lines {
+ @if $unit == em or px{
+ $output: join($output, rhythm($line, $unit, $font-size));
+ }
+ @else {
+ @warn "rhythm blocks can only be calculated in `px`, `em` or `rem`.";
+ }
+ }
+ #{$property}: $output;
+ }
+}
+
+
+// ----- Establish baseline ----- //
+/// Set type size and baseline grid on the root element.
+/// ---
+@mixin establish-baseline {
+ @if (& == html) {
+ $html-line-height: convert-length(
+ $base-line-height * lines-for-font-size($base-font-size),
+ $to-unit: em,
+ $from-context: $base-font-size);
+ font-size: $base-font-size;
+ line-height: $html-line-height;
+ }
+ @else {
+ @at-root html {
+ $html-line-height: convert-length(
+ $base-line-height * lines-for-font-size($base-font-size),
+ $to-unit: em,
+ $from-context: $base-font-size);
+ font-size: $base-font-size;
+ line-height: $html-line-height;
+ }
+ }
+}
+
+// ----- Set line height ----- //
+/// Adjust a block to have different line height to maintain the rhythm.
+/// $lines specifies how many multiples of the baseline rhythm each line of this
+/// block should use. It does not have to be an integer, but it defaults to the
+/// smallest integer that is large enough to fit the font.
+/// ---
+/// @param {number | string} $lines (auto)
+/// The number of vertical-rhythm lines the line-height should span.
+/// @param {number} $font-size
+/// The font-size of the line being adjusted.
+/// ---
+/// @requires {function} rhythm
+/// @requires {function} lines-for-font-size
+/// @requires {mixin} output-rhythm
+/// ---
+/// @alias adjust-leading-to
+/// ---
+@mixin line-height($lines: auto, $font-size: $base-font-size) {
+ @if $lines == auto {
+ $lines: lines-for-font-size($font-size);
+ }
+ @else if type-of($lines) != number {
+ @error '$lines can only be a number or `auto`. You are trying to set it to #{$lines}';
+ }
+ @include output-rhythm(line-height, rhythm($lines, em, $font-size));
+}
+
+/// @alias line-height
+/// ---
+@mixin adjust-leading-to($lines: auto, $font-size: $base-font-size) {
+ @include line-height($lines, $font-size);
+}
+
+
+
+// ----- Set font Size ----- //
+/// Adjust a block to have a different font size and line height to maintain the
+/// rhythm. $lines specifies how many multiples of the baseline rhythm each line
+/// of this block should use. It does not have to be an integer, but it
+/// defaults to the smallest integer that is large enough to fit the font.
+/// Use $from-size to adjust from a font-size other than the base font-size.
+
+/// @param {number} $to-size
+/// Desired font size, in pixels
+/// @param {number | string} $lines (auto)
+/// Desired leading, expressed in baselines (can be fractional)
+/// @param {number} $from-size
+/// Context. Font-size of containing element. Only relevant when using EMs.
+/// ---
+/// @requires {function} lines-for-font-size
+/// @requires {mixin} output-rhythm
+/// ---
+/// @alias adjust-font-size-to
+/// ---
+@mixin font-size($to-size, $lines: auto, $from-size: $base-font-size) {
+ $to-size: convert-length($to-size, px, $from-size);
+ @include output-rhythm(font-size, convert-length($to-size, $rhythm-unit, $from-size));
+ @include line-height($lines, $to-size);
+}
+
+/// @alias font-size
+@mixin adjust-font-size-to($to-size, $lines: auto, $from-size: $base-font-size) {
+ @include font-size($to-size, $lines, $from-size);
+}
+
+
+
+// ----- Leader spacing ----- //
+
+/// Apply leading whitespace.
+/// ---
+/// @param {number} $lines (1)
+/// The number of vertical-rhythm lines to space with.
+/// @param {string} $property (margin)
+/// [margin | padding]
+/// @param {string} $unit ($rhythm-unit)
+/// [px, em, rem]. Determines the unit in which the output will be.
+/// @param {number} $font-size ($base-font-size)
+/// For context when using EMs.
+/// ---
+/// @requires {function} rhythm
+/// @requires {mixin} output-rhythm
+/// ---
+@mixin leader(
+ $lines: 1,
+ $property: margin,
+ $unit: $rhythm-unit,
+ $font-size: $base-font-size) {
+ @include output-rhythm(#{$property}-top, rhythm($lines, $unit, $font-size));
+}
+
+
+/// Apply leading whitespace as padding.
+/// ---
+/// @param {number} $lines (1)
+/// The number of vertical-rhythm lines to space with.
+/// @param {string} $unit ($rhythm-unit)
+/// [px, em, rem]. Determines the unit in which the output will be.
+/// @param {number} $font-size ($base-font-size)
+/// For context when using EMs.
+/// ---
+/// @requires {function} rhythm
+/// @requires {mixin} output-rhythm
+/// ---
+
+@mixin padding-leader(
+ $lines:1,
+ $unit: $rhythm-unit,
+ $font-size: $base-font-size) {
+ @include output-rhythm(padding-top, rhythm($lines, $unit, $font-size));
+}
+
+
+/// Apply leading whitespace as margin.
+/// ---
+/// @param {number} $lines (1)
+/// The number of vertical-rhythm lines to space with.
+/// @param {string} $unit ($rhythm-unit)
+/// [px, em, rem]. Determines the unit in which the output will be.
+/// @param {number} $font-size ($base-font-size)
+/// For context when using EMs.
+/// ---
+/// @requires {function} rhythm
+/// @requires {mixin} output-rhythm
+/// ---
+@mixin margin-leader(
+ $lines:1,
+ $unit: $rhythm-unit,
+ $font-size: $base-font-size) {
+ @include output-rhythm(margin-top, rhythm($lines, $unit, $font-size));
+}
+
+
+
+// ----- Trailer spacing ----- //
+
+/// Apply trailing whitespace.
+/// ---
+/// @param {number} $lines (1)
+/// The number of vertical-rhythm lines to space with.
+/// @param {string} $property (margin)
+/// [margin | padding]
+/// @param {string} $unit ($rhythm-unit)
+/// [px, em, rem]. Determines the unit in which the output will be.
+/// @param {number} $font-size ($base-font-size)
+/// For context when using EMs.
+/// ---
+/// @requires {function} rhythm
+/// @requires {mixin} output-rhythm
+/// ---
+@mixin trailer(
+ $lines: 1,
+ $property: margin,
+ $unit: $rhythm-unit,
+ $font-size: $base-font-size) {
+ @include output-rhythm(#{$property}-bottom, rhythm($lines, $unit, $font-size));
+}
+
+
+// Apply trailing whitespace as padding.
+/// ---
+/// @param {number} $lines (1)
+/// The number of vertical-rhythm lines to space with.
+/// @param {string} $unit ($rhythm-unit)
+/// [px, em, rem]. Determines the unit in which the output will be.
+/// @param {number} $font-size ($base-font-size)
+/// For context when using EMs.
+/// ---
+/// @requires {function} rhythm
+/// @requires {mixin} output-rhythm
+/// ---
+@mixin padding-trailer(
+ $lines: 1,
+ $unit: $rhythm-unit,
+ $font-size: $base-font-size) {
+ @include output-rhythm(padding-bottom, rhythm($lines, $unit, $font-size));
+}
+
+
+// Apply trailing whitespace as margin.
+/// ---
+/// @param {number} $lines (1)
+/// The number of vertical-rhythm lines to space with.
+/// @param {string} $unit ($rhythm-unit)
+/// [px, em, rem]. Determines the unit in which the output will be.
+/// @param {number} $font-size ($base-font-size)
+/// For context when using EMs.
+/// ---
+/// @requires {function} rhythm
+/// @requires {mixin} output-rhythm
+/// ---
+@mixin margin-trailer(
+ $lines: 1,
+ $unit: $rhythm-unit,
+ $font-size: $base-font-size) {
+ @include output-rhythm(margin-bottom, rhythm($lines, $unit, $font-size));
+}
+
+
+
+// ----- Top+bottom spacing ----- //
+/// Shorthand mixin to apply whitespace for top and bottom margins and padding.
+/// ---
+/// @param {number} $leader (1)
+/// The number of vertical-rhythm lines to apply above the element in margin
+/// @param {number} $padding-leader (0)
+/// The number of vertical-rhythm lines to apply above the element in padding
+/// @param {number} $padding-trailer (trailer)
+/// The number of vertical-rhythm lines to apply bellow the element in padding
+/// @param {number} $trailer (trailer)
+/// The number of vertical-rhythm lines to apply bellow the element in margin
+/// @param {string} $unit ($rhythm-unit)
+/// [px, em, rem]. Determines the unit in which the output will be.
+/// @param {number} $font-size ($base-font-size)
+/// For context when using EMs.
+/// ---
+/// @requires {mixin} margin-leader
+/// @requires {mixin} margin-trailer
+/// ---
+@mixin rhythm(
+ $leader: 1,
+ $padding-leader: 0,
+ $padding-trailer: $padding-leader,
+ $trailer: $leader,
+ $unit: $rhythm-unit,
+ $font-size: $base-font-size) {
+ @include margin-leader($leader, $unit, $font-size);
+ @include padding-leader($padding-leader, $unit, $font-size);
+ @include padding-trailer($padding-trailer, $unit, $font-size);
+ @include margin-trailer($trailer, $unit, $font-size);
+}
+
+
+/// Shorthand mixin to apply whitespace for top and bottom margins.
+/// ---
+/// @param {number} $leader (1)
+/// The number of vertical-rhythm lines to apply above the element
+/// @param {number} $trailer (trailer)
+/// The number of vertical-rhythm lines to apply bellow the element
+/// @param {string} $unit ($rhythm-unit)
+/// [px, em, rem]. Determines the unit in which the output will be.
+/// @param {number} $font-size ($base-font-size)
+/// For context when using EMs.
+/// ---
+/// @requires {mixin} margin-leader
+/// @requires {mixin} margin-trailer
+/// ---
+@mixin rhythm-margins(
+ $leader: 1,
+ $trailer: $leader,
+ $unit: $rhythm-unit,
+ $font-size: $base-font-size) {
+ @include margin-leader($leader, $unit, $font-size);
+ @include margin-trailer($trailer, $unit, $font-size);
+}
+
+
+/// Shorthand mixin to apply whitespace for top and bottom padding.
+/// ---
+/// @param {number} $leader (1)
+/// The number of vertical-rhythm lines to apply above the element
+/// @param {number} $trailer (trailer)
+/// The number of vertical-rhythm lines to apply bellow the element
+/// @param {string} $unit ($rhythm-unit)
+/// [px, em, rem]. Determines the unit in which the output will be.
+/// @param {number} $font-size ($base-font-size)
+/// For context when using EMs.
+/// ---
+/// @requires {mixin} padding-leader
+/// @requires {mixin} padding-trailer
+/// ---
+@mixin rhythm-padding(
+ $leader: 1,
+ $trailer: $leader,
+ $unit: $rhythm-unit,
+ $font-size: $base-font-size) {
+ @include padding-leader($leader, $unit, $font-size);
+ @include padding-trailer($trailer, $unit, $font-size);
+}
+
+
+
+// ----- Borders ----- //
+
+/// Apply a border to one side of an element without throwing off
+/// the vertical rhythm. The available space ($lines) must be
+/// greater than the width of your border.
+/// ---
+/// @param {string} $side
+/// [all | top | right | bottom | left]
+/// @param {number} $width ($default-rhythm-border-width)
+/// width of border, in pixels.
+/// @param {number} $lines (1)
+/// The number of lines which the border and padding will span together.
+/// The available space generated by $lines must be greater than $width.
+/// @param {string | list} $border-style ($default-rhythm-border-style)
+/// Can take a string containing the border style, e.g `solid` or
+/// a list containing the border style and color, e.g. `solid red`.
+/// @param {string} $unit ($rhythm-unit)
+/// [px, em, rem]. Determines the unit in which the output will be.
+/// @param {number} $font-size ($base-font-size)
+/// For context when using EMs.
+/// ---
+/// @requires {function} convert-length
+/// @requires {function} rhythm
+/// @requires {mixin} output-rhythm
+/// ---
+/// @alias rhythm-border
+/// ---
+@mixin apply-side-rhythm-border(
+ $side,
+ $width: $default-rhythm-border-width,
+ $lines: 1,
+ $border-style: $default-rhythm-border-style,
+ $unit: $rhythm-unit,
+ $font-size: $base-font-size) {
+ // If applying borders to all sides, use shorthand properties
+ $border-prop: if($side == all, border, border-#{$side});
+ $width: if(unit($width) == px, $width, convert-length($width, px, $font-size));
+ #{$border-prop}: $width $border-style;
+
+ $padding-prop: if($side == all, padding, padding-#{$side});
+ @include output-rhythm(#{$padding-prop}, rhythm($lines, $unit, $font-size, $offset: $width));
+}
+
+/// @alias apply-side-rhythm-border
+@mixin rhythm-border(
+ $side,
+ $width: $default-rhythm-border-width,
+ $lines: 1,
+ $border-style: $default-rhythm-border-style,
+ $unit: $rhythm-unit,
+ $font-size: $base-font-size) {
+ @include apply-side-rhythm-border($side, $width, $lines, $border-style, $unit, $font-size)
+}
+
+
+
+/// Apply a leading border.
+/// ---
+/// @param {number} $width ($default-rhythm-border-width)
+/// width of border, in pixels.
+/// @param {number} $lines (1)
+/// The number of lines which the border and padding will span together.
+/// The available space generated by $lines must be greater than $width.
+/// @param {string | list} $border-style ($default-rhythm-border-style)
+/// Can take a string containing the border style, e.g `solid` or
+/// a list containing the border style and color, e.g. `solid red`.
+/// @param {string} $unit ($rhythm-unit)
+/// [px, em, rem]. Determines the unit in which the output will be.
+/// @param {number} $font-size ($base-font-size)
+/// For context when using EMs.
+/// ---
+/// @requires {mixin} apply-side-rhythm-border
+/// ---
+@mixin leading-border(
+ $width: $default-rhythm-border-width,
+ $lines: 1,
+ $border-style: $default-rhythm-border-style,
+ $unit: $rhythm-unit,
+ $font-size: $base-font-size) {
+ @include apply-side-rhythm-border(top, $width, $lines, $border-style, $unit, $font-size)
+}
+
+
+/// Apply a trailing border.
+/// ---
+/// @param {number} $width ($default-rhythm-border-width)
+/// width of border, in pixels.
+/// @param {number} $lines (1)
+/// The number of lines which the border and padding will span together.
+/// The available space generated by $lines must be greater than $width.
+/// @param {string | list} $border-style ($default-rhythm-border-style)
+/// Can take a string containing the border style, e.g `solid` or
+/// a list containing the border style and color, e.g. `solid red`.
+/// @param {string} $unit ($rhythm-unit)
+/// [px, em, rem]. Determines the unit in which the output will be.
+/// @param {number} $font-size ($base-font-size)
+/// For context when using EMs.
+/// ---
+/// @requires {mixin} apply-side-rhythm-border
+/// ---
+@mixin trailing-border(
+ $width: $default-rhythm-border-width,
+ $lines: 1,
+ $border-style: $default-rhythm-border-style,
+ $unit: $rhythm-unit,
+ $font-size: $base-font-size) {
+ @include apply-side-rhythm-border(bottom, $width, $lines, $border-style, $unit, $font-size)
+}
+
+
+/// Apply both leading and trailing borders.
+/// ---
+/// @param {number} $width ($default-rhythm-border-width)
+/// width of border, in pixels.
+/// @param {number} $lines (1)
+/// The number of lines which the border and padding will span together.
+/// The available space generated by $lines must be greater than $width.
+/// @param {string | list} $border-style ($default-rhythm-border-style)
+/// Can take a string containing the border style, e.g `solid` or
+/// a list containing the border style and color, e.g. `solid red`.
+/// @param {string} $unit ($rhythm-unit)
+/// [px, em, rem]. Determines the unit in which the output will be.
+/// @param {number} $font-size ($base-font-size)
+/// For context when using EMs.
+/// ---
+/// @requires {mixin} apply-side-rhythm-border
+/// ---
+/// @alias h-borders
+/// ---
+@mixin horizontal-borders(
+ $width: $default-rhythm-border-width,
+ $lines: 1,
+ $border-style: $default-rhythm-border-style,
+ $unit: $rhythm-unit,
+ $font-size: $base-font-size) {
+ @include leading-border($width, $lines, $border-style, $unit, $font-size);
+ @include trailing-border($width, $lines, $border-style, $unit, $font-size);
+}
+
+
+/// @alias horizontal-borders
+/// ---
+@mixin h-borders(
+ $width: $default-rhythm-border-width,
+ $lines: 1,
+ $border-style: $default-rhythm-border-style,
+ $unit: $rhythm-unit,
+ $font-size: $base-font-size) {
+ @include horizontal-borders($width, $lines, $border-style, $unit, $font-size);
+}
+
+
+/// Apply borders and whitespace equally to all sides.
+/// @param {number} $width ($default-rhythm-border-width)
+/// width of border, in pixels.
+/// @param {number} $lines (1)
+/// The number of lines which the border and padding will span together.
+/// The available space generated by $lines must be greater than $width.
+/// @param {string | list} $border-style ($default-rhythm-border-style)
+/// Can take a string containing the border style, e.g `solid` or
+/// a list containing the border style and color, e.g. `solid red`.
+/// @param {string} $unit ($rhythm-unit)
+/// [px, em, rem]. Determines the unit in which the output will be.
+/// @param {number} $font-size ($base-font-size)
+/// For context when using EMs.
+/// ---
+/// @requires {mixin} apply-side-rhythm-border
+/// ---
+@mixin rhythm-borders(
+ $width: $default-rhythm-border-width,
+ $lines: 1,
+ $border-style: $default-rhythm-border-style,
+ $unit: $rhythm-unit,
+ $font-size: $base-font-size) {
+ @include apply-side-rhythm-border(all, $width, $lines, $border-style, $unit, $font-size)
+}
diff --git a/utils/_u.selectors.scss b/utils/_u.selectors.scss
new file mode 100644
index 0000000..ccb6fe0
--- /dev/null
+++ b/utils/_u.selectors.scss
@@ -0,0 +1,229 @@
+// *************************************
+//
+// #SELECTORS
+// -> Selector manipulation and creation
+// functions and mixins
+//
+////
+/// @group Selector-manipulation
+////
+//
+// *************************************
+
+// -------------------------------------
+// IE classes
+// -------------------------------------
+
+/// Serve styles only to Explorer 8 and down
+/// ---
+/// @group General
+/// ---
+@mixin old-ie {
+ @if setting(old-ie) {
+ @content;
+ }
+}
+
+
+
+
+
+// -------------------------------------
+// CREATE AND EXTEND PLACEHOLDER
+// -------------------------------------
+
+/// Dynamically create and extend a placeholder selector.
+/// ---
+/// @param {string} $name
+/// ---
+/// @requires {mixin} check-placeholders
+/// ---
+@mixin ex($name) {
+ // Make sure $placeholders exists in the global scope
+ @include check-placeholders;
+
+ // Check if there is already a placeholder by
+ // this name in the `$placeholders` map.
+ // Create it if there isn't
+ @if not index($placeholders, $name) {
+ $placeholders: append($placeholders, $name) !global;
+
+ @at-root %#{$name} {
+ @content;
+ }
+ }
+ @extend %#{$name};
+}
+
+/// Dynamically create and extend a placeholder selector at the current bp.
+/// ---
+/// @param {string} $name
+/// ---
+/// @requires {mixin} check-placeholders
+/// ---
+@mixin ex-cur-bp($name) {
+ // Make sure $placeholders exists in the global scope
+ @include check-placeholders;
+
+ $direction: if(str-index($bp-current-breakpoint, until), until, from);
+
+ $until-bp: if($direction == until, str-slice($bp-current-breakpoint, 7), false);
+ $from-bp: if($direction == until, false, $bp-current-breakpoint);
+ $name: $name+'--'+$bp-current-breakpoint;
+ // Check if there is already a placeholder by
+ // this name in the `$placeholders` map.
+ // Create it if there isn't
+ @if not index($placeholders, $name) {
+ $placeholders: append($placeholders, $name) !global;
+
+ @at-root(with: media) {
+ %#{$name} {
+ @content;
+ }
+ }
+ }
+ @extend %#{$name};
+}
+
+
+
+
+
+// -------------------------------------
+// RESPONSIVE PLACEHOLDERS
+// -------------------------------------
+
+/// Dynamically generate and extend placeholder selectors
+/// that can be extended inside media queries
+/// ---
+/// @requires {map} $bp-breakpoints
+/// @requires {variable} $bp-default-breakpoint
+/// @requires {variable} $bp-current-breakpoint
+///
+/// @requires {function} is
+///
+/// @requires {mixin} bp
+/// ---
+/// @param {string} $name
+///
+/// @param {list} $from-bps (null)
+/// list of min-width breakpoint to extend in
+/// @param {list} $to-bps (null)
+/// list of max-width breakpoint to extend in
+///
+/// @param {bool | string} $class (false)
+/// [false | true | both | from | until | to]
+/// Generate an accompanying classes if set to `true` or `both`
+/// Generate accompanying min-width classes if set to `from`
+/// Generate accompanying max-width classes if set to `until` or `to`
+/// ---
+/// @throws '$name + " already exists in `$placeholders`, and will be overwritten."'
+@mixin rex($name, $from-bps: null, $to-bps: null, $class: false){
+
+ @if $class == to {
+ $class: until;
+ }
+ @else if $class == true {
+ $class: both;
+ }
+ // Make sure $placeholders exists in the global scope
+ @include check-placeholders;
+
+ // Check if there is already a placeholder by
+ // this name in the `$placeholders` map.
+ // Create it if there isn't.
+ @if not index($placeholders, $name) {
+ $placeholders: append($placeholders, $name) !global;
+ @at-root{
+ // default, outside media queries
+ %#{$name}--#{$bp-default-breakpoint} {
+ @content;
+ }
+ @each $bp, $value in $bp-breakpoints {
+ @if $value != 0 {
+ // min-width placeholders
+ @include bp($bp){
+ %#{$name}--#{$bp}{
+ @content;
+ }
+ }
+
+ // max-width placeholders
+ @include bp($until: $bp){
+ %#{$name}--until-#{$bp}{
+ @content;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Extend
+ @if not $class {
+ @extend %#{$name}--#{$bp-current-breakpoint} !optional;
+ @if $from-bps != null {
+ @each $bp in $from-bps {
+ @include bp($bp){
+ @extend %#{$name}--#{$bp-current-breakpoint} !optional;
+ }
+ }
+ }
+ @if $to-bps != null {
+ @each $bp in $to-bps {
+ @include bp($until: $bp){
+ @extend %#{$name}--#{$bp-current-breakpoint} !optional;
+ }
+ }
+ }
+ }
+
+ // Generate a regular class as well
+ @else {
+ @at-root{
+ // default, outside media queries
+ .#{$name} {
+ @extend %#{$name}--#{$bp-current-breakpoint} !optional;
+ }
+ @each $bp, $value in $bp-breakpoints {
+ @if $value != 0 {
+ // min-width class
+ @if is($class, 'both' 'from') {
+ @include bp($bp){
+ .#{$name}--#{$bp}{
+ @extend %#{$name}--#{$bp-current-breakpoint} !optional;
+ }
+ }
+ }
+ // max-width class
+ @if is($class, 'both' 'until') {
+ @include bp($until: $bp){
+ .#{$name}--until-#{$bp}{
+ @extend %#{$name}--#{$bp-current-breakpoint} !optional;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+
+
+
+
+// -------------------------------------
+// UTILITY MIXINS
+// -------------------------------------
+
+/// Make sure $placeholders exists in the global scope
+/// ---
+/// @access private
+// ---
+
+@mixin check-placeholders {
+ @if not global-variable-exists(placeholders){
+ $placeholders: () !global;
+ }
+}
diff --git a/utils/_u.typography.scss b/utils/_u.typography.scss
new file mode 100644
index 0000000..d535333
--- /dev/null
+++ b/utils/_u.typography.scss
@@ -0,0 +1,667 @@
+// *************************************
+//
+// #Typography
+// -> Typography related utilities
+//
+////
+/// @group Typography
+////
+//
+// *************************************
+
+// -------------------------------------
+// TOC
+// -------------------------------------
+// Table of contents .......... Here we are.
+// Root baseline .............. A mixin to set font-size and line-height
+// on the html element.
+// Responsive vertical rhythm . Tools to extend Compass's vertical rhythm
+// system to include different baselines in
+// different contexts, mostly breakpoints.
+// Font-stack ................. Tools for organizing and getting
+// predefined font-family stacks
+// Font-size .................. Tools for organizing and getting
+// predefined font-sizes
+// Typographic-scale .......... Tools for creating and using
+// meaningful typographic scales.
+// Measure .................... A function to calculate optimal line-length
+// for a given font-size
+
+
+
+
+
+// -------------------------------------
+// ROOT-BASELINE
+// -------------------------------------
+
+/// Define font-size and line-height on the html element based on the current
+/// contextual vertical rhythm.
+/// ---
+/// @param {list | null} $bps (null)
+/// Accepts a list of breakpoints to set root-baseline in.
+/// Must be compatible with named breakpoints in $bp-breakpoints.
+/// ---
+/// @requires {variable} $base-font-size
+/// @requires {variable} $base-line-height
+/// @requires {function} em
+/// @requires {function} lines-for-font-size
+/// from `compass/typography/vertical_rhythm`
+/// @requires {mixin} bp
+/// ---
+/// @example scss
+/// @include set-root-baseline(s, m);
+///
+/// @include bp(s){
+/// @include set-root-baseline;
+/// }
+/// .el{
+/// @include bp(m){
+/// @include set-root-baseline;
+/// }
+/// }
+/// html{
+/// @include bp(xl){
+/// @include set-root-baseline;
+/// }
+/// }
+/// ---
+/// @outputs
+/// html {
+/// font-size: 16px;
+/// line-height: 1.5em;
+/// }
+/// @media all and (min-width: 37.5em) {
+/// html {
+/// font-size: 18px;
+/// line-height: 1.55556em;
+/// }
+/// }
+/// @media all and (min-width: 71.875em) {
+/// html {
+/// font-size: 20px;
+/// line-height: 1.6em;
+/// }
+/// }
+/// ---
+@mixin set-root-baseline ($bps: null) {
+ @if $bps {
+ @each $bp in $bps {
+ @include bp($bp) {
+ @include root-baseline-private;
+ }
+ }
+ }
+ @else {
+ @include root-baseline-private;
+ }
+}
+
+/// Private mixin used by set-root-baseline for the sake of DRYness
+/// @access private
+@mixin root-baseline-private {
+ @if (& == html) {
+ $html-line-height: em($base-line-height * lines-for-font-size($base-font-size), $base-font-size);
+ font-size: $base-font-size;
+ line-height: $html-line-height;
+ }
+ @else {
+ @at-root html {
+ $html-line-height: em($base-line-height * lines-for-font-size($base-font-size), $base-font-size);
+ font-size: $base-font-size;
+ line-height: $html-line-height;
+ }
+ }
+}
+
+
+
+
+
+// -------------------------------------
+// RESPONSIVE VERTICAL RHYTHM
+// -------------------------------------
+
+/// Contextual baselines for each breakpoint.
+/// Breakpoint names must be in parity with
+/// names in `$bp-breakpoints`.
+/// ---
+/// @type map
+/// ---
+/// @prop {map} name
+/// Name of context (usually a breakpoint).
+///
+/// @prop {number} name.fs
+/// Base font-size, in pixels
+///
+/// @prop {number} name.lh
+/// Base line-height, in pixels
+/// ---
+$bl-baseline-context:(
+ // s: (
+ // fs: 16px, lh: 6px,
+ // ),
+) !default;
+
+
+
+/// Add a baseline context
+/// ---
+/// @param {string} $name
+/// Name of the new baseline
+///
+/// @param {number} $fs
+/// New font-size
+///
+/// @param {number} $lh
+/// New line-height
+/// ---
+/// @requires {map} $bl-baseline-context
+/// ---
+/// @example scss
+/// $bl-baseline-context: bl-add-baseline(tv, 40, 60);
+/// ---
+/// @returns {map}
+/// New contextual baselines map.
+/// ---
+@function bl-add-baseline($name, $fs, $lh){
+
+ @if (unitless($fs)){
+ $fs: $fs+0px;
+ } @else if (unit($fs) != px) {
+ @error '$fs must be defined in pixels'
+ }
+
+ @if (unitless($lh)){
+ $lh: $lh+0px;
+ } @else if (unit($lh) != px) {
+ @error '$lh must be defined in pixels'
+ }
+
+ $values: (fs: $fs, lh: $lh);
+ $new-baseline: (#{$name}: $values);
+
+ @return map-merge($bl-baseline-context, $new-baseline);
+
+}
+
+
+/// A responsive Vertical Rhythm system extending compass's vertical rhythm
+/// system to handle different vertical rhythms at different breakpoints
+/// and contexts.
+/// ---
+/// @requires {function} get
+///
+/// @requires {map} $bl-baseline-context
+///
+/// @requires {mixin} $set-spacing-system
+/// ---
+/// @param {string} $context
+/// a key from `$bl-baseline-context`
+/// ---
+/// @example scss
+/// p{
+/// @include trailer(2);
+//// div {
+/// @include adjust-baseline(boxes){
+/// @include trailer(2);
+/// }
+/// }
+/// }
+/// ---
+/// @output
+/// p {margin-bottom: 1rem;}
+///
+/// p div {margin-bottom: 1.2rem;}
+/// ---
+/// @see {mixin} bp
+/// ---
+@mixin adjust-baseline($context) {
+
+ // Keep initial baseline, for resetting.
+ $initial-baseline: ();
+ @if variable-exists(base-font-size) and variable-exists(base-line-height) {
+ $initial-baseline: (fs: $base-font-size, lh: $base-line-height);
+ }
+
+ // Set contextual baseline
+ // 1. Variables need to be set to global in order for them to be available
+ // to the vertical rhythm mixins and functions.
+ @if map-has-key($bl-baseline-context, $context) {
+ $base-font-size: get($bl-baseline-context, $context, fs) !global;
+ $base-line-height: get($bl-baseline-context, $context, lh) !global;
+ $base-spacing: $base-line-height * lines-for-font-size($base-font-size) !global;
+ @include set-spacing-system;
+
+ @content;
+
+ // Reset initial baseline
+ @if map-has-key($initial-baseline, fs) {
+ $base-font-size: get($initial-baseline, fs) !global; // [1]
+ $base-line-height: get($initial-baseline, lh) !global; // [1]
+ @include set-spacing-system;
+ }
+ }
+ @else {
+ // Context doesn't exist.
+ // Include content based on the default baseline.
+ @content;
+ }
+}
+
+/// Adjust styles at breakpoints in which
+/// the vertical rhythm varies from
+/// default one.
+/// ---
+@mixin bl-style-adjust {
+ @content;
+ @if ( setting(bl-bps) ) {
+ @each $bp in setting(bl-bps) {
+ @if ($bp != $bp-default-breakpoint ) {
+ @include bp($bp) {
+ @content;
+ }
+ }
+ }
+ }
+}
+
+
+
+
+
+// -------------------------------------
+// FONT-STACK
+// -------------------------------------
+/// Font stacks
+/// ---
+/// @type map
+/// ---
+/// @see {function} family
+/// ---
+$font-stack: () !default;
+
+
+/// Get a predefined font-stack
+/// ---
+/// @param {string} $stack
+/// ---
+/// @example scss
+/// .sel {
+/// font-family: family(base);
+/// }
+/// ---
+/// @returns {list}
+/// ---
+/// @group Getters
+/// @group Typography
+/// ---
+@function family($stack) {
+ @if global-variable-exists(font-stack) {
+ @if map-has-key($font-stack, $stack) {
+ @return map-get($font-stack, $stack);
+ }
+ @else {
+ @error '#{$stack} is not defined in `$font-stack`. \a Available values are #{map-keys($font-stack)}';
+ }
+ }
+ @else {
+ @error 'The `$font-stack` map does not exist in the global scope. \a Cannot return a value.'
+ }
+}
+
+
+
+
+
+// -------------------------------------
+// FONT-SIZE
+// -------------------------------------
+
+/// Site's base font size.
+/// ---
+/// @type number
+/// ---
+/// @requires {function} get
+/// @requires {map} $bl-baseline-context
+/// ---
+$base-font-size: 16px !default;
+
+
+/// Site fundamental vertical spacing unit.
+/// ---
+/// @type number
+/// ---
+/// @requires {function} get
+/// @requires {map} $bl-baseline-context
+/// ---
+$base-line-height: 6px !default;
+
+
+/// Specifies the typographic scale.
+/// Can optionally specify a different scale
+/// for each breakpoint.
+/// May be used in conjunction with
+/// the typographic-scale function.
+/// ---
+/// @type map
+/// ---
+/// @prop {map} name
+/// Named breakpoint for when using a responsive scale
+/// Must match names of named breakpoints in `$bp-breakpoints`.
+/// @prop {number} name.size
+/// A font size defined in pixel units.
+/// ---
+/// @see {function} typographic-scale
+/// @see {function} font-size
+/// @see {function} fs
+/// ---
+$font-size: (
+ s: (
+ // Extra-large sizes.
+ giga: 96px,
+ mega: 72px,
+ kilo: 48px,
+
+ // Heading-sizes.
+ h1: 36px, // alpha
+ h2: 30px, // .beta
+ h3: 24px, // .gamma
+ h4: 20px, // .delta
+ h5: 18px, // .epsilon
+ h6: $base-font-size, // .zeta
+
+ // Small sizes
+ milli: 14px,
+ micro: 12px,
+ ),
+) !default;
+
+
+// ----- Getter ----- //
+/// Get a predefined font-size.
+/// ---
+/// @param {string} $size
+/// Named size from `$font-size`, e.g. giga.
+/// @param {string} $bp ($bp-current-breakpoint)
+/// Determines which values for which breakpoint
+/// to pull when using a responsive scale.
+/// Min-width media-queries ($from) will set
+/// this automatically.
+/// ---
+/// @example scss
+/// .sel {
+/// font-size: font-size(base);
+/// }
+/// ---
+/// @requires {function} get
+/// ---
+/// @returns {number}
+/// ---
+/// @alias fs
+/// ---
+/// @group Getters
+/// @group Typography
+/// ---
+@function font-size($size, $bp: $bp-current-breakpoint) {
+ @if global-variable-exists(font-size) {
+
+ // Non responsive scale, never mind the breakpoint.
+ @if ( length($font-size == 1) ) {
+ // Get name of sub-map
+ $bp: nth(nth($font-size, 1), 1);
+ }
+ // check if $bp contains `to` or `until`, meaning
+ // it is not a strictly min-width media-query. Use default
+ @else if ( str-index($bp, 'to') or str-index($bp, 'until') ) {
+ $bp: $bp-default-breakpoint;
+ @warn "Can only get font-sizes for min-width breakpoint. \a Trying to return values for the default breakpoint."
+ }
+
+ @if ( map-has-key($font-size, $bp) ) {
+ $sizes: map-get($font-size, $bp);
+ @if map-has-key($sizes, $size) {
+ @return map-get($sizes, $size);
+ }
+ @else {
+ @error '`$font-size` does not have a size called #{$size} is not defined in breakpoint #{$bp}. \a available values are #{map-keys($sizes)}';
+ }
+ }
+ @else {
+ @error '`$font-size` does not have value for the `#{$bp}` breakpoint. \a available values are #{map-keys($font-size)}';
+ }
+ }
+ @else {
+ @error 'The $font-size map does not exist in the global scope. \a Cannot return a value.'
+ }
+}
+
+/// @alias font-size
+/// ---
+/// @group Getters
+/// @group Typography
+/// ---
+@function fs($size, $bp: $bp-current-breakpoint) {
+ @return font-size($size, $bp);
+}
+
+
+
+
+
+// -------------------------------------
+// TYPOGRAPHIC_SCALE
+// -------------------------------------
+
+/// Typographic scale ratios
+/// ---
+/// @type map
+/// ---
+/// @prop {number} name
+/// The multiplier ratio of each scale.
+/// ---
+$ts-ratios: (
+ golden : 1.618034,
+ double-octave : 4,
+ major-twelfth : 3,
+ major-eleventh : 2.666666667,
+ major-tenth : 2.5,
+ octave : 2,
+ major-seventh : 1.875,
+ minor-seventh : 1.777777778,
+ major-sixth : 1.666666667,
+ minor-sixth : 1.6,
+ fifth : 1.5,
+ augmented-fourth : 1.41421,
+ fourth : 1.333333333,
+ major-third : 1.25,
+ minor-third : 1.2,
+ major-second : 1.125,
+ minor-second : 1.066666667,
+) !default;
+
+/// Generate font-sizes according to a typographic scale
+/// ---
+/// @requires {function} get
+/// @requires {map} $ts-ratios
+/// @requires {variable} $base-font-size
+/// ---
+/// @param {number} $hierarchy
+/// Specifies how many levels away from the base output will be. 0 == base;
+/// Can receive positive as well as negative values.
+/// @param {string | number} $ratio (minor-third)
+/// Can receive a string with a name of a ratio from `$st-ratios`
+/// or a unitless number to serve as the multiplication ratio.
+/// @param {number} $base ($base-font-size)
+/// The font-size that will serve as the base of the typographic scale.
+/// ---
+/// @throws 'The value of `$hierarchy` must be a unitless number'
+/// @throws 'The value or `$ratio` must be a unitless number or the name of a key in the `$ts-ratios` map'
+/// @throws 'The value `$base` must be specified in pixel values'
+/// @throws 'The value of `$base` must be specified in pixels. Trying to convert.'
+/// ---
+/// @returns {number}
+/// ---
+/// @alias ts
+/// ---
+/// @group Getters
+/// @group Typography
+/// ---
+@function typographic-scale($hierarchy, $ratio: major-third, $base: $base-font-size){
+ @if (type-of($hierarchy) != number) or not unitless($hierarchy) {
+ @error 'The value of `$hierarchy` must be a unitless number';
+ }
+ @if (type-of($ratio) != number) {
+ @if map-has-key($ts-ratios, $ratio) {
+ $ratio: get($ts-ratios, $ratio);
+ } @else {
+ @error 'The value or `$ratio` must be a unitless number or the name of a key in the `$ts-ratios` map';
+ }
+ } @else if not unitless($ratio) {
+ @error 'The value or `$ratio` must be a unitless number or the name of a key in the `$ts-ratios` map';
+ }
+ @if (type-of($base) != number) {
+ @error 'The value `$base` must be specified in pixel values';
+ } @else if unitless($base){
+ @warn 'The value of `$base` must be specified in pixels. Trying to convert.';
+ $base: $base + 0px;
+ } @else if unit($base) != px {
+ @error 'The value `$base` must be specified in pixel values';
+ }
+ // initialize font-size
+ $ts-font-size: $base;
+ @if $hierarchy == 0 {
+ @return round($ts-font-size);
+ } @else if $hierarchy < 0 {
+ $hierarchy: abs($hierarchy);
+ @for $i from 1 through $hierarchy {
+ $ts-font-size: ceil($ts-font-size - 2);
+ }
+ @return $ts-font-size;
+ } @else {
+ @for $i from 1 through $hierarchy {
+ $ts-font-size: round($ts-font-size * $ratio / 2) * 2;
+ }
+ @return $ts-font-size;
+ }
+}
+
+
+/// @alias typographic-scale
+/// ---
+@function ts($hierarchy, $ratio: major-third, $base:$base-font-size){
+ @return typographic-scale($hierarchy, $ratio, $base)
+}
+
+
+
+
+
+// -------------------------------------
+// MEASURE
+// -------------------------------------
+
+/// Calculates the ideal line width for a given font size
+/// ---
+/// @param $fs {number} $fs ($base-font-size)
+/// The font size for which optimal measure will be calculated
+/// @param $offset {number} $offset (0)
+/// Amount to add to or subtract from the measure.
+/// ---
+/// @requires {function} get
+/// @requires {map} $spacing
+/// @requires {variable} $base-font-size
+/// ---
+/// @returns {number}
+/// ---
+@function measure($fs: $base-font-size, $offset: 0){
+ @if (type-of($fs) != number) {
+ @error 'The font-size must be specified in pixel values';
+ } @else if unitless($fs){
+ @warn 'The font-size must be specified in pixels. Trying to convert.';
+ $fs: $fs + 0px;
+ } @else if (unit($fs) != px){
+ @error 'The font-size must be specified in pixel values';
+ }
+
+ @if (type-of($offset) != number) {
+ @error '$offset must be specified in pixel values';
+ }
+ @else if unitless($offset) and $offset != 0 {
+ @warn '$offset must be specified in pixels. Trying to convert.';
+ $offset: $offset + 0px;
+ }
+ @else if (unit($offset) != px) and $offset != 0{
+ @error '$offset must be specified in pixel values';
+ }
+
+ $measure: ceil($fs * 28.6);
+ @return $measure + $offset;
+}
+
+
+
+
+
+// -------------------------------------
+// ELLIPSIS
+// -------------------------------------
+
+/// Generate classes for set-height, multi-line text
+/// Which will automatically truncated by an ellipsis.
+/// The truncated text node must reside within an extra
+/// parent element, below the element carrying the class.
+/// e.g.
+/// ```
+/// text text text
+///
```
+///
+/// Generated classes are determined in $s-typography.ellipsis.
+/// ---
+/// @see {variable} $s-typography
+/// ---
+@mixin ellipsis-lines {
+ // non responsive scale, never mind the breakpoint.
+ @if ( length($font-size == 1) ) {
+ // get name of sub-map
+ $typo-scale: nth(nth($font-size, 1), 1);
+ }
+ // check if $bp contains `to` or `until`, meaning
+ // it is not a strictly min-width media-query. use default
+ @else {
+ $typo-scale: $bp-default-breakpoint;
+ }
+ @each $bp, $sizes in setting(ellipsis) {
+ @include bp($bp) {
+ @each $f-size, $lines-set in $sizes {
+ @if $lines-set {
+ $font-size-name: setting(type, map, $f-size);
+ @each $lines in $lines-set {
+ @if ( type-of($lines) != number
+ or not unitless($lines) ) {
+ @error "Line numbers for ellipsis-lines in `$s-typography.ellipsis` can only be unitless numbers. You specified #{$lines} for #{$size} in #{$bp}."
+ }
+ $sel: if($bp == $bp-default-breakpoint,
+ t-#{$f-size}--#{$lines}lines,
+ t-#{$f-size}--#{$lines}lines--#{$bp});
+ .#{$sel} {
+ @include bl-style-adjust {
+ $line-height: lines-for-font-size(fs(setting(type, map, $f-size))) * $base-line-height;
+ @include font-size(fs(setting(type, map, $f-size)));
+ &,
+ &:before {
+ @include rem(height, $line-height * $lines);
+ }
+ &:after {
+ @include rem(top, -1 * $line-height);
+ @include bidi(margin-right, -1 * setting(ellipsis-width));
+ }
+ }
+ }
+ }
+ }
+
+ }
+ }
+ }
+}
diff --git a/utils/_u.valign.scss b/utils/_u.valign.scss
new file mode 100644
index 0000000..cca17ce
--- /dev/null
+++ b/utils/_u.valign.scss
@@ -0,0 +1,52 @@
+// *************************************
+//
+// #Vertical-align
+//
+////
+/// @group Layout
+////
+//
+// *************************************
+
+/// Position an element at the vertical center of its father.
+/// Uses relative positioning. Parent must have set width.
+/// ---
+/// @param {bool} $extend (true)
+/// Extend placeholder if true, include rules if false
+/// ---
+/// @source http://bit.ly/KVwNTj
+@mixin valign($extend: true){
+ @if $extend {
+ @include ex(valign) {
+ @include valign($extend: false);
+ }
+ }
+ @else {
+ position: relative;
+ top: 50%;
+ transform: translateY(-50%);
+ }
+}
+
+/// Position an element at the horizontal and
+/// vertical center of its father
+/// Uses Absolute positioning.
+/// Centers itself at middle of first non-static
+/// ancestor.
+/// ---
+/// @param {bool} $extend (true)
+/// Extend placeholder if true, include rules if false
+/// ---
+/// @source http://bit.ly/1sqEYed
+@mixin abs-middle($extend: true) {
+ @if $extend {
+ @include ex(abs-middle) {
+ @include abs-middle($extend: false);
+ }
+ } @else {
+ left: 50%;
+ position: absolute;
+ top: 50%;
+ transform: translate(-50%, -50%);
+ }
+}
diff --git a/utils/_u.variables.scss b/utils/_u.variables.scss
new file mode 100644
index 0000000..d1d2206
--- /dev/null
+++ b/utils/_u.variables.scss
@@ -0,0 +1,141 @@
+// *************************************
+//
+// #VARIABLES
+// -> Misc variables.
+//
+//
+// *************************************
+
+// Initialized for documentation's sake. Define in config.scss
+/// base values for ui elements
+/// ---
+/// @type map
+/// ---
+/// @requires {function} color
+/// @requires {function} shadow
+/// ---
+/// @prop {color} border.color
+/// @prop {string} border.style
+/// @prop {number} border.width
+/// @prop {number} radius.name
+/// @prop {string} shadow.name
+/// ---
+/// @see {map} $color
+/// ---
+/// @group UI
+$ui: (
+) !default;
+
+
+/// Animation / transition durations, easings etc.
+/// ---
+/// @type map
+/// ---
+/// @prop {number} duration.name
+///
+/// @prop {string} easing.name
+/// ---
+/// @see {function} anim
+/// ---
+/// @group general
+/// ---
+$animation: (
+ duration: (
+ ),
+ easing: (
+ ),
+) !default;
+
+
+
+// -------------------------------------
+// COMPASS
+// -------------------------------------
+
+/// The length unit in which to output rhythm values.
+/// Supported values: PX, EM, REM.
+/// * Percent units not supported *
+/// ---
+/// @type string
+/// ---
+/// @group Typography
+/// ---
+$rhythm-unit: "rem" !default;
+
+/// Output fallback values in px when using rem as the rhythm-unit?
+/// ---
+/// @type bool
+/// ---
+/// @group Typography
+/// ---
+$rem-with-px-fallback: true !default;
+
+/// Allows the `adjust-font-size-to` mixin and the `lines-for-font-size` function
+/// to round the line height to the nearest half line height instead of the
+/// nearest integral line height to avoid large spacing between lines.
+/// ---
+/// @type bool
+/// ---
+/// @group Typography
+/// ---
+$round-to-nearest-half-line:false !default;
+
+/// Ensure there is at least this many pixels of vertical padding above and
+/// below the text.
+/// ---
+/// @type number
+/// ---
+/// @group Typography
+/// ---
+$min-line-padding: 2px !default;
+
+@if global-variable-exists(ui){
+/// Default width of rhythm-border
+/// ---
+/// @requires {function} get
+/// @requires {map} $ui
+/// ---
+/// @type number
+/// ---
+/// @group Typography
+/// ---
+ $default-rhythm-border-width: get($ui, border, width) !default;
+}
+
+@if global-variable-exists(ui){
+/// Default values for rhythm borders properties.
+/// Supports style alone eg. `solid` or list of style and color eg. `solid #aaa`;
+/// ---
+/// @requires {function} get
+/// @requires {map} $ui
+/// ---
+/// @type number
+/// ---
+/// @group Typography
+/// ---
+ $default-rhythm-border-style: get($ui, border, style)
+ get($ui, border, color) !default;
+}
+
+
+
+
+
+// -------------------------------------
+// SETTINGS
+// -------------------------------------
+
+// TODO: copy properties from _config
+
+/// Global settings.
+/// Turn features on / off.
+/// Include / exclude modules.
+/// ---
+/// @type map
+/// ---
+/// @see {function} setting
+/// ---
+/// @group Settings
+/// ---
+$settings: () !default;
+//