diff --git a/package.json b/package.json
index 69eb6ae0e463d2662087fa33458a6d9bc8b72784..93fbd110ecaf43f2c4dd8dc913f588baa82a7b57 100644
--- a/package.json
+++ b/package.json
@@ -22,13 +22,13 @@
     "css": "npm-run-all --parallel css-lint* css-compile* --sequential css-prefix* css-minify*",
     "css-main": "npm-run-all --parallel css-lint css-compile --sequential css-prefix css-minify",
     "css-docs": "npm-run-all --parallel css-lint-docs css-compile-docs --sequential css-prefix-docs css-minify-docs",
-    "css-compile": "node-sass --output-style expanded --source-map true --source-map-contents true --precision 6 scss/bootstrap.scss dist/css/bootstrap.css && node-sass --output-style expanded --source-map true --source-map-contents true --precision 6 scss/bootstrap-grid.scss dist/css/bootstrap-grid.css && node-sass --output-style expanded --source-map true --source-map-contents true --precision 6 scss/bootstrap-reboot.scss dist/css/bootstrap-reboot.css",
+    "css-compile": "node-sass --output-style expanded --source-map true --source-map-contents true --precision 6 scss/bootstrap.scss dist/css/bootstrap.css && node-sass --output-style expanded --source-map true --source-map-contents true --precision 6 scss/bootstrap-grid.scss dist/css/bootstrap-grid.css && node-sass --output-style expanded --source-map true --source-map-contents true --precision 6 scss/bootstrap-placeholders.scss dist/css/bootstrap-placeholders.css && node-sass --output-style expanded --source-map true --source-map-contents true --precision 6 scss/bootstrap-reboot.scss dist/css/bootstrap-reboot.css",
     "css-compile-docs": "node-sass --output-style expanded --source-map true --source-map-contents true --precision 6 assets/scss/docs.scss assets/css/docs.min.css",
     "css-lint": "stylelint --config build/.stylelintrc --syntax scss \"scss/**/*.scss\"",
     "css-lint-docs": "stylelint --config build/.stylelintrc --syntax scss \"assets/scss/*.scss\" && stylelint --config docs/4.0/examples/.stylelintrc \"docs/**/*.css\"",
     "css-prefix": "postcss --config build/postcss.config.js --replace \"dist/css/*.css\"",
     "css-prefix-docs": "postcss --config build/postcss.config.js --replace \"assets/css/docs.min.css\" \"docs/**/*.css\"",
-    "css-minify": "cleancss --level 1 --source-map --source-map-inline-sources --output dist/css/bootstrap.min.css dist/css/bootstrap.css && cleancss --level 1 --source-map --source-map-inline-sources --output dist/css/bootstrap-grid.min.css dist/css/bootstrap-grid.css && cleancss --level 1 --source-map --source-map-inline-sources --output dist/css/bootstrap-reboot.min.css dist/css/bootstrap-reboot.css",
+    "css-minify": "cleancss --level 1 --source-map --source-map-inline-sources --output dist/css/bootstrap.min.css dist/css/bootstrap.css && cleancss --level 1 --source-map --source-map-inline-sources --output dist/css/bootstrap-grid.min.css dist/css/bootstrap-grid.css && cleancss --level 1 --source-map --source-map-inline-sources --output dist/css/bootstrap-placeholders.min.css dist/css/bootstrap-placeholders.css && cleancss --level 1 --source-map --source-map-inline-sources --output dist/css/bootstrap-reboot.min.css dist/css/bootstrap-reboot.css",
     "css-minify-docs": "cleancss --level 1 --source-map --source-map-inline-sources --output assets/css/docs.min.css assets/css/docs.min.css",
     "js": "npm-run-all js-lint* js-compile* js-minify*",
     "js-main": "npm-run-all js-lint js-compile js-minify",
@@ -64,6 +64,7 @@
   },
   "style": "dist/css/bootstrap.css",
   "sass": "scss/bootstrap.scss",
+  "sass-placeholders": "scss/bootstrap-placeholders.scss",
   "main": "dist/js/bootstrap",
   "repository": {
     "type": "git",
@@ -147,6 +148,14 @@
       "path": "./dist/css/bootstrap-grid.min.css",
       "maxSize": "5 kB"
     },
+    {
+      "path": "./dist/css/bootstrap-placeholders.css",
+      "maxSize": "215 B"
+    },
+    {
+      "path": "./dist/css/bootstrap-placeholders.min.css",
+      "maxSize": "215 B"
+    },
     {
       "path": "./dist/css/bootstrap-reboot.css",
       "maxSize": "5 kB"
diff --git a/scss/bootstrap-grid.scss b/scss/bootstrap-grid.scss
index d7d4e7863d9f9a4debd6fdf477a749142d88fc31..7d3dbb256df66fed0e6e1d5ddd4c757e1a76ac6d 100644
--- a/scss/bootstrap-grid.scss
+++ b/scss/bootstrap-grid.scss
@@ -31,5 +31,5 @@ html {
 @import "mixins/grid-framework";
 @import "mixins/grid";
 
-@import "grid";
+@import "components/grid";
 @import "utilities/flex";
diff --git a/scss/bootstrap-placeholders.scss b/scss/bootstrap-placeholders.scss
new file mode 100644
index 0000000000000000000000000000000000000000..68c216a6906aa18430cc2d9a246f877145d91892
--- /dev/null
+++ b/scss/bootstrap-placeholders.scss
@@ -0,0 +1,42 @@
+/*!
+ * Bootstrap v4.0.0-beta.2 (https://getbootstrap.com)
+ * Copyright 2011-2017 The Bootstrap Authors
+ * Copyright 2011-2017 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+
+@import "functions";
+@import "variables";
+@import "mixins";
+//@import "root";
+//@import "print";
+// @import "reboot";
+@import "placeholders/type";
+@import "placeholders/images";
+@import "placeholders/code";
+@import "placeholders/grid";
+// @import "placeholders/tables";
+// @import "placeholders/forms";
+// @import "placeholders/buttons";
+// @import "placeholders/transitions";
+// @import "placeholders/dropdown";
+// @import "placeholders/button-group";
+// @import "placeholders/input-group";
+// @import "placeholders/custom-forms";
+// @import "placeholders/nav";
+// @import "placeholders/navbar";
+// @import "placeholders/card";
+// @import "placeholders/breadcrumb";
+// @import "placeholders/pagination";
+// @import "placeholders/badge";
+// @import "placeholders/jumbotron";
+// @import "placeholders/alert";
+// @import "placeholders/progress";
+// @import "placeholders/media";
+// @import "placeholders/list-group";
+// @import "placeholders/close";
+// @import "placeholders/modal";
+// @import "placeholders/tooltip";
+// @import "placeholders/popover";
+// @import "placeholders/carousel";
+//@import "utilities";
diff --git a/scss/bootstrap.scss b/scss/bootstrap.scss
index bfeffacacf7c22b73d6e60949feeebd080e37d8a..f520ff5f766ca240cc8b7b76f2f3111b4c14249f 100644
--- a/scss/bootstrap.scss
+++ b/scss/bootstrap.scss
@@ -11,32 +11,32 @@
 @import "root";
 @import "print";
 @import "reboot";
-@import "type";
-@import "images";
-@import "code";
-@import "grid";
-@import "tables";
-@import "forms";
-@import "buttons";
-@import "transitions";
-@import "dropdown";
-@import "button-group";
-@import "input-group";
-@import "custom-forms";
-@import "nav";
-@import "navbar";
-@import "card";
-@import "breadcrumb";
-@import "pagination";
-@import "badge";
-@import "jumbotron";
-@import "alert";
-@import "progress";
-@import "media";
-@import "list-group";
-@import "close";
-@import "modal";
-@import "tooltip";
-@import "popover";
-@import "carousel";
+@import "components/type";
+@import "components/images";
+@import "components/code";
+@import "components/grid";
+@import "components/tables";
+@import "components/forms";
+@import "components/buttons";
+@import "components/transitions";
+@import "components/dropdown";
+@import "components/button-group";
+@import "components/input-group";
+@import "components/custom-forms";
+@import "components/nav";
+@import "components/navbar";
+@import "components/card";
+@import "components/breadcrumb";
+@import "components/pagination";
+@import "components/badge";
+@import "components/jumbotron";
+@import "components/alert";
+@import "components/progress";
+@import "components/media";
+@import "components/list-group";
+@import "components/close";
+@import "components/modal";
+@import "components/tooltip";
+@import "components/popover";
+@import "components/carousel";
 @import "utilities";
diff --git a/scss/_alert.scss b/scss/components/_alert.scss
similarity index 100%
rename from scss/_alert.scss
rename to scss/components/_alert.scss
diff --git a/scss/_badge.scss b/scss/components/_badge.scss
similarity index 100%
rename from scss/_badge.scss
rename to scss/components/_badge.scss
diff --git a/scss/_breadcrumb.scss b/scss/components/_breadcrumb.scss
similarity index 100%
rename from scss/_breadcrumb.scss
rename to scss/components/_breadcrumb.scss
diff --git a/scss/_button-group.scss b/scss/components/_button-group.scss
similarity index 100%
rename from scss/_button-group.scss
rename to scss/components/_button-group.scss
diff --git a/scss/_buttons.scss b/scss/components/_buttons.scss
similarity index 100%
rename from scss/_buttons.scss
rename to scss/components/_buttons.scss
diff --git a/scss/_card.scss b/scss/components/_card.scss
similarity index 100%
rename from scss/_card.scss
rename to scss/components/_card.scss
diff --git a/scss/_carousel.scss b/scss/components/_carousel.scss
similarity index 100%
rename from scss/_carousel.scss
rename to scss/components/_carousel.scss
diff --git a/scss/_close.scss b/scss/components/_close.scss
similarity index 100%
rename from scss/_close.scss
rename to scss/components/_close.scss
diff --git a/scss/components/_code.scss b/scss/components/_code.scss
new file mode 100644
index 0000000000000000000000000000000000000000..635b3577be238ca67c02f8de041370439ca3c794
--- /dev/null
+++ b/scss/components/_code.scss
@@ -0,0 +1,23 @@
+@import "../placeholders/code";
+
+// Inline and block code styles
+code { @extend %code; }
+kbd { @extend %kbd; }
+pre { @extend %pre; }
+samp { @extend %samp; }
+
+a > code {
+  @extend %a_code;
+}
+
+kbd kbd {
+  @extend %kbd__kbd;
+}
+pre code {
+  @extend %pre__code;
+}
+
+// Enable scrollable blocks of code
+.pre-scrollable {
+  @extend %pre-scrollable;
+}
diff --git a/scss/_custom-forms.scss b/scss/components/_custom-forms.scss
similarity index 100%
rename from scss/_custom-forms.scss
rename to scss/components/_custom-forms.scss
diff --git a/scss/_dropdown.scss b/scss/components/_dropdown.scss
similarity index 100%
rename from scss/_dropdown.scss
rename to scss/components/_dropdown.scss
diff --git a/scss/_forms.scss b/scss/components/_forms.scss
similarity index 100%
rename from scss/_forms.scss
rename to scss/components/_forms.scss
diff --git a/scss/components/_grid.scss b/scss/components/_grid.scss
new file mode 100644
index 0000000000000000000000000000000000000000..4433d3996ece5deb3bdf84ee51702eba619932e5
--- /dev/null
+++ b/scss/components/_grid.scss
@@ -0,0 +1,50 @@
+@import "../placeholders/grid";
+// Container widths
+//
+// Set the container width, and override it for fixed navbars in media queries.
+
+@if $enable-grid-classes {
+  .container {
+    @extend %container;
+  }
+}
+
+// Fluid container
+//
+// Utilizes the mixin meant for fixed width containers, but with 100% width for
+// fluid, full width layouts.
+
+@if $enable-grid-classes {
+  .container-fluid {
+    @extend %container-fluid;
+  }
+}
+
+// Row
+//
+// Rows contain and clear the floats of your columns.
+
+@if $enable-grid-classes {
+  .row {
+    @extend %row;
+  }
+
+  // Remove the negative margin from default .row, then the horizontal padding
+  // from all immediate children columns (to prevent runaway style inheritance).
+  .no-gutters {
+    @extend %no-gutters;
+
+    > .col,
+    > [class*="col-"] {
+      @extend %no-gutters_col;
+    }
+  }
+}
+
+// Columns
+//
+// Common styles for small and large grid columns
+
+@if $enable-grid-classes {
+  @include make-grid-columns();
+}
diff --git a/scss/components/_images.scss b/scss/components/_images.scss
new file mode 100644
index 0000000000000000000000000000000000000000..713a60675d82989f354715230a8fca40bc42be95
--- /dev/null
+++ b/scss/components/_images.scss
@@ -0,0 +1,33 @@
+@import "../placeholders/images";
+// Responsive images (ensure images don't scale beyond their parents)
+//
+// This is purposefully opt-in via an explicit class rather than being the default for all `<img>`s.
+// We previously tried the "images are responsive by default" approach in Bootstrap v2,
+// and abandoned it in Bootstrap v3 because it breaks lots of third-party widgets (including Google Maps)
+// which weren't expecting the images within themselves to be involuntarily resized.
+// See also https://github.com/twbs/bootstrap/issues/18178
+.img-fluid {
+  @extend %img-fluid;
+}
+
+
+// Image thumbnails
+.img-thumbnail {
+  @extend %img-thumbnail;
+}
+
+//
+// Figures
+//
+
+.figure {
+  @extend %figure;
+}
+
+.figure-img {
+  @extend %figure-img;
+}
+
+.figure-caption {
+  @extend %figure-caption;
+}
diff --git a/scss/_input-group.scss b/scss/components/_input-group.scss
similarity index 100%
rename from scss/_input-group.scss
rename to scss/components/_input-group.scss
diff --git a/scss/_jumbotron.scss b/scss/components/_jumbotron.scss
similarity index 100%
rename from scss/_jumbotron.scss
rename to scss/components/_jumbotron.scss
diff --git a/scss/_list-group.scss b/scss/components/_list-group.scss
similarity index 100%
rename from scss/_list-group.scss
rename to scss/components/_list-group.scss
diff --git a/scss/_media.scss b/scss/components/_media.scss
similarity index 100%
rename from scss/_media.scss
rename to scss/components/_media.scss
diff --git a/scss/_modal.scss b/scss/components/_modal.scss
similarity index 100%
rename from scss/_modal.scss
rename to scss/components/_modal.scss
diff --git a/scss/_nav.scss b/scss/components/_nav.scss
similarity index 100%
rename from scss/_nav.scss
rename to scss/components/_nav.scss
diff --git a/scss/_navbar.scss b/scss/components/_navbar.scss
similarity index 100%
rename from scss/_navbar.scss
rename to scss/components/_navbar.scss
diff --git a/scss/_pagination.scss b/scss/components/_pagination.scss
similarity index 100%
rename from scss/_pagination.scss
rename to scss/components/_pagination.scss
diff --git a/scss/_popover.scss b/scss/components/_popover.scss
similarity index 100%
rename from scss/_popover.scss
rename to scss/components/_popover.scss
diff --git a/scss/_progress.scss b/scss/components/_progress.scss
similarity index 100%
rename from scss/_progress.scss
rename to scss/components/_progress.scss
diff --git a/scss/_tables.scss b/scss/components/_tables.scss
similarity index 100%
rename from scss/_tables.scss
rename to scss/components/_tables.scss
diff --git a/scss/_tooltip.scss b/scss/components/_tooltip.scss
similarity index 100%
rename from scss/_tooltip.scss
rename to scss/components/_tooltip.scss
diff --git a/scss/_transitions.scss b/scss/components/_transitions.scss
similarity index 100%
rename from scss/_transitions.scss
rename to scss/components/_transitions.scss
diff --git a/scss/components/_type.scss b/scss/components/_type.scss
new file mode 100644
index 0000000000000000000000000000000000000000..86bbcc70601c50d61674fed0d6954ae2ad6e1be3
--- /dev/null
+++ b/scss/components/_type.scss
@@ -0,0 +1,92 @@
+@import "../placeholders/type";
+// stylelint-disable declaration-no-important, selector-list-comma-newline-after
+
+//
+// Headings
+//
+
+
+h1, .h1 { @extend %h1; }
+h2, .h2 { @extend %h2; }
+h3, .h3 { @extend %h3; }
+h4, .h4 { @extend %h4; }
+h5, .h5 { @extend %h5; }
+h6, .h6 { @extend %h6; }
+
+.lead {
+  @extend %lead;
+}
+
+// Type display classes
+.display-1 {
+  @extend %display-1;
+}
+.display-2 {
+  @extend %display-1;
+}
+.display-3 {
+  @extend %display-1;
+}
+.display-4 {
+  @extend %display-1;
+}
+
+
+//
+// Horizontal rules
+//
+
+hr {
+  @extend %hr;
+}
+
+
+//
+// Emphasis
+//
+
+small,
+.small {
+  @extend %small;
+}
+
+mark,
+.mark {
+  @extend %mark;
+}
+
+
+//
+// Lists
+//
+
+.list-unstyled {
+  @extend %list-unstyled;
+}
+
+// Inline turns list items into inline-block
+.list-inline {
+  @extend %list-inline;
+}
+.list-inline-item {
+  @extend %list-inline-item;
+}
+
+
+//
+// Misc
+//
+
+// Builds on `abbr`
+.initialism {
+  @extend %initialism;
+}
+
+// Blockquotes
+.blockquote {
+  @extend %blockquote;
+}
+
+.blockquote-footer {
+  @extend %blockquote-footer;
+}
diff --git a/scss/mixins/_grid-framework.scss b/scss/mixins/_grid-framework.scss
index 41bdf4646da2140fc46a514131a7886bfbc961f8..28294129c39e6240163068e22a957253cbe53cf6 100644
--- a/scss/mixins/_grid-framework.scss
+++ b/scss/mixins/_grid-framework.scss
@@ -3,7 +3,7 @@
 // Used only by Bootstrap to generate the correct number of grid classes given
 // any value of `$grid-columns`.
 
-@mixin make-grid-columns($columns: $grid-columns, $gutter: $grid-gutter-width, $breakpoints: $grid-breakpoints) {
+@mixin make-grid-columns-placeholders($columns: $grid-columns, $gutter: $grid-gutter-width, $breakpoints: $grid-breakpoints) {
   // Common properties for all breakpoints
   %grid-column {
     position: relative;
@@ -18,40 +18,40 @@
 
     // Allow columns to stretch full width below their breakpoints
     @for $i from 1 through $columns {
-      .col#{$infix}-#{$i} {
+      %col#{$infix}-#{$i} {
         @extend %grid-column;
       }
     }
-    .col#{$infix},
-    .col#{$infix}-auto {
+    %col#{$infix},
+    %col#{$infix}-auto {
       @extend %grid-column;
     }
 
     @include media-breakpoint-up($breakpoint, $breakpoints) {
       // Provide basic `.col-{bp}` classes for equal-width flexbox columns
-      .col#{$infix} {
+      %col#{$infix} {
         flex-basis: 0;
         flex-grow: 1;
         max-width: 100%;
       }
-      .col#{$infix}-auto {
+      %col#{$infix}-auto {
         flex: 0 0 auto;
         width: auto;
         max-width: none; // Reset earlier grid tiers
       }
 
       @for $i from 1 through $columns {
-        .col#{$infix}-#{$i} {
+        %col#{$infix}-#{$i} {
           @include make-col($i, $columns);
         }
       }
 
-      .order#{$infix}-first {
+      %order#{$infix}-first {
         order: -1;
       }
 
       @for $i from 1 through $columns {
-        .order#{$infix}-#{$i} {
+        %order#{$infix}-#{$i} {
           order: $i;
         }
       }
@@ -59,7 +59,7 @@
       // `$columns - 1` because offsetting by the width of an entire row isn't possible
       @for $i from 0 through ($columns - 1) {
         @if not ($infix == "" and $i == 0) { // Avoid emitting useless .offset-0
-          .offset#{$infix}-#{$i} {
+          %offset#{$infix}-#{$i} {
             @include make-col-offset($i, $columns);
           }
         }
@@ -67,3 +67,60 @@
     }
   }
 }
+
+@mixin make-grid-columns($columns: $grid-columns, $gutter: $grid-gutter-width, $breakpoints: $grid-breakpoints) {
+
+  @include make-grid-columns-placeholders($columns, $gutter, $breakpoints);
+
+  @each $breakpoint in map-keys($breakpoints) {
+    $infix: breakpoint-infix($breakpoint, $breakpoints);
+
+    // Allow columns to stretch full width below their breakpoints
+    @for $i from 1 through $columns {
+      .col#{$infix}-#{$i} {
+        @extend %col#{$infix}-#{$i};
+      }
+    }
+    .col#{$infix} {
+      @extend %col#{$infix};
+    }
+    .col#{$infix}-auto {
+      @extend %col#{$infix}-auto;
+    }
+
+    @include media-breakpoint-up($breakpoint, $breakpoints) {
+
+      .col#{$infix} {
+        @extend %col#{$infix};
+      }
+      .col#{$infix}-auto {
+        @extend %col#{$infix}-auto;
+      }
+
+      @for $i from 1 through $columns {
+        .col#{$infix}-#{$i} {
+          @extend %col#{$infix}-#{$i};
+        }
+      }
+
+      .order#{$infix}-first {
+        @extend %order#{$infix}-first;
+      }
+
+      @for $i from 1 through $columns {
+        .order#{$infix}-#{$i} {
+          @extend %order#{$infix}-#{$i};
+        }
+      }
+
+      @for $i from 0 through ($columns - 1) {
+        @if not ($infix == "" and $i == 0) { // Avoid emitting useless .offset-0
+          .offset#{$infix}-#{$i} {
+            @extend %offset#{$infix}-#{$i};
+          }
+        }
+      }
+
+    }
+  }
+}
diff --git a/scss/placeholders/_alert.scss b/scss/placeholders/_alert.scss
new file mode 100644
index 0000000000000000000000000000000000000000..66fba24ead2b33a4844c5884fee8dca10ff727f5
--- /dev/null
+++ b/scss/placeholders/_alert.scss
@@ -0,0 +1,49 @@
+//
+// Base styles
+//
+
+.alert {
+  position: relative;
+  padding: $alert-padding-y $alert-padding-x;
+  margin-bottom: $alert-margin-bottom;
+  border: $alert-border-width solid transparent;
+  @include border-radius($alert-border-radius);
+}
+
+// Headings for larger alerts
+.alert-heading {
+  // Specified to prevent conflicts of changing $headings-color
+  color: inherit;
+}
+
+// Provide class for links that match alerts
+.alert-link {
+  font-weight: $alert-link-font-weight;
+}
+
+
+// Dismissible alerts
+//
+// Expand the right padding and account for the close button's positioning.
+
+.alert-dismissible {
+  // Adjust close link position
+  .close {
+    position: absolute;
+    top: 0;
+    right: 0;
+    padding: $alert-padding-y $alert-padding-x;
+    color: inherit;
+  }
+}
+
+
+// Alternate styles
+//
+// Generate contextual modifier classes for colorizing the alert.
+
+@each $color, $value in $theme-colors {
+  .alert-#{$color} {
+    @include alert-variant(theme-color-level($color, -10), theme-color-level($color, -9), theme-color-level($color, 6));
+  }
+}
diff --git a/scss/placeholders/_badge.scss b/scss/placeholders/_badge.scss
new file mode 100644
index 0000000000000000000000000000000000000000..b87a1b00495abc8b00d4c813ec301c22cb320f80
--- /dev/null
+++ b/scss/placeholders/_badge.scss
@@ -0,0 +1,47 @@
+// Base class
+//
+// Requires one of the contextual, color modifier classes for `color` and
+// `background-color`.
+
+.badge {
+  display: inline-block;
+  padding: $badge-padding-y $badge-padding-x;
+  font-size: $badge-font-size;
+  font-weight: $badge-font-weight;
+  line-height: 1;
+  text-align: center;
+  white-space: nowrap;
+  vertical-align: baseline;
+  @include border-radius($badge-border-radius);
+
+  // Empty badges collapse automatically
+  &:empty {
+    display: none;
+  }
+}
+
+// Quick fix for badges in buttons
+.btn .badge {
+  position: relative;
+  top: -1px;
+}
+
+// Pill badges
+//
+// Make them extra rounded with a modifier to replace v3's badges.
+
+.badge-pill {
+  padding-right: $badge-pill-padding-x;
+  padding-left: $badge-pill-padding-x;
+  @include border-radius($badge-pill-border-radius);
+}
+
+// Colors
+//
+// Contextual variations (linked badges get darker on :hover).
+
+@each $color, $value in $theme-colors {
+  .badge-#{$color} {
+    @include badge-variant($value);
+  }
+}
diff --git a/scss/placeholders/_breadcrumb.scss b/scss/placeholders/_breadcrumb.scss
new file mode 100644
index 0000000000000000000000000000000000000000..25b9d85a1285b323b3023a3e788256c50f72e2fe
--- /dev/null
+++ b/scss/placeholders/_breadcrumb.scss
@@ -0,0 +1,38 @@
+.breadcrumb {
+  display: flex;
+  flex-wrap: wrap;
+  padding: $breadcrumb-padding-y $breadcrumb-padding-x;
+  margin-bottom: $breadcrumb-margin-bottom;
+  list-style: none;
+  background-color: $breadcrumb-bg;
+  @include border-radius($border-radius);
+}
+
+.breadcrumb-item {
+  // The separator between breadcrumbs (by default, a forward-slash: "/")
+  + .breadcrumb-item::before {
+    display: inline-block; // Suppress underlining of the separator in modern browsers
+    padding-right: $breadcrumb-item-padding;
+    padding-left: $breadcrumb-item-padding;
+    color: $breadcrumb-divider-color;
+    content: "#{$breadcrumb-divider}";
+  }
+
+  // IE9-11 hack to properly handle hyperlink underlines for breadcrumbs built
+  // without `<ul>`s. The `::before` pseudo-element generates an element
+  // *within* the .breadcrumb-item and thereby inherits the `text-decoration`.
+  //
+  // To trick IE into suppressing the underline, we give the pseudo-element an
+  // underline and then immediately remove it.
+  + .breadcrumb-item:hover::before {
+    text-decoration: underline;
+  }
+  // stylelint-disable-next-line no-duplicate-selectors
+  + .breadcrumb-item:hover::before {
+    text-decoration: none;
+  }
+
+  &.active {
+    color: $breadcrumb-active-color;
+  }
+}
diff --git a/scss/placeholders/_button-group.scss b/scss/placeholders/_button-group.scss
new file mode 100644
index 0000000000000000000000000000000000000000..1a373f323282b31e07f13bd851bfb9120a53621d
--- /dev/null
+++ b/scss/placeholders/_button-group.scss
@@ -0,0 +1,207 @@
+// stylelint-disable selector-no-qualifying-type
+
+// Make the div behave like a button
+.btn-group,
+.btn-group-vertical {
+  position: relative;
+  display: inline-flex;
+  vertical-align: middle; // match .btn alignment given font-size hack above
+
+  > .btn {
+    position: relative;
+    flex: 0 1 auto;
+
+    // Bring the hover, focused, and "active" buttons to the front to overlay
+    // the borders properly
+    @include hover {
+      z-index: 2;
+    }
+    &:focus,
+    &:active,
+    &.active {
+      z-index: 2;
+    }
+  }
+
+  // Prevent double borders when buttons are next to each other
+  .btn + .btn,
+  .btn + .btn-group,
+  .btn-group + .btn,
+  .btn-group + .btn-group {
+    margin-left: -$input-btn-border-width;
+  }
+}
+
+// Optional: Group multiple button groups together for a toolbar
+.btn-toolbar {
+  display: flex;
+  flex-wrap: wrap;
+  justify-content: flex-start;
+
+  .input-group {
+    width: auto;
+  }
+}
+
+.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {
+  border-radius: 0;
+}
+
+// Set corners individual because sometimes a single button can be in a .btn-group
+// and we need :first-child and :last-child to both match
+.btn-group > .btn:first-child {
+  margin-left: 0;
+
+  &:not(:last-child):not(.dropdown-toggle) {
+    @include border-right-radius(0);
+  }
+}
+// Need .dropdown-toggle since :last-child doesn't apply given a .dropdown-menu
+// immediately after it
+.btn-group > .btn:last-child:not(:first-child),
+.btn-group > .dropdown-toggle:not(:first-child) {
+  @include border-left-radius(0);
+}
+
+// Custom edits for including btn-groups within btn-groups (useful for including
+// dropdown buttons within a btn-group)
+.btn-group > .btn-group {
+  float: left;
+}
+
+.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {
+  border-radius: 0;
+}
+
+.btn-group > .btn-group:first-child:not(:last-child) {
+  > .btn:last-child,
+  > .dropdown-toggle {
+    @include border-right-radius(0);
+  }
+}
+
+.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {
+  @include border-left-radius(0);
+}
+
+
+// Sizing
+//
+// Remix the default button sizing classes into new ones for easier manipulation.
+
+.btn-group-sm > .btn { @extend .btn-sm; }
+.btn-group-lg > .btn { @extend .btn-lg; }
+
+
+//
+// Split button dropdowns
+//
+
+.btn + .dropdown-toggle-split {
+  padding-right: $input-btn-padding-x * .75;
+  padding-left: $input-btn-padding-x * .75;
+
+  &::after {
+    margin-left: 0;
+  }
+}
+
+.btn-sm + .dropdown-toggle-split {
+  padding-right: $input-btn-padding-x-sm * .75;
+  padding-left: $input-btn-padding-x-sm * .75;
+}
+
+.btn-lg + .dropdown-toggle-split {
+  padding-right: $input-btn-padding-x-lg * .75;
+  padding-left: $input-btn-padding-x-lg * .75;
+}
+
+
+// The clickable button for toggling the menu
+// Set the same inset shadow as the :active state
+.btn-group.show .dropdown-toggle {
+  @include box-shadow($btn-active-box-shadow);
+
+  // Show no shadow for `.btn-link` since it has no other button styles.
+  &.btn-link {
+    @include box-shadow(none);
+  }
+}
+
+
+//
+// Vertical button groups
+//
+
+.btn-group-vertical {
+  flex-direction: column;
+  align-items: flex-start;
+  justify-content: center;
+
+  .btn,
+  .btn-group {
+    width: 100%;
+  }
+
+  > .btn + .btn,
+  > .btn + .btn-group,
+  > .btn-group + .btn,
+  > .btn-group + .btn-group {
+    margin-top: -$input-btn-border-width;
+    margin-left: 0;
+  }
+
+  > .btn {
+    &:not(:first-child):not(:last-child) {
+      border-radius: 0;
+    }
+
+    &:first-child:not(:last-child) {
+      @include border-bottom-radius(0);
+    }
+
+    &:last-child:not(:first-child) {
+      @include border-top-radius(0);
+    }
+  }
+
+  > .btn-group:not(:first-child):not(:last-child) > .btn {
+    border-radius: 0;
+  }
+
+  > .btn-group:first-child:not(:last-child) {
+    > .btn:last-child,
+    > .dropdown-toggle {
+      @include border-bottom-radius(0);
+    }
+  }
+
+  > .btn-group:last-child:not(:first-child) > .btn:first-child {
+    @include border-top-radius(0);
+  }
+}
+
+
+// Checkbox and radio options
+//
+// In order to support the browser's form validation feedback, powered by the
+// `required` attribute, we have to "hide" the inputs via `clip`. We cannot use
+// `display: none;` or `visibility: hidden;` as that also hides the popover.
+// Simply visually hiding the inputs via `opacity` would leave them clickable in
+// certain cases which is prevented by using `clip` and `pointer-events`.
+// This way, we ensure a DOM element is visible to position the popover from.
+//
+// See https://github.com/twbs/bootstrap/pull/12794 and
+// https://github.com/twbs/bootstrap/pull/14559 for more information.
+
+[data-toggle="buttons"] {
+  > .btn,
+  > .btn-group > .btn {
+    input[type="radio"],
+    input[type="checkbox"] {
+      position: absolute;
+      clip: rect(0,0,0,0);
+      pointer-events: none;
+    }
+  }
+}
diff --git a/scss/placeholders/_buttons.scss b/scss/placeholders/_buttons.scss
new file mode 100644
index 0000000000000000000000000000000000000000..7cd27830b5966b2c1394d9c9cd80ff039b74e007
--- /dev/null
+++ b/scss/placeholders/_buttons.scss
@@ -0,0 +1,136 @@
+// stylelint-disable selector-no-qualifying-type
+
+//
+// Base styles
+//
+
+.btn {
+  display: inline-block;
+  font-weight: $btn-font-weight;
+  text-align: center;
+  white-space: nowrap;
+  vertical-align: middle;
+  user-select: none;
+  border: $input-btn-border-width solid transparent;
+  @include button-size($input-btn-padding-y, $input-btn-padding-x, $font-size-base, $input-btn-line-height, $btn-border-radius);
+  @include transition($btn-transition);
+
+  // Share hover and focus styles
+  @include hover-focus {
+    text-decoration: none;
+  }
+  &:focus,
+  &.focus {
+    outline: 0;
+    box-shadow: $input-btn-focus-box-shadow;
+  }
+
+  // Disabled comes first so active can properly restyle
+  &.disabled,
+  &:disabled {
+    opacity: .65;
+    @include box-shadow(none);
+  }
+
+  &:not([disabled]):not(.disabled):active,
+  &:not([disabled]):not(.disabled).active {
+    background-image: none;
+    @include box-shadow($input-btn-focus-box-shadow, $btn-active-box-shadow);
+  }
+}
+
+// Future-proof disabling of clicks on `<a>` elements
+a.btn.disabled,
+fieldset[disabled] a.btn {
+  pointer-events: none;
+}
+
+
+//
+// Alternate buttons
+//
+
+@each $color, $value in $theme-colors {
+  .btn-#{$color} {
+    @include button-variant($value, $value);
+  }
+}
+
+@each $color, $value in $theme-colors {
+  .btn-outline-#{$color} {
+    @if $color == "light" {
+      @include button-outline-variant($value, $gray-900);
+    } @else {
+      @include button-outline-variant($value, $white);
+    }
+  }
+}
+
+
+//
+// Link buttons
+//
+
+// Make a button look and behave like a link
+.btn-link {
+  font-weight: $font-weight-normal;
+  color: $link-color;
+  background-color: transparent;
+
+  @include hover {
+    color: $link-hover-color;
+    text-decoration: $link-hover-decoration;
+    background-color: transparent;
+    border-color: transparent;
+  }
+
+  &:focus,
+  &.focus {
+    border-color: transparent;
+    box-shadow: none;
+  }
+
+  &:disabled,
+  &.disabled {
+    color: $btn-link-disabled-color;
+  }
+
+  // No need for an active state here
+}
+
+
+//
+// Button Sizes
+//
+
+.btn-lg {
+  @include button-size($input-btn-padding-y-lg, $input-btn-padding-x-lg, $font-size-lg, $input-btn-line-height-lg, $btn-border-radius-lg);
+}
+
+.btn-sm {
+  @include button-size($input-btn-padding-y-sm, $input-btn-padding-x-sm, $font-size-sm, $input-btn-line-height-sm, $btn-border-radius-sm);
+}
+
+
+//
+// Block button
+//
+
+.btn-block {
+  display: block;
+  width: 100%;
+}
+
+// Vertically space out multiple block buttons
+.btn-block + .btn-block {
+  margin-top: $btn-block-spacing-y;
+}
+
+// Specificity overrides
+input[type="submit"],
+input[type="reset"],
+input[type="button"] {
+  &.btn-block {
+    width: 100%;
+  }
+}
diff --git a/scss/placeholders/_card.scss b/scss/placeholders/_card.scss
new file mode 100644
index 0000000000000000000000000000000000000000..a739f193558aaae11ab2ff6a572217485c150c3a
--- /dev/null
+++ b/scss/placeholders/_card.scss
@@ -0,0 +1,259 @@
+//
+// Base styles
+//
+
+.card {
+  position: relative;
+  display: flex;
+  flex-direction: column;
+  min-width: 0;
+  word-wrap: break-word;
+  background-color: $card-bg;
+  background-clip: border-box;
+  border: $card-border-width solid $card-border-color;
+  @include border-radius($card-border-radius);
+
+  > hr {
+    margin-right: 0;
+    margin-left: 0;
+  }
+
+  > .list-group:first-child {
+    .list-group-item:first-child {
+      @include border-top-radius($card-border-radius);
+    }
+  }
+
+  > .list-group:last-child {
+    .list-group-item:last-child {
+      @include border-bottom-radius($card-border-radius);
+    }
+  }
+}
+
+.card-body {
+  // Enable `flex-grow: 1` for decks and groups so that card blocks take up
+  // as much space as possible, ensuring footers are aligned to the bottom.
+  flex: 1 1 auto;
+  padding: $card-spacer-x;
+}
+
+.card-title {
+  margin-bottom: $card-spacer-y;
+}
+
+.card-subtitle {
+  margin-top: -($card-spacer-y / 2);
+  margin-bottom: 0;
+}
+
+.card-text:last-child {
+  margin-bottom: 0;
+}
+
+.card-link {
+  @include hover {
+    text-decoration: none;
+  }
+
+  + .card-link {
+    margin-left: $card-spacer-x;
+  }
+}
+
+//
+// Optional textual caps
+//
+
+.card-header {
+  padding: $card-spacer-y $card-spacer-x;
+  margin-bottom: 0; // Removes the default margin-bottom of <hN>
+  background-color: $card-cap-bg;
+  border-bottom: $card-border-width solid $card-border-color;
+
+  &:first-child {
+    @include border-radius($card-inner-border-radius $card-inner-border-radius 0 0);
+  }
+
+  + .list-group {
+    .list-group-item:first-child {
+      border-top: 0;
+    }
+  }
+}
+
+.card-footer {
+  padding: $card-spacer-y $card-spacer-x;
+  background-color: $card-cap-bg;
+  border-top: $card-border-width solid $card-border-color;
+
+  &:last-child {
+    @include border-radius(0 0 $card-inner-border-radius $card-inner-border-radius);
+  }
+}
+
+
+//
+// Header navs
+//
+
+.card-header-tabs {
+  margin-right: -($card-spacer-x / 2);
+  margin-bottom: -$card-spacer-y;
+  margin-left: -($card-spacer-x / 2);
+  border-bottom: 0;
+}
+
+.card-header-pills {
+  margin-right: -($card-spacer-x / 2);
+  margin-left: -($card-spacer-x / 2);
+}
+
+// Card image
+.card-img-overlay {
+  position: absolute;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  padding: $card-img-overlay-padding;
+}
+
+.card-img {
+  width: 100%; // Required because we use flexbox and this inherently applies align-self: stretch
+  @include border-radius($card-inner-border-radius);
+}
+
+// Card image caps
+.card-img-top {
+  width: 100%; // Required because we use flexbox and this inherently applies align-self: stretch
+  @include border-top-radius($card-inner-border-radius);
+}
+
+.card-img-bottom {
+  width: 100%; // Required because we use flexbox and this inherently applies align-self: stretch
+  @include border-bottom-radius($card-inner-border-radius);
+}
+
+
+// Card deck
+
+.card-deck {
+  display: flex;
+  flex-direction: column;
+
+  .card {
+    margin-bottom: $card-deck-margin;
+  }
+
+  @include media-breakpoint-up(sm) {
+    flex-flow: row wrap;
+    margin-right: -$card-deck-margin;
+    margin-left: -$card-deck-margin;
+
+    .card {
+      display: flex;
+      // Flexbugs #4: https://github.com/philipwalton/flexbugs#4-flex-shorthand-declarations-with-unitless-flex-basis-values-are-ignored
+      flex: 1 0 0%;
+      flex-direction: column;
+      margin-right: $card-deck-margin;
+      margin-bottom: 0; // Override the default
+      margin-left: $card-deck-margin;
+    }
+  }
+}
+
+
+//
+// Card groups
+//
+
+.card-group {
+  display: flex;
+  flex-direction: column;
+
+  .card {
+    margin-bottom: $card-group-margin;
+  }
+
+  @include media-breakpoint-up(sm) {
+    flex-flow: row wrap;
+
+    .card {
+      // Flexbugs #4: https://github.com/philipwalton/flexbugs#4-flex-shorthand-declarations-with-unitless-flex-basis-values-are-ignored
+      flex: 1 0 0%;
+      margin-bottom: 0;
+
+      + .card {
+        margin-left: 0;
+        border-left: 0;
+      }
+
+      // Handle rounded corners
+      @if $enable-rounded {
+        &:first-child {
+          @include border-right-radius(0);
+
+          .card-img-top {
+            border-top-right-radius: 0;
+          }
+          .card-img-bottom {
+            border-bottom-right-radius: 0;
+          }
+        }
+
+        &:last-child {
+          @include border-left-radius(0);
+
+          .card-img-top {
+            border-top-left-radius: 0;
+          }
+          .card-img-bottom {
+            border-bottom-left-radius: 0;
+          }
+        }
+
+        &:only-child {
+          @include border-radius($card-border-radius);
+
+          .card-img-top {
+            @include border-top-radius($card-border-radius);
+          }
+          .card-img-bottom {
+            @include border-bottom-radius($card-border-radius);
+          }
+        }
+
+        &:not(:first-child):not(:last-child):not(:only-child) {
+          border-radius: 0;
+
+          .card-img-top,
+          .card-img-bottom {
+            border-radius: 0;
+          }
+        }
+      }
+    }
+  }
+}
+
+
+//
+// Columns
+//
+
+.card-columns {
+  .card {
+    margin-bottom: $card-columns-margin;
+  }
+
+  @include media-breakpoint-up(sm) {
+    column-count: $card-columns-count;
+    column-gap: $card-columns-gap;
+
+    .card {
+      display: inline-block; // Don't let them vertically span multiple columns
+      width: 100%; // Don't let their width change
+    }
+  }
+}
diff --git a/scss/placeholders/_carousel.scss b/scss/placeholders/_carousel.scss
new file mode 100644
index 0000000000000000000000000000000000000000..c3c207387c9b3ee180b7fe4bd8c0530064c9d901
--- /dev/null
+++ b/scss/placeholders/_carousel.scss
@@ -0,0 +1,191 @@
+// Wrapper for the slide container and indicators
+.carousel {
+  position: relative;
+}
+
+.carousel-inner {
+  position: relative;
+  width: 100%;
+  overflow: hidden;
+}
+
+.carousel-item {
+  position: relative;
+  display: none;
+  align-items: center;
+  width: 100%;
+  @include transition($carousel-transition);
+  backface-visibility: hidden;
+  perspective: 1000px;
+}
+
+.carousel-item.active,
+.carousel-item-next,
+.carousel-item-prev {
+  display: block;
+}
+
+.carousel-item-next,
+.carousel-item-prev {
+  position: absolute;
+  top: 0;
+}
+
+// CSS3 transforms when supported by the browser
+.carousel-item-next.carousel-item-left,
+.carousel-item-prev.carousel-item-right {
+  transform: translateX(0);
+
+  @supports (transform-style: preserve-3d) {
+    transform: translate3d(0, 0, 0);
+  }
+}
+
+.carousel-item-next,
+.active.carousel-item-right {
+  transform: translateX(100%);
+
+  @supports (transform-style: preserve-3d) {
+    transform: translate3d(100%, 0, 0);
+  }
+}
+
+.carousel-item-prev,
+.active.carousel-item-left {
+  transform: translateX(-100%);
+
+  @supports (transform-style: preserve-3d) {
+    transform: translate3d(-100%, 0, 0);
+  }
+}
+
+
+//
+// Left/right controls for nav
+//
+
+.carousel-control-prev,
+.carousel-control-next {
+  position: absolute;
+  top: 0;
+  bottom: 0;
+  // Use flex for alignment (1-3)
+  display: flex; // 1. allow flex styles
+  align-items: center; // 2. vertically center contents
+  justify-content: center; // 3. horizontally center contents
+  width: $carousel-control-width;
+  color: $carousel-control-color;
+  text-align: center;
+  opacity: $carousel-control-opacity;
+  // We can't have a transition here because WebKit cancels the carousel
+  // animation if you trip this while in the middle of another animation.
+
+  // Hover/focus state
+  @include hover-focus {
+    color: $carousel-control-color;
+    text-decoration: none;
+    outline: 0;
+    opacity: .9;
+  }
+}
+.carousel-control-prev {
+  left: 0;
+  @if $enable-gradients {
+    background: linear-gradient(90deg, rgba(0,0,0,.25), rgba(0,0,0,.001));
+  }
+}
+.carousel-control-next {
+  right: 0;
+  @if $enable-gradients {
+    background: linear-gradient(270deg, rgba(0,0,0,.25), rgba(0,0,0,.001));
+  }
+}
+
+// Icons for within
+.carousel-control-prev-icon,
+.carousel-control-next-icon {
+  display: inline-block;
+  width: $carousel-control-icon-width;
+  height: $carousel-control-icon-width;
+  background: transparent no-repeat center center;
+  background-size: 100% 100%;
+}
+.carousel-control-prev-icon {
+  background-image: $carousel-control-prev-icon-bg;
+}
+.carousel-control-next-icon {
+  background-image: $carousel-control-next-icon-bg;
+}
+
+
+// Optional indicator pips
+//
+// Add an ordered list with the following class and add a list item for each
+// slide your carousel holds.
+
+.carousel-indicators {
+  position: absolute;
+  right: 0;
+  bottom: 10px;
+  left: 0;
+  z-index: 15;
+  display: flex;
+  justify-content: center;
+  padding-left: 0; // override <ol> default
+  // Use the .carousel-control's width as margin so we don't overlay those
+  margin-right: $carousel-control-width;
+  margin-left: $carousel-control-width;
+  list-style: none;
+
+  li {
+    position: relative;
+    flex: 0 1 auto;
+    width: $carousel-indicator-width;
+    height: $carousel-indicator-height;
+    margin-right: $carousel-indicator-spacer;
+    margin-left: $carousel-indicator-spacer;
+    text-indent: -999px;
+    background-color: rgba($carousel-indicator-active-bg, .5);
+
+    // Use pseudo classes to increase the hit area by 10px on top and bottom.
+    &::before {
+      position: absolute;
+      top: -10px;
+      left: 0;
+      display: inline-block;
+      width: 100%;
+      height: 10px;
+      content: "";
+    }
+    &::after {
+      position: absolute;
+      bottom: -10px;
+      left: 0;
+      display: inline-block;
+      width: 100%;
+      height: 10px;
+      content: "";
+    }
+  }
+
+  .active {
+    background-color: $carousel-indicator-active-bg;
+  }
+}
+
+
+// Optional captions
+//
+//
+
+.carousel-caption {
+  position: absolute;
+  right: ((100% - $carousel-caption-width) / 2);
+  bottom: 20px;
+  left: ((100% - $carousel-caption-width) / 2);
+  z-index: 10;
+  padding-top: 20px;
+  padding-bottom: 20px;
+  color: $carousel-caption-color;
+  text-align: center;
+}
diff --git a/scss/placeholders/_close.scss b/scss/placeholders/_close.scss
new file mode 100644
index 0000000000000000000000000000000000000000..897d4868443ab748ecd4cd22ce437ec2bda010a9
--- /dev/null
+++ b/scss/placeholders/_close.scss
@@ -0,0 +1,29 @@
+.close {
+  float: right;
+  font-size: $close-font-size;
+  font-weight: $close-font-weight;
+  line-height: 1;
+  color: $close-color;
+  text-shadow: $close-text-shadow;
+  opacity: .5;
+
+  @include hover-focus {
+    color: $close-color;
+    text-decoration: none;
+    opacity: .75;
+  }
+}
+
+// Additional properties for button version
+// iOS requires the button element instead of an anchor tag.
+// If you want the anchor version, it requires `href="#"`.
+// See https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile
+
+// stylelint-disable property-no-vendor-prefix, selector-no-qualifying-type
+button.close {
+  padding: 0;
+  background: transparent;
+  border: 0;
+  -webkit-appearance: none;
+}
+// stylelint-enable
diff --git a/scss/_code.scss b/scss/placeholders/_code.scss
similarity index 78%
rename from scss/_code.scss
rename to scss/placeholders/_code.scss
index b88f5b61dee156f49935fb361ea40fb9da048179..d7180a46ef6fc44fa1073e60718e126bafe5f6b1 100644
--- a/scss/_code.scss
+++ b/scss/placeholders/_code.scss
@@ -1,29 +1,30 @@
 // Inline and block code styles
-code,
-kbd,
-pre,
-samp {
+%code,
+%kbd,
+%pre,
+%samp {
   font-family: $font-family-monospace;
 }
 
 // Inline code
-code {
+%code {
   padding: $code-padding-y $code-padding-x;
   font-size: $code-font-size;
   color: $code-color;
   background-color: $code-bg;
   @include border-radius($border-radius);
 
-  // Streamline the style when inside anchors to avoid broken underline and more
-  a > & {
-    padding: 0;
-    color: inherit;
-    background-color: inherit;
-  }
 }
+// Streamline the style when inside anchors to avoid broken underline and more
+%a_code {
+  padding: 0;
+  color: inherit;
+  background-color: inherit;
+}
+
 
 // User input typically entered via keyboard
-kbd {
+%kbd {
   padding: $code-padding-y $code-padding-x;
   font-size: $code-font-size;
   color: $kbd-color;
@@ -31,7 +32,7 @@ kbd {
   @include border-radius($border-radius-sm);
   @include box-shadow($kbd-box-shadow);
 
-  kbd {
+  &__kbd {
     padding: 0;
     font-size: 100%;
     font-weight: $nested-kbd-font-weight;
@@ -40,13 +41,15 @@ kbd {
 }
 
 // Blocks of code
-pre {
+%pre {
   display: block;
+  margin-top: 0;
+  margin-bottom: 1rem;
   font-size: $code-font-size;
   color: $pre-color;
 
   // Account for some code outputs that place code tags in pre tags
-  code {
+  &__code {
     padding: 0;
     font-size: inherit;
     color: inherit;
@@ -56,7 +59,7 @@ pre {
 }
 
 // Enable scrollable blocks of code
-.pre-scrollable {
+%pre-scrollable {
   max-height: $pre-scrollable-max-height;
   overflow-y: scroll;
 }
diff --git a/scss/placeholders/_custom-forms.scss b/scss/placeholders/_custom-forms.scss
new file mode 100644
index 0000000000000000000000000000000000000000..a521dbdc9445db37c507e036abb7c73b8b6055b6
--- /dev/null
+++ b/scss/placeholders/_custom-forms.scss
@@ -0,0 +1,257 @@
+// Embedded icons from Open Iconic.
+// Released under MIT and copyright 2014 Waybury.
+// https://useiconic.com/open
+
+
+// Checkboxes and radios
+//
+// Base class takes care of all the key behavioral aspects.
+
+.custom-control {
+  position: relative;
+  display: inline-flex;
+  min-height: (1rem * $line-height-base);
+  padding-left: $custom-control-gutter;
+  margin-right: $custom-control-spacer-x;
+}
+
+.custom-control-input {
+  position: absolute;
+  z-index: -1; // Put the input behind the label so it doesn't overlay text
+  opacity: 0;
+
+  &:checked ~ .custom-control-indicator {
+    color: $custom-control-indicator-checked-color;
+    @include gradient-bg($custom-control-indicator-checked-bg);
+    @include box-shadow($custom-control-indicator-checked-box-shadow);
+  }
+
+  &:focus ~ .custom-control-indicator {
+    // the mixin is not used here to make sure there is feedback
+    box-shadow: $custom-control-indicator-focus-box-shadow;
+  }
+
+  &:active ~ .custom-control-indicator {
+    color: $custom-control-indicator-active-color;
+    @include gradient-bg($custom-control-indicator-active-bg);
+    @include box-shadow($custom-control-indicator-active-box-shadow);
+  }
+
+  &:disabled {
+    ~ .custom-control-indicator {
+      background-color: $custom-control-indicator-disabled-bg;
+    }
+
+    ~ .custom-control-description {
+      color: $custom-control-description-disabled-color;
+    }
+  }
+}
+
+// Custom indicator
+//
+// Generates a shadow element to create our makeshift checkbox/radio background.
+
+.custom-control-indicator {
+  position: absolute;
+  top: (($line-height-base - $custom-control-indicator-size) / 2);
+  left: 0;
+  display: block;
+  width: $custom-control-indicator-size;
+  height: $custom-control-indicator-size;
+  pointer-events: none;
+  user-select: none;
+  background-color: $custom-control-indicator-bg;
+  background-repeat: no-repeat;
+  background-position: center center;
+  background-size: $custom-control-indicator-bg-size;
+  @include box-shadow($custom-control-indicator-box-shadow);
+}
+
+// Checkboxes
+//
+// Tweak just a few things for checkboxes.
+
+.custom-checkbox {
+  .custom-control-indicator {
+    @include border-radius($custom-checkbox-indicator-border-radius);
+  }
+
+  .custom-control-input:checked ~ .custom-control-indicator {
+    background-image: $custom-checkbox-indicator-icon-checked;
+  }
+
+  .custom-control-input:indeterminate ~ .custom-control-indicator {
+    background-color: $custom-checkbox-indicator-indeterminate-bg;
+    background-image: $custom-checkbox-indicator-icon-indeterminate;
+    @include box-shadow($custom-checkbox-indicator-indeterminate-box-shadow);
+  }
+}
+
+// Radios
+//
+// Tweak just a few things for radios.
+
+.custom-radio {
+  .custom-control-indicator {
+    border-radius: $custom-radio-indicator-border-radius;
+  }
+
+  .custom-control-input:checked ~ .custom-control-indicator {
+    background-image: $custom-radio-indicator-icon-checked;
+  }
+}
+
+
+// Layout options
+//
+// By default radios and checkboxes are `inline-block` with no additional spacing
+// set. Use these optional classes to tweak the layout.
+
+.custom-controls-stacked {
+  display: flex;
+  flex-direction: column;
+
+  .custom-control {
+    margin-bottom: $custom-control-spacer-y;
+
+    + .custom-control {
+      margin-left: 0;
+    }
+  }
+}
+
+
+// Select
+//
+// Replaces the browser default select with a custom one, mostly pulled from
+// http://primercss.io.
+//
+
+.custom-select {
+  display: inline-block;
+  max-width: 100%;
+  height: $input-height;
+  padding: $custom-select-padding-y ($custom-select-padding-x + $custom-select-indicator-padding) $custom-select-padding-y $custom-select-padding-x;
+  line-height: $custom-select-line-height;
+  color: $custom-select-color;
+  vertical-align: middle;
+  background: $custom-select-bg $custom-select-indicator no-repeat right $custom-select-padding-x center;
+  background-size: $custom-select-bg-size;
+  border: $custom-select-border-width solid $custom-select-border-color;
+  @if $enable-rounded {
+    border-radius: $custom-select-border-radius;
+  } @else {
+    border-radius: 0;
+  }
+  appearance: none;
+
+  &:focus {
+    border-color: $custom-select-focus-border-color;
+    outline: none;
+    @include box-shadow($custom-select-focus-box-shadow);
+
+    &::-ms-value {
+      // For visual consistency with other platforms/browsers,
+      // supress the default white text on blue background highlight given to
+      // the selected option text when the (still closed) <select> receives focus
+      // in IE and (under certain conditions) Edge.
+      // See https://github.com/twbs/bootstrap/issues/19398.
+      color: $input-color;
+      background-color: $input-bg;
+    }
+  }
+
+  &[multiple] {
+    height: auto;
+    background-image: none;
+  }
+
+  &:disabled {
+    color: $custom-select-disabled-color;
+    background-color: $custom-select-disabled-bg;
+  }
+
+  // Hides the default caret in IE11
+  &::-ms-expand {
+    opacity: 0;
+  }
+}
+
+.custom-select-sm {
+  height: $custom-select-height-sm;
+  padding-top: $custom-select-padding-y;
+  padding-bottom: $custom-select-padding-y;
+  font-size: $custom-select-font-size-sm;
+}
+
+
+// File
+//
+// Custom file input.
+
+.custom-file {
+  position: relative;
+  display: inline-block;
+  max-width: 100%;
+  height: $custom-file-height;
+  margin-bottom: 0;
+}
+
+.custom-file-input {
+  min-width: $custom-file-width;
+  max-width: 100%;
+  height: $custom-file-height;
+  margin: 0;
+  opacity: 0;
+
+  &:focus ~ .custom-file-control {
+    box-shadow: $custom-file-focus-box-shadow;
+  }
+}
+
+.custom-file-control {
+  position: absolute;
+  top: 0;
+  right: 0;
+  left: 0;
+  z-index: 5;
+  height: $custom-file-height;
+  padding: $custom-file-padding-y $custom-file-padding-x;
+  line-height: $custom-file-line-height;
+  color: $custom-file-color;
+  pointer-events: none;
+  user-select: none;
+  background-color: $custom-file-bg;
+  border: $custom-file-border-width solid $custom-file-border-color;
+  @include border-radius($custom-file-border-radius);
+  @include box-shadow($custom-file-box-shadow);
+
+  @each $lang, $text in map-get($custom-file-text, placeholder) {
+    &:lang(#{$lang}):empty::after {
+      content: $text;
+    }
+  }
+
+  &::before {
+    position: absolute;
+    top: -$custom-file-border-width;
+    right: -$custom-file-border-width;
+    bottom: -$custom-file-border-width;
+    z-index: 6;
+    display: block;
+    height: $custom-file-height;
+    padding: $custom-file-padding-y $custom-file-padding-x;
+    line-height: $custom-file-line-height;
+    color: $custom-file-button-color;
+    @include gradient-bg($custom-file-button-bg);
+    border: $custom-file-border-width solid $custom-file-border-color;
+    @include border-radius(0 $custom-file-border-radius $custom-file-border-radius 0);
+  }
+
+  @each $lang, $text in map-get($custom-file-text, button-label) {
+    &:lang(#{$lang})::before {
+      content: $text;
+    }
+  }
+}
diff --git a/scss/placeholders/_dropdown.scss b/scss/placeholders/_dropdown.scss
new file mode 100644
index 0000000000000000000000000000000000000000..daa867a573e5cc5e4d28959ac75fa08a41676f5e
--- /dev/null
+++ b/scss/placeholders/_dropdown.scss
@@ -0,0 +1,103 @@
+// The dropdown wrapper (`<div>`)
+.dropup,
+.dropdown {
+  position: relative;
+}
+
+.dropdown-toggle {
+  // Generate the caret automatically
+  @include caret;
+}
+
+// The dropdown menu
+.dropdown-menu {
+  position: absolute;
+  top: 100%;
+  left: 0;
+  z-index: $zindex-dropdown;
+  display: none; // none by default, but block on "open" of the menu
+  float: left;
+  min-width: $dropdown-min-width;
+  padding: $dropdown-padding-y 0;
+  margin: $dropdown-spacer 0 0; // override default ul
+  font-size: $font-size-base; // Redeclare because nesting can cause inheritance issues
+  color: $body-color;
+  text-align: left; // Ensures proper alignment if parent has it changed (e.g., modal footer)
+  list-style: none;
+  background-color: $dropdown-bg;
+  background-clip: padding-box;
+  border: $dropdown-border-width solid $dropdown-border-color;
+  @include border-radius($border-radius);
+  @include box-shadow($dropdown-box-shadow);
+}
+
+// Allow for dropdowns to go bottom up (aka, dropup-menu)
+// Just add .dropup after the standard .dropdown class and you're set.
+.dropup {
+  .dropdown-menu {
+    margin-top: 0;
+    margin-bottom: $dropdown-spacer;
+  }
+
+  .dropdown-toggle {
+    @include caret(up);
+  }
+}
+
+// Dividers (basically an `<hr>`) within the dropdown
+.dropdown-divider {
+  @include nav-divider($dropdown-divider-bg);
+}
+
+// Links, buttons, and more within the dropdown menu
+//
+// `<button>`-specific styles are denoted with `// For <button>s`
+.dropdown-item {
+  display: block;
+  width: 100%; // For `<button>`s
+  padding: $dropdown-item-padding-y $dropdown-item-padding-x;
+  clear: both;
+  font-weight: $font-weight-normal;
+  color: $dropdown-link-color;
+  text-align: inherit; // For `<button>`s
+  white-space: nowrap; // prevent links from randomly breaking onto new lines
+  background: none; // For `<button>`s
+  border: 0; // For `<button>`s
+
+  @include hover-focus {
+    color: $dropdown-link-hover-color;
+    text-decoration: none;
+    @include gradient-bg($dropdown-link-hover-bg);
+  }
+
+  &.active,
+  &:active {
+    color: $dropdown-link-active-color;
+    text-decoration: none;
+    @include gradient-bg($dropdown-link-active-bg);
+  }
+
+  &.disabled,
+  &:disabled {
+    color: $dropdown-link-disabled-color;
+    background-color: transparent;
+    // Remove CSS gradients if they're enabled
+    @if $enable-gradients {
+      background-image: none;
+    }
+  }
+}
+
+.dropdown-menu.show {
+  display: block;
+}
+
+// Dropdown section headers
+.dropdown-header {
+  display: block;
+  padding: $dropdown-padding-y $dropdown-item-padding-x;
+  margin-bottom: 0; // for use with heading elements
+  font-size: $font-size-sm;
+  color: $dropdown-header-color;
+  white-space: nowrap; // as with > li > a
+}
diff --git a/scss/placeholders/_forms.scss b/scss/placeholders/_forms.scss
new file mode 100644
index 0000000000000000000000000000000000000000..80bc7f3ba875f7ce222bff7ba42e074390b38d5b
--- /dev/null
+++ b/scss/placeholders/_forms.scss
@@ -0,0 +1,358 @@
+// stylelint-disable selector-no-qualifying-type
+
+//
+// Textual form controls
+//
+
+.form-control {
+  display: block;
+  width: 100%;
+  padding: $input-btn-padding-y $input-btn-padding-x;
+  font-size: $font-size-base;
+  line-height: $input-btn-line-height;
+  color: $input-color;
+  background-color: $input-bg;
+  // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214.
+  background-image: none;
+  background-clip: padding-box;
+  border: $input-btn-border-width solid $input-border-color;
+
+  // Note: This has no effect on <select>s in some browsers, due to the limited stylability of `<select>`s in CSS.
+  @if $enable-rounded {
+    // Manually use the if/else instead of the mixin to account for iOS override
+    border-radius: $input-border-radius;
+  } @else {
+    // Otherwise undo the iOS default
+    border-radius: 0;
+  }
+
+  @include box-shadow($input-box-shadow);
+  @include transition($input-transition);
+
+  // Unstyle the caret on `<select>`s in IE10+.
+  &::-ms-expand {
+    background-color: transparent;
+    border: 0;
+  }
+
+  // Customize the `:focus` state to imitate native WebKit styles.
+  @include form-control-focus();
+
+  // Placeholder
+  &::placeholder {
+    color: $input-placeholder-color;
+    // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526.
+    opacity: 1;
+  }
+
+  // Disabled and read-only inputs
+  //
+  // HTML5 says that controls under a fieldset > legend:first-child won't be
+  // disabled if the fieldset is disabled. Due to implementation difficulty, we
+  // don't honor that edge case; we style them as disabled anyway.
+  &:disabled,
+  &[readonly] {
+    background-color: $input-disabled-bg;
+    // iOS fix for unreadable disabled content; see https://github.com/twbs/bootstrap/issues/11655.
+    opacity: 1;
+  }
+}
+
+select.form-control {
+  &:not([size]):not([multiple]) {
+    height: $input-height;
+  }
+
+  &:focus::-ms-value {
+    // Suppress the nested default white text on blue background highlight given to
+    // the selected option text when the (still closed) <select> receives focus
+    // in IE and (under certain conditions) Edge, as it looks bad and cannot be made to
+    // match the appearance of the native widget.
+    // See https://github.com/twbs/bootstrap/issues/19398.
+    color: $input-color;
+    background-color: $input-bg;
+  }
+}
+
+// Make file inputs better match text inputs by forcing them to new lines.
+.form-control-file,
+.form-control-range {
+  display: block;
+}
+
+
+//
+// Labels
+//
+
+// For use with horizontal and inline forms, when you need the label text to
+// align with the form controls.
+.col-form-label {
+  padding-top: calc(#{$input-btn-padding-y} + #{$input-btn-border-width});
+  padding-bottom: calc(#{$input-btn-padding-y} + #{$input-btn-border-width});
+  margin-bottom: 0; // Override the `<label>` default
+  line-height: $input-btn-line-height;
+}
+
+.col-form-label-lg {
+  padding-top: calc(#{$input-btn-padding-y-lg} + #{$input-btn-border-width});
+  padding-bottom: calc(#{$input-btn-padding-y-lg} + #{$input-btn-border-width});
+  font-size: $font-size-lg;
+  line-height: $input-btn-line-height-lg;
+}
+
+.col-form-label-sm {
+  padding-top: calc(#{$input-btn-padding-y-sm} + #{$input-btn-border-width});
+  padding-bottom: calc(#{$input-btn-padding-y-sm} + #{$input-btn-border-width});
+  font-size: $font-size-sm;
+  line-height: $input-btn-line-height-sm;
+}
+
+
+//
+// Legends
+//
+
+// For use with horizontal and inline forms, when you need the legend text to
+// be the same size as regular labels, and to align with the form controls.
+.col-form-legend {
+  padding-top: $input-btn-padding-y;
+  padding-bottom: $input-btn-padding-y;
+  margin-bottom: 0;
+  font-size: $font-size-base;
+}
+
+
+// Readonly controls as plain text
+//
+// Apply class to a readonly input to make it appear like regular plain
+// text (without any border, background color, focus indicator)
+
+.form-control-plaintext {
+  padding-top: $input-btn-padding-y;
+  padding-bottom: $input-btn-padding-y;
+  margin-bottom: 0; // match inputs if this class comes on inputs with default margins
+  line-height: $input-btn-line-height;
+  background-color: transparent;
+  border: solid transparent;
+  border-width: $input-btn-border-width 0;
+
+  &.form-control-sm,
+  &.form-control-lg {
+    padding-right: 0;
+    padding-left: 0;
+  }
+}
+
+
+// Form control sizing
+//
+// Build on `.form-control` with modifier classes to decrease or increase the
+// height and font-size of form controls.
+//
+// The `.form-group-* form-control` variations are sadly duplicated to avoid the
+// issue documented in https://github.com/twbs/bootstrap/issues/15074.
+
+.form-control-sm {
+  padding: $input-btn-padding-y-sm $input-btn-padding-x-sm;
+  font-size: $font-size-sm;
+  line-height: $input-btn-line-height-sm;
+  @include border-radius($input-border-radius-sm);
+}
+
+select.form-control-sm {
+  &:not([size]):not([multiple]) {
+    height: $input-height-sm;
+  }
+}
+
+.form-control-lg {
+  padding: $input-btn-padding-y-lg $input-btn-padding-x-lg;
+  font-size: $font-size-lg;
+  line-height: $input-btn-line-height-lg;
+  @include border-radius($input-border-radius-lg);
+}
+
+select.form-control-lg {
+  &:not([size]):not([multiple]) {
+    height: $input-height-lg;
+  }
+}
+
+
+// Form groups
+//
+// Designed to help with the organization and spacing of vertical forms. For
+// horizontal forms, use the predefined grid classes.
+
+.form-group {
+  margin-bottom: $form-group-margin-bottom;
+}
+
+.form-text {
+  display: block;
+  margin-top: $form-text-margin-top;
+}
+
+
+// Form grid
+//
+// Special replacement for our grid system's `.row` for tighter form layouts.
+
+.form-row {
+  display: flex;
+  flex-wrap: wrap;
+  margin-right: -5px;
+  margin-left: -5px;
+
+  > .col,
+  > [class*="col-"] {
+    padding-right: 5px;
+    padding-left: 5px;
+  }
+}
+
+
+// Checkboxes and radios
+//
+// Indent the labels to position radios/checkboxes as hanging controls.
+
+.form-check {
+  position: relative;
+  display: block;
+  margin-bottom: $form-check-margin-bottom;
+
+  &.disabled {
+    .form-check-label {
+      color: $text-muted;
+    }
+  }
+}
+
+.form-check-label {
+  padding-left: $form-check-input-gutter;
+  margin-bottom: 0; // Override default `<label>` bottom margin
+}
+
+.form-check-input {
+  position: absolute;
+  margin-top: $form-check-input-margin-y;
+  margin-left: -$form-check-input-gutter;
+}
+
+// Radios and checkboxes on same line
+.form-check-inline {
+  display: inline-block;
+  margin-right: $form-check-inline-margin-x;
+
+  .form-check-label {
+    vertical-align: middle;
+  }
+}
+
+
+// Form validation
+//
+// Provide feedback to users when form field values are valid or invalid. Works
+// primarily for client-side validation via scoped `:invalid` and `:valid`
+// pseudo-classes but also includes `.is-invalid` and `.is-valid` classes for
+// server side validation.
+
+@include form-validation-state("valid", $form-feedback-valid-color);
+@include form-validation-state("invalid", $form-feedback-invalid-color);
+
+// Inline forms
+//
+// Make forms appear inline(-block) by adding the `.form-inline` class. Inline
+// forms begin stacked on extra small (mobile) devices and then go inline when
+// viewports reach <768px.
+//
+// Requires wrapping inputs and labels with `.form-group` for proper display of
+// default HTML form controls and our custom form controls (e.g., input groups).
+
+.form-inline {
+  display: flex;
+  flex-flow: row wrap;
+  align-items: center; // Prevent shorter elements from growing to same height as others (e.g., small buttons growing to normal sized button height)
+
+  // Because we use flex, the initial sizing of checkboxes is collapsed and
+  // doesn't occupy the full-width (which is what we want for xs grid tier),
+  // so we force that here.
+  .form-check {
+    width: 100%;
+  }
+
+  // Kick in the inline
+  @include media-breakpoint-up(sm) {
+    label {
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      margin-bottom: 0;
+    }
+
+    // Inline-block all the things for "inline"
+    .form-group {
+      display: flex;
+      flex: 0 0 auto;
+      flex-flow: row wrap;
+      align-items: center;
+      margin-bottom: 0;
+    }
+
+    // Allow folks to *not* use `.form-group`
+    .form-control {
+      display: inline-block;
+      width: auto; // Prevent labels from stacking above inputs in `.form-group`
+      vertical-align: middle;
+    }
+
+    // Make static controls behave like regular ones
+    .form-control-plaintext {
+      display: inline-block;
+    }
+
+    .input-group {
+      width: auto;
+    }
+
+    // Remove default margin on radios/checkboxes that were used for stacking, and
+    // then undo the floating of radios and checkboxes to match.
+    .form-check {
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      width: auto;
+      margin-top: 0;
+      margin-bottom: 0;
+    }
+    .form-check-label {
+      padding-left: 0;
+    }
+    .form-check-input {
+      position: relative;
+      margin-top: 0;
+      margin-right: $form-check-input-margin-x;
+      margin-left: 0;
+    }
+
+    // Custom form controls
+    .custom-control {
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      padding-left: 0;
+    }
+    .custom-control-indicator {
+      position: static;
+      display: inline-block;
+      margin-right: $form-check-input-margin-x; // Flexbox alignment means we lose our HTML space here, so we compensate.
+      vertical-align: text-bottom;
+    }
+
+    // Re-override the feedback icon.
+    .has-feedback .form-control-feedback {
+      top: 0;
+    }
+  }
+}
diff --git a/scss/_grid.scss b/scss/placeholders/_grid.scss
similarity index 87%
rename from scss/_grid.scss
rename to scss/placeholders/_grid.scss
index a227515379c4bd9979039bc0e86ca3626123b96b..7173501e40979324620b9b4d2db7f83cb1c418ef 100644
--- a/scss/_grid.scss
+++ b/scss/placeholders/_grid.scss
@@ -3,7 +3,7 @@
 // Set the container width, and override it for fixed navbars in media queries.
 
 @if $enable-grid-classes {
-  .container {
+  %container {
     @include make-container();
     @include make-container-max-widths();
   }
@@ -15,7 +15,7 @@
 // fluid, full width layouts.
 
 @if $enable-grid-classes {
-  .container-fluid {
+  %container-fluid {
     @include make-container();
   }
 }
@@ -25,18 +25,17 @@
 // Rows contain and clear the floats of your columns.
 
 @if $enable-grid-classes {
-  .row {
+  %row {
     @include make-row();
   }
 
   // Remove the negative margin from default .row, then the horizontal padding
   // from all immediate children columns (to prevent runaway style inheritance).
-  .no-gutters {
+  %no-gutters {
     margin-right: 0;
     margin-left: 0;
 
-    > .col,
-    > [class*="col-"] {
+    &_col {
       padding-right: 0;
       padding-left: 0;
     }
@@ -48,5 +47,5 @@
 // Common styles for small and large grid columns
 
 @if $enable-grid-classes {
-  @include make-grid-columns();
+  @include make-grid-columns-placeholders();
 }
diff --git a/scss/_images.scss b/scss/placeholders/_images.scss
similarity index 93%
rename from scss/_images.scss
rename to scss/placeholders/_images.scss
index 50c56108a9174734a38ae9142dedb378d3739a56..ce410cc17a7a4019eb1f7a402fb6537b7a40b815 100644
--- a/scss/_images.scss
+++ b/scss/placeholders/_images.scss
@@ -5,13 +5,13 @@
 // and abandoned it in Bootstrap v3 because it breaks lots of third-party widgets (including Google Maps)
 // which weren't expecting the images within themselves to be involuntarily resized.
 // See also https://github.com/twbs/bootstrap/issues/18178
-.img-fluid {
+%img-fluid {
   @include img-fluid;
 }
 
 
 // Image thumbnails
-.img-thumbnail {
+%img-thumbnail {
   padding: $thumbnail-padding;
   background-color: $thumbnail-bg;
   border: $thumbnail-border-width solid $thumbnail-border-color;
@@ -27,17 +27,17 @@
 // Figures
 //
 
-.figure {
+%figure {
   // Ensures the caption's text aligns with the image.
   display: inline-block;
 }
 
-.figure-img {
+%figure-img {
   margin-bottom: ($spacer / 2);
   line-height: 1;
 }
 
-.figure-caption {
+%figure-caption {
   font-size: $figure-caption-font-size;
   color: $figure-caption-color;
 }
diff --git a/scss/placeholders/_input-group.scss b/scss/placeholders/_input-group.scss
new file mode 100644
index 0000000000000000000000000000000000000000..a1d16e3848e7fd773951d9a3f9753179dcb30eb1
--- /dev/null
+++ b/scss/placeholders/_input-group.scss
@@ -0,0 +1,186 @@
+// stylelint-disable selector-no-qualifying-type
+
+//
+// Base styles
+//
+
+.input-group {
+  position: relative;
+  display: flex;
+  align-items: stretch;
+  width: 100%;
+
+  .form-control {
+    // Ensure that the input is always above the *appended* addon button for
+    // proper border colors.
+    position: relative;
+    z-index: 2;
+    flex: 1 1 auto;
+    // Add width 1% and flex-basis auto to ensure that button will not wrap out
+    // the column. Applies to IE Edge+ and Firefox. Chrome does not require this.
+    width: 1%;
+    margin-bottom: 0;
+
+    // Bring the "active" form control to the front
+    @include hover-focus-active {
+      z-index: 3;
+    }
+  }
+}
+
+.input-group-addon,
+.input-group-btn,
+.input-group .form-control {
+  display: flex;
+  align-items: center;
+  &:not(:first-child):not(:last-child) {
+    @include border-radius(0);
+  }
+}
+
+.input-group-addon,
+.input-group-btn {
+  white-space: nowrap;
+}
+
+
+// Sizing options
+//
+// Remix the default form control sizing classes into new ones for easier
+// manipulation.
+
+.input-group-lg > .form-control,
+.input-group-lg > .input-group-addon,
+.input-group-lg > .input-group-btn > .btn {
+  @extend .form-control-lg;
+}
+.input-group-sm > .form-control,
+.input-group-sm > .input-group-addon,
+.input-group-sm > .input-group-btn > .btn {
+  @extend .form-control-sm;
+}
+
+
+//
+// Text input groups
+//
+
+.input-group-addon {
+  padding: $input-btn-padding-y $input-btn-padding-x;
+  margin-bottom: 0; // Allow use of <label> elements by overriding our default margin-bottom
+  font-size: $font-size-base; // Match inputs
+  font-weight: $font-weight-normal;
+  line-height: $input-btn-line-height;
+  color: $input-group-addon-color;
+  text-align: center;
+  background-color: $input-group-addon-bg;
+  border: $input-btn-border-width solid $input-group-addon-border-color;
+  @include border-radius($input-border-radius);
+
+  // Sizing
+  &.form-control-sm {
+    padding: $input-btn-padding-y-sm $input-btn-padding-x-sm;
+    font-size: $font-size-sm;
+    @include border-radius($input-border-radius-sm);
+  }
+
+  &.form-control-lg {
+    padding: $input-btn-padding-y-lg $input-btn-padding-x-lg;
+    font-size: $font-size-lg;
+    @include border-radius($input-border-radius-lg);
+  }
+
+  // Nuke default margins from checkboxes and radios to vertically center within.
+  input[type="radio"],
+  input[type="checkbox"] {
+    margin-top: 0;
+  }
+}
+
+
+//
+// Reset rounded corners
+//
+
+.input-group .form-control:not(:last-child),
+.input-group-addon:not(:last-child),
+.input-group-btn:not(:last-child) > .btn,
+.input-group-btn:not(:last-child) > .btn-group > .btn,
+.input-group-btn:not(:last-child) > .dropdown-toggle,
+.input-group-btn:not(:first-child) > .btn:not(:last-child):not(.dropdown-toggle),
+.input-group-btn:not(:first-child) > .btn-group:not(:last-child) > .btn {
+  @include border-right-radius(0);
+}
+.input-group-addon:not(:last-child) {
+  border-right: 0;
+}
+.input-group .form-control:not(:first-child),
+.input-group-addon:not(:first-child),
+.input-group-btn:not(:first-child) > .btn,
+.input-group-btn:not(:first-child) > .btn-group > .btn,
+.input-group-btn:not(:first-child) > .dropdown-toggle,
+.input-group-btn:not(:last-child) > .btn:not(:first-child),
+.input-group-btn:not(:last-child) > .btn-group:not(:first-child) > .btn {
+  @include border-left-radius(0);
+}
+.form-control + .input-group-addon:not(:first-child) {
+  border-left: 0;
+}
+
+//
+// Button input groups
+//
+
+.input-group-btn {
+  position: relative;
+  align-items: stretch;
+  // Jankily prevent input button groups from wrapping with `white-space` and
+  // `font-size` in combination with `inline-block` on buttons.
+  font-size: 0;
+  white-space: nowrap;
+
+  // Negative margin for spacing, position for bringing hovered/focused/actived
+  // element above the siblings.
+  > .btn {
+    position: relative;
+
+    + .btn {
+      margin-left: (-$input-btn-border-width);
+    }
+
+    // Bring the "active" button to the front
+    @include hover-focus-active {
+      z-index: 3;
+    }
+  }
+
+  &:first-child > .btn + .btn {
+    margin-left: 0;
+  }
+
+  // Negative margin to only have a single, shared border between the two
+  &:not(:last-child) {
+    > .btn,
+    > .btn-group {
+      margin-right: (-$input-btn-border-width);
+    }
+  }
+  &:not(:first-child) {
+    > .btn,
+    > .btn-group {
+      z-index: 2;
+      // remove nagative margin ($input-btn-border-width) to solve overlapping issue with button.
+      margin-left: 0;
+
+      // When input is first, overlap the right side of it with the button(-group)
+      &:first-child {
+        margin-left: (-$input-btn-border-width);
+      }
+
+      // Because specificity
+      @include hover-focus-active {
+        z-index: 3;
+      }
+    }
+  }
+}
diff --git a/scss/placeholders/_jumbotron.scss b/scss/placeholders/_jumbotron.scss
new file mode 100644
index 0000000000000000000000000000000000000000..7966bba1e22a62689973b6cb377d97802e2c5bbb
--- /dev/null
+++ b/scss/placeholders/_jumbotron.scss
@@ -0,0 +1,16 @@
+.jumbotron {
+  padding: $jumbotron-padding ($jumbotron-padding / 2);
+  margin-bottom: $jumbotron-padding;
+  background-color: $jumbotron-bg;
+  @include border-radius($border-radius-lg);
+
+  @include media-breakpoint-up(sm) {
+    padding: ($jumbotron-padding * 2) $jumbotron-padding;
+  }
+}
+
+.jumbotron-fluid {
+  padding-right: 0;
+  padding-left: 0;
+  @include border-radius(0);
+}
diff --git a/scss/placeholders/_list-group.scss b/scss/placeholders/_list-group.scss
new file mode 100644
index 0000000000000000000000000000000000000000..7e0b19e01ea62dddbdc24199538675d0ee5a9b1c
--- /dev/null
+++ b/scss/placeholders/_list-group.scss
@@ -0,0 +1,114 @@
+// Base class
+//
+// Easily usable on <ul>, <ol>, or <div>.
+
+.list-group {
+  display: flex;
+  flex-direction: column;
+
+  // No need to set list-style: none; since .list-group-item is block level
+  padding-left: 0; // reset padding because ul and ol
+  margin-bottom: 0;
+}
+
+
+// Interactive list items
+//
+// Use anchor or button elements instead of `li`s or `div`s to create interactive
+// list items. Includes an extra `.active` modifier class for selected items.
+
+.list-group-item-action {
+  width: 100%; // For `<button>`s (anchors become 100% by default though)
+  color: $list-group-action-color;
+  text-align: inherit; // For `<button>`s (anchors inherit)
+
+  // Hover state
+  @include hover-focus {
+    color: $list-group-action-hover-color;
+    text-decoration: none;
+    background-color: $list-group-hover-bg;
+  }
+
+  &:active {
+    color: $list-group-action-active-color;
+    background-color: $list-group-action-active-bg;
+  }
+}
+
+
+// Individual list items
+//
+// Use on `li`s or `div`s within the `.list-group` parent.
+
+.list-group-item {
+  position: relative;
+  display: block;
+  padding: $list-group-item-padding-y $list-group-item-padding-x;
+  // Place the border on the list items and negative margin up for better styling
+  margin-bottom: -$list-group-border-width;
+  background-color: $list-group-bg;
+  border: $list-group-border-width solid $list-group-border-color;
+
+  &:first-child {
+    @include border-top-radius($list-group-border-radius);
+  }
+
+  &:last-child {
+    margin-bottom: 0;
+    @include border-bottom-radius($list-group-border-radius);
+  }
+
+  @include hover-focus {
+    text-decoration: none;
+  }
+
+  &.disabled,
+  &:disabled {
+    color: $list-group-disabled-color;
+    background-color: $list-group-disabled-bg;
+  }
+
+  // Include both here for `<a>`s and `<button>`s
+  &.active {
+    z-index: 2; // Place active items above their siblings for proper border styling
+    color: $list-group-active-color;
+    background-color: $list-group-active-bg;
+    border-color: $list-group-active-border-color;
+  }
+}
+
+
+// Flush list items
+//
+// Remove borders and border-radius to keep list group items edge-to-edge. Most
+// useful within other components (e.g., cards).
+
+.list-group-flush {
+  .list-group-item {
+    border-right: 0;
+    border-left: 0;
+    border-radius: 0;
+  }
+
+  &:first-child {
+    .list-group-item:first-child {
+      border-top: 0;
+    }
+  }
+
+  &:last-child {
+    .list-group-item:last-child {
+      border-bottom: 0;
+    }
+  }
+}
+
+
+// Contextual variants
+//
+// Add modifier classes to change text and background color on individual items.
+// Organizationally, this must come after the `:hover` states.
+
+@each $color, $value in $theme-colors {
+  @include list-group-item-variant($color, theme-color-level($color, -9), theme-color-level($color, 6));
+}
diff --git a/scss/placeholders/_media.scss b/scss/placeholders/_media.scss
new file mode 100644
index 0000000000000000000000000000000000000000..b573052c14affa5bdca02ac9e3e7a4168768925b
--- /dev/null
+++ b/scss/placeholders/_media.scss
@@ -0,0 +1,8 @@
+.media {
+  display: flex;
+  align-items: flex-start;
+}
+
+.media-body {
+  flex: 1;
+}
diff --git a/scss/placeholders/_modal.scss b/scss/placeholders/_modal.scss
new file mode 100644
index 0000000000000000000000000000000000000000..e655850e387366df7b3cc590229f7cf8621811d3
--- /dev/null
+++ b/scss/placeholders/_modal.scss
@@ -0,0 +1,153 @@
+// .modal-open      - body class for killing the scroll
+// .modal           - container to scroll within
+// .modal-dialog    - positioning shell for the actual modal
+// .modal-content   - actual modal w/ bg and corners and stuff
+
+
+// Kill the scroll on the body
+.modal-open {
+  overflow: hidden;
+}
+
+// Container that the modal scrolls within
+.modal {
+  position: fixed;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  z-index: $zindex-modal;
+  display: none;
+  overflow: hidden;
+  // Prevent Chrome on Windows from adding a focus outline. For details, see
+  // https://github.com/twbs/bootstrap/pull/10951.
+  outline: 0;
+  // We deliberately don't use `-webkit-overflow-scrolling: touch;` due to a
+  // gnarly iOS Safari bug: https://bugs.webkit.org/show_bug.cgi?id=158342
+  // See also https://github.com/twbs/bootstrap/issues/17695
+
+  // When fading in the modal, animate it to slide down
+  &.fade .modal-dialog {
+    @include transition($modal-transition);
+    transform: translate(0, -25%);
+  }
+  &.show .modal-dialog { transform: translate(0, 0); }
+}
+.modal-open .modal {
+  overflow-x: hidden;
+  overflow-y: auto;
+}
+
+// Shell div to position the modal with bottom padding
+.modal-dialog {
+  position: relative;
+  width: auto;
+  margin: $modal-dialog-margin;
+  // allow clicks to pass through for custom click handling to close modal
+  pointer-events: none;
+}
+
+// Actual modal
+.modal-content {
+  position: relative;
+  display: flex;
+  flex-direction: column;
+  // counteract the pointer-events: none; in the .modal-dialog
+  pointer-events: auto;
+  background-color: $modal-content-bg;
+  background-clip: padding-box;
+  border: $modal-content-border-width solid $modal-content-border-color;
+  @include border-radius($border-radius-lg);
+  @include box-shadow($modal-content-box-shadow-xs);
+  // Remove focus outline from opened modal
+  outline: 0;
+}
+
+// Modal background
+.modal-backdrop {
+  position: fixed;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  z-index: $zindex-modal-backdrop;
+  background-color: $modal-backdrop-bg;
+
+  // Fade for backdrop
+  &.fade { opacity: 0; }
+  &.show { opacity: $modal-backdrop-opacity; }
+}
+
+// Modal header
+// Top section of the modal w/ title and dismiss
+.modal-header {
+  display: flex;
+  align-items: flex-start; // so the close btn always stays on the upper right corner
+  justify-content: space-between; // Put modal header elements (title and dismiss) on opposite ends
+  padding: $modal-header-padding;
+  border-bottom: $modal-header-border-width solid $modal-header-border-color;
+  @include border-top-radius($border-radius-lg);
+
+  .close {
+    padding: $modal-header-padding;
+    // auto on the left force icon to the right even when there is no .modal-title
+    margin: (-$modal-header-padding) (-$modal-header-padding) (-$modal-header-padding) auto;
+  }
+}
+
+// Title text within header
+.modal-title {
+  margin-bottom: 0;
+  line-height: $modal-title-line-height;
+}
+
+// Modal body
+// Where all modal content resides (sibling of .modal-header and .modal-footer)
+.modal-body {
+  position: relative;
+  // Enable `flex-grow: 1` so that the body take up as much space as possible
+  // when should there be a fixed height on `.modal-dialog`.
+  flex: 1 1 auto;
+  padding: $modal-inner-padding;
+}
+
+// Footer (for actions)
+.modal-footer {
+  display: flex;
+  align-items: center; // vertically center
+  justify-content: flex-end; // Right align buttons with flex property because text-align doesn't work on flex items
+  padding: $modal-inner-padding;
+  border-top: $modal-footer-border-width solid $modal-footer-border-color;
+
+  // Easily place margin between footer elements
+  > :not(:first-child) { margin-left: .25rem; }
+  > :not(:last-child) { margin-right: .25rem; }
+}
+
+// Measure scrollbar width for padding body during modal show/hide
+.modal-scrollbar-measure {
+  position: absolute;
+  top: -9999px;
+  width: 50px;
+  height: 50px;
+  overflow: scroll;
+}
+
+// Scale up the modal
+@include media-breakpoint-up(sm) {
+  // Automatically set modal's width for larger viewports
+  .modal-dialog {
+    max-width: $modal-md;
+    margin: $modal-dialog-margin-y-sm-up auto;
+  }
+
+  .modal-content {
+    @include box-shadow($modal-content-box-shadow-sm-up);
+  }
+
+  .modal-sm { max-width: $modal-sm; }
+}
+
+@include media-breakpoint-up(lg) {
+  .modal-lg { max-width: $modal-lg; }
+}
diff --git a/scss/placeholders/_nav.scss b/scss/placeholders/_nav.scss
new file mode 100644
index 0000000000000000000000000000000000000000..14e76c9acc48792a6083de6a03c200140e03c9cf
--- /dev/null
+++ b/scss/placeholders/_nav.scss
@@ -0,0 +1,118 @@
+// Base class
+//
+// Kickstart any navigation component with a set of style resets. Works with
+// `<nav>`s or `<ul>`s.
+
+.nav {
+  display: flex;
+  flex-wrap: wrap;
+  padding-left: 0;
+  margin-bottom: 0;
+  list-style: none;
+}
+
+.nav-link {
+  display: block;
+  padding: $nav-link-padding-y $nav-link-padding-x;
+
+  @include hover-focus {
+    text-decoration: none;
+  }
+
+  // Disabled state lightens text
+  &.disabled {
+    color: $nav-link-disabled-color;
+  }
+}
+
+//
+// Tabs
+//
+
+.nav-tabs {
+  border-bottom: $nav-tabs-border-width solid $nav-tabs-border-color;
+
+  .nav-item {
+    margin-bottom: -$nav-tabs-border-width;
+  }
+
+  .nav-link {
+    border: $nav-tabs-border-width solid transparent;
+    @include border-top-radius($nav-tabs-border-radius);
+
+    @include hover-focus {
+      border-color: $nav-tabs-link-hover-border-color $nav-tabs-link-hover-border-color $nav-tabs-border-color;
+    }
+
+    &.disabled {
+      color: $nav-link-disabled-color;
+      background-color: transparent;
+      border-color: transparent;
+    }
+  }
+
+  .nav-link.active,
+  .nav-item.show .nav-link {
+    color: $nav-tabs-link-active-color;
+    background-color: $nav-tabs-link-active-bg;
+    border-color: $nav-tabs-link-active-border-color $nav-tabs-link-active-border-color $nav-tabs-link-active-bg;
+  }
+
+  .dropdown-menu {
+    // Make dropdown border overlap tab border
+    margin-top: -$nav-tabs-border-width;
+    // Remove the top rounded corners here since there is a hard edge above the menu
+    @include border-top-radius(0);
+  }
+}
+
+
+//
+// Pills
+//
+
+.nav-pills {
+  .nav-link {
+    @include border-radius($nav-pills-border-radius);
+  }
+
+  .nav-link.active,
+  .show > .nav-link {
+    color: $nav-pills-link-active-color;
+    background-color: $nav-pills-link-active-bg;
+  }
+}
+
+
+//
+// Justified variants
+//
+
+.nav-fill {
+  .nav-item {
+    flex: 1 1 auto;
+    text-align: center;
+  }
+}
+
+.nav-justified {
+  .nav-item {
+    flex-basis: 0;
+    flex-grow: 1;
+    text-align: center;
+  }
+}
+
+
+// Tabbable tabs
+//
+// Hide tabbable panes to start, show them when `.active`
+
+.tab-content {
+  > .tab-pane {
+    display: none;
+  }
+  > .active {
+    display: block;
+  }
+}
diff --git a/scss/placeholders/_navbar.scss b/scss/placeholders/_navbar.scss
new file mode 100644
index 0000000000000000000000000000000000000000..6b023e82e4001979088b95a2f12366b0b80c3108
--- /dev/null
+++ b/scss/placeholders/_navbar.scss
@@ -0,0 +1,306 @@
+// Contents
+//
+// Navbar
+// Navbar brand
+// Navbar nav
+// Navbar text
+// Navbar divider
+// Responsive navbar
+// Navbar position
+// Navbar themes
+
+
+// Navbar
+//
+// Provide a static navbar from which we expand to create full-width, fixed, and
+// other navbar variations.
+
+.navbar {
+  position: relative;
+  display: flex;
+  flex-wrap: wrap; // allow us to do the line break for collapsing content
+  align-items: center;
+  justify-content: space-between; // space out brand from logo
+  padding: $navbar-padding-y $navbar-padding-x;
+
+  // Because flex properties aren't inherited, we need to redeclare these first
+  // few properities so that content nested within behave properly.
+  > .container,
+  > .container-fluid {
+    display: flex;
+    flex-wrap: wrap;
+    align-items: center;
+    justify-content: space-between;
+  }
+}
+
+
+// Navbar brand
+//
+// Used for brand, project, or site names.
+
+.navbar-brand {
+  display: inline-block;
+  padding-top: $navbar-brand-padding-y;
+  padding-bottom: $navbar-brand-padding-y;
+  margin-right: $navbar-padding-x;
+  font-size: $navbar-brand-font-size;
+  line-height: inherit;
+  white-space: nowrap;
+
+  @include hover-focus {
+    text-decoration: none;
+  }
+}
+
+
+// Navbar nav
+//
+// Custom navbar navigation (doesn't require `.nav`, but does make use of `.nav-link`).
+
+.navbar-nav {
+  display: flex;
+  flex-direction: column; // cannot use `inherit` to get the `.navbar`s value
+  padding-left: 0;
+  margin-bottom: 0;
+  list-style: none;
+
+  .nav-link {
+    padding-right: 0;
+    padding-left: 0;
+  }
+
+  .dropdown-menu {
+    position: static;
+    float: none;
+  }
+}
+
+
+// Navbar text
+//
+//
+
+.navbar-text {
+  display: inline-block;
+  padding-top: $nav-link-padding-y;
+  padding-bottom: $nav-link-padding-y;
+}
+
+
+// Responsive navbar
+//
+// Custom styles for responsive collapsing and toggling of navbar contents.
+// Powered by the collapse Bootstrap JavaScript plugin.
+
+// When collapsed, prevent the toggleable navbar contents from appearing in
+// the default flexbox row orienation. Requires the use of `flex-wrap: wrap`
+// on the `.navbar` parent.
+.navbar-collapse {
+  flex-basis: 100%;
+  flex-grow: 1;
+  // For always expanded or extra full navbars, ensure content aligns itself
+  // properly vertically. Can be easily overridden with flex utilities.
+  align-items: center;
+}
+
+// Button for toggling the navbar when in its collapsed state
+.navbar-toggler {
+  padding: $navbar-toggler-padding-y $navbar-toggler-padding-x;
+  font-size: $navbar-toggler-font-size;
+  line-height: 1;
+  background: transparent; // remove default button style
+  border: $border-width solid transparent; // remove default button style
+  @include border-radius($navbar-toggler-border-radius);
+
+  @include hover-focus {
+    text-decoration: none;
+  }
+}
+
+// Keep as a separate element so folks can easily override it with another icon
+// or image file as needed.
+.navbar-toggler-icon {
+  display: inline-block;
+  width: 1.5em;
+  height: 1.5em;
+  vertical-align: middle;
+  content: "";
+  background: no-repeat center center;
+  background-size: 100% 100%;
+}
+
+// Generate series of `.navbar-expand-*` responsive classes for configuring
+// where your navbar collapses.
+.navbar-expand {
+  @each $breakpoint in map-keys($grid-breakpoints) {
+    $next: breakpoint-next($breakpoint, $grid-breakpoints);
+    $infix: breakpoint-infix($next, $grid-breakpoints);
+
+    &#{$infix} {
+      @include media-breakpoint-down($breakpoint) {
+        > .container,
+        > .container-fluid {
+          padding-right: 0;
+          padding-left: 0;
+        }
+      }
+
+      @include media-breakpoint-up($next) {
+        flex-flow: row nowrap;
+        justify-content: flex-start;
+
+        .navbar-nav {
+          flex-direction: row;
+
+          .dropdown-menu {
+            position: absolute;
+          }
+
+          .dropdown-menu-right {
+            right: 0;
+            left: auto; // Reset the default from `.dropdown-menu`
+          }
+
+          .nav-link {
+            padding-right: .5rem;
+            padding-left: .5rem;
+          }
+        }
+
+        // For nesting containers, have to redeclare for alignment purposes
+        > .container,
+        > .container-fluid {
+          flex-wrap: nowrap;
+        }
+
+        .navbar-collapse {
+          display: flex !important;  // stylelint-disable-line declaration-no-important
+
+          // Changes flex-bases to auto because of an IE10 bug
+          flex-basis: auto;
+        }
+
+        .navbar-toggler {
+          display: none;
+        }
+
+        .dropup {
+          .dropdown-menu {
+            top: auto;
+            bottom: 100%;
+          }
+        }
+      }
+    }
+  }
+}
+
+
+// Navbar themes
+//
+// Styles for switching between navbars with light or dark background.
+
+// Dark links against a light background
+.navbar-light {
+  .navbar-brand {
+    color: $navbar-light-active-color;
+
+    @include hover-focus {
+      color: $navbar-light-active-color;
+    }
+  }
+
+  .navbar-nav {
+    .nav-link {
+      color: $navbar-light-color;
+
+      @include hover-focus {
+        color: $navbar-light-hover-color;
+      }
+
+      &.disabled {
+        color: $navbar-light-disabled-color;
+      }
+    }
+
+    .show > .nav-link,
+    .active > .nav-link,
+    .nav-link.show,
+    .nav-link.active {
+      color: $navbar-light-active-color;
+    }
+  }
+
+  .navbar-toggler {
+    color: $navbar-light-color;
+    border-color: $navbar-light-toggler-border-color;
+  }
+
+  .navbar-toggler-icon {
+    background-image: $navbar-light-toggler-icon-bg;
+  }
+
+  .navbar-text {
+    color: $navbar-light-color;
+    a {
+      color: $navbar-light-active-color;
+
+      @include hover-focus {
+        color: $navbar-light-active-color;
+      }
+    }
+  }
+}
+
+// White links against a dark background
+.navbar-dark {
+  .navbar-brand {
+    color: $navbar-dark-active-color;
+
+    @include hover-focus {
+      color: $navbar-dark-active-color;
+    }
+  }
+
+  .navbar-nav {
+    .nav-link {
+      color: $navbar-dark-color;
+
+      @include hover-focus {
+        color: $navbar-dark-hover-color;
+      }
+
+      &.disabled {
+        color: $navbar-dark-disabled-color;
+      }
+    }
+
+    .show > .nav-link,
+    .active > .nav-link,
+    .nav-link.show,
+    .nav-link.active {
+      color: $navbar-dark-active-color;
+    }
+  }
+
+  .navbar-toggler {
+    color: $navbar-dark-color;
+    border-color: $navbar-dark-toggler-border-color;
+  }
+
+  .navbar-toggler-icon {
+    background-image: $navbar-dark-toggler-icon-bg;
+  }
+
+  .navbar-text {
+    color: $navbar-dark-color;
+    a {
+      color: $navbar-dark-active-color;
+
+      @include hover-focus {
+        color: $navbar-dark-active-color;
+      }
+    }
+  }
+}
diff --git a/scss/placeholders/_pagination.scss b/scss/placeholders/_pagination.scss
new file mode 100644
index 0000000000000000000000000000000000000000..69a36ffe53b820648d96c339ef5682d7e7501f01
--- /dev/null
+++ b/scss/placeholders/_pagination.scss
@@ -0,0 +1,64 @@
+.pagination {
+  display: flex;
+  @include list-unstyled();
+  @include border-radius();
+}
+
+.page-item {
+  &:first-child {
+    .page-link {
+      margin-left: 0;
+      @include border-left-radius($border-radius);
+    }
+  }
+  &:last-child {
+    .page-link {
+      @include border-right-radius($border-radius);
+    }
+  }
+
+  &.active .page-link {
+    z-index: 2;
+    color: $pagination-active-color;
+    background-color: $pagination-active-bg;
+    border-color: $pagination-active-border-color;
+  }
+
+  &.disabled .page-link {
+    color: $pagination-disabled-color;
+    pointer-events: none;
+    background-color: $pagination-disabled-bg;
+    border-color: $pagination-disabled-border-color;
+  }
+}
+
+.page-link {
+  position: relative;
+  display: block;
+  padding: $pagination-padding-y $pagination-padding-x;
+  margin-left: -$pagination-border-width;
+  line-height: $pagination-line-height;
+  color: $pagination-color;
+  background-color: $pagination-bg;
+  border: $pagination-border-width solid $pagination-border-color;
+
+  @include hover-focus {
+    color: $pagination-hover-color;
+    text-decoration: none;
+    background-color: $pagination-hover-bg;
+    border-color: $pagination-hover-border-color;
+  }
+}
+
+
+//
+// Sizing
+//
+
+.pagination-lg {
+  @include pagination-size($pagination-padding-y-lg, $pagination-padding-x-lg, $font-size-lg, $line-height-lg, $border-radius-lg);
+}
+
+.pagination-sm {
+  @include pagination-size($pagination-padding-y-sm, $pagination-padding-x-sm, $font-size-sm, $line-height-sm, $border-radius-sm);
+}
diff --git a/scss/placeholders/_popover.scss b/scss/placeholders/_popover.scss
new file mode 100644
index 0000000000000000000000000000000000000000..450376752b495fade40c378a75c038fa306abee3
--- /dev/null
+++ b/scss/placeholders/_popover.scss
@@ -0,0 +1,194 @@
+.popover {
+  position: absolute;
+  top: 0;
+  left: 0;
+  z-index: $zindex-popover;
+  display: block;
+  max-width: $popover-max-width;
+  // Our parent element can be arbitrary since tooltips are by default inserted as a sibling of their target element.
+  // So reset our font and text properties to avoid inheriting weird values.
+  @include reset-text();
+  font-size: $font-size-sm;
+  // Allow breaking very long words so they don't overflow the popover's bounds
+  word-wrap: break-word;
+  background-color: $popover-bg;
+  background-clip: padding-box;
+  border: $popover-border-width solid $popover-border-color;
+  @include border-radius($border-radius-lg);
+  @include box-shadow($popover-box-shadow);
+
+  // Arrows
+  //
+  // .arrow is outer, .arrow::after is inner
+
+  .arrow {
+    position: absolute;
+    display: block;
+    width: $popover-arrow-width;
+    height: $popover-arrow-height;
+  }
+
+  .arrow::before,
+  .arrow::after {
+    position: absolute;
+    display: block;
+    border-color: transparent;
+    border-style: solid;
+  }
+
+  .arrow::before {
+    content: "";
+    border-width: $popover-arrow-width;
+  }
+  .arrow::after {
+    content: "";
+    border-width: $popover-arrow-width;
+  }
+
+  // Popover directions
+
+  &.bs-popover-top {
+    margin-bottom: $popover-arrow-width;
+
+    .arrow {
+      bottom: 0;
+    }
+
+    .arrow::before,
+    .arrow::after {
+      border-bottom-width: 0;
+    }
+
+    .arrow::before {
+      bottom: -$popover-arrow-width;
+      margin-left: -$popover-arrow-width;
+      border-top-color: $popover-arrow-outer-color;
+    }
+
+    .arrow::after {
+      bottom: calc((#{$popover-arrow-width} - #{$popover-border-width}) * -1);
+      margin-left: -$popover-arrow-width;
+      border-top-color: $popover-arrow-color;
+    }
+  }
+
+  &.bs-popover-right {
+    margin-left: $popover-arrow-width;
+
+    .arrow {
+      left: 0;
+    }
+
+    .arrow::before,
+    .arrow::after {
+      margin-top: -$popover-arrow-width;
+      border-left-width: 0;
+    }
+
+    .arrow::before {
+      left: -$popover-arrow-width;
+      border-right-color: $popover-arrow-outer-color;
+    }
+
+    .arrow::after {
+      left: calc((#{$popover-arrow-width} - #{$popover-border-width}) * -1);
+      border-right-color: $popover-arrow-color;
+    }
+  }
+
+  &.bs-popover-bottom {
+    margin-top: $popover-arrow-width;
+
+    .arrow {
+      top: 0;
+    }
+
+    .arrow::before,
+    .arrow::after {
+      margin-left: -$popover-arrow-width;
+      border-top-width: 0;
+    }
+
+    .arrow::before {
+      top: -$popover-arrow-width;
+      border-bottom-color: $popover-arrow-outer-color;
+    }
+
+    .arrow::after {
+      top: calc((#{$popover-arrow-width} - #{$popover-border-width}) * -1);
+      border-bottom-color: $popover-arrow-color;
+    }
+
+    // This will remove the popover-header's border just below the arrow
+    .popover-header::before {
+      position: absolute;
+      top: 0;
+      left: 50%;
+      display: block;
+      width: 20px;
+      margin-left: -10px;
+      content: "";
+      border-bottom: $popover-border-width solid $popover-header-bg;
+    }
+  }
+
+  &.bs-popover-left {
+    margin-right: $popover-arrow-width;
+
+    .arrow {
+      right: 0;
+    }
+
+    .arrow::before,
+    .arrow::after {
+      margin-top: -$popover-arrow-width;
+      border-right-width: 0;
+    }
+
+    .arrow::before {
+      right: -$popover-arrow-width;
+      border-left-color: $popover-arrow-outer-color;
+    }
+
+    .arrow::after {
+      right: calc((#{$popover-arrow-width} - #{$popover-border-width}) * -1);
+      border-left-color: $popover-arrow-color;
+    }
+  }
+  &.bs-popover-auto {
+    &[x-placement^="top"] {
+      @extend .bs-popover-top;
+    }
+    &[x-placement^="right"] {
+      @extend .bs-popover-right;
+    }
+    &[x-placement^="bottom"] {
+      @extend .bs-popover-bottom;
+    }
+    &[x-placement^="left"] {
+      @extend .bs-popover-left;
+    }
+  }
+}
+
+
+// Offset the popover to account for the popover arrow
+.popover-header {
+  padding: $popover-header-padding-y $popover-header-padding-x;
+  margin-bottom: 0; // Reset the default from Reboot
+  font-size: $font-size-base;
+  color: $popover-header-color;
+  background-color: $popover-header-bg;
+  border-bottom: $popover-border-width solid darken($popover-header-bg, 5%);
+  $offset-border-width: calc(#{$border-radius-lg} - #{$popover-border-width});
+  @include border-top-radius($offset-border-width);
+
+  &:empty {
+    display: none;
+  }
+}
+
+.popover-body {
+  padding: $popover-body-padding-y $popover-body-padding-x;
+  color: $popover-body-color;
+}
diff --git a/scss/placeholders/_progress.scss b/scss/placeholders/_progress.scss
new file mode 100644
index 0000000000000000000000000000000000000000..efbb4403407d239763fa5013fa257eecc63d30c2
--- /dev/null
+++ b/scss/placeholders/_progress.scss
@@ -0,0 +1,30 @@
+@keyframes progress-bar-stripes {
+  from { background-position: $progress-height 0; }
+  to { background-position: 0 0; }
+}
+
+.progress {
+  display: flex;
+  height: $progress-height;
+  overflow: hidden; // force rounded corners by cropping it
+  font-size: $progress-font-size;
+  background-color: $progress-bg;
+  @include border-radius($progress-border-radius);
+}
+
+.progress-bar {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  color: $progress-bar-color;
+  background-color: $progress-bar-bg;
+}
+
+.progress-bar-striped {
+  @include gradient-striped();
+  background-size: $progress-height $progress-height;
+}
+
+.progress-bar-animated {
+  animation: progress-bar-stripes $progress-bar-animation-timing;
+}
diff --git a/scss/placeholders/_tables.scss b/scss/placeholders/_tables.scss
new file mode 100644
index 0000000000000000000000000000000000000000..6bd0b91a43cdc2d345b7859d1e5c73bb7ca05681
--- /dev/null
+++ b/scss/placeholders/_tables.scss
@@ -0,0 +1,180 @@
+//
+// Basic Bootstrap table
+//
+
+.table {
+  width: 100%;
+  max-width: 100%;
+  margin-bottom: $spacer;
+  background-color: $table-bg; // Reset for nesting within parents with `background-color`.
+
+  th,
+  td {
+    padding: $table-cell-padding;
+    vertical-align: top;
+    border-top: $table-border-width solid $table-border-color;
+  }
+
+  thead th {
+    vertical-align: bottom;
+    border-bottom: (2 * $table-border-width) solid $table-border-color;
+  }
+
+  tbody + tbody {
+    border-top: (2 * $table-border-width) solid $table-border-color;
+  }
+
+  .table {
+    background-color: $body-bg;
+  }
+}
+
+
+//
+// Condensed table w/ half padding
+//
+
+.table-sm {
+  th,
+  td {
+    padding: $table-cell-padding-sm;
+  }
+}
+
+
+// Bordered version
+//
+// Add borders all around the table and between all the columns.
+
+.table-bordered {
+  border: $table-border-width solid $table-border-color;
+
+  th,
+  td {
+    border: $table-border-width solid $table-border-color;
+  }
+
+  thead {
+    th,
+    td {
+      border-bottom-width: (2 * $table-border-width);
+    }
+  }
+}
+
+
+// Zebra-striping
+//
+// Default zebra-stripe styles (alternating gray and transparent backgrounds)
+
+.table-striped {
+  tbody tr:nth-of-type(odd) {
+    background-color: $table-accent-bg;
+  }
+}
+
+
+// Hover effect
+//
+// Placed here since it has to come after the potential zebra striping
+
+.table-hover {
+  tbody tr {
+    @include hover {
+      background-color: $table-hover-bg;
+    }
+  }
+}
+
+
+// Table backgrounds
+//
+// Exact selectors below required to override `.table-striped` and prevent
+// inheritance to nested tables.
+
+@each $color, $value in $theme-colors {
+  @include table-row-variant($color, theme-color-level($color, -9));
+}
+
+@include table-row-variant(active, $table-active-bg);
+
+
+// Dark styles
+//
+// Same table markup, but inverted color scheme: dark background and light text.
+
+// stylelint-disable-next-line no-duplicate-selectors
+.table {
+  .thead-dark {
+    th {
+      color: $table-dark-color;
+      background-color: $table-dark-bg;
+      border-color: $table-dark-border-color;
+    }
+  }
+
+  .thead-light {
+    th {
+      color: $table-head-color;
+      background-color: $table-head-bg;
+      border-color: $table-border-color;
+    }
+  }
+}
+
+.table-dark {
+  color: $table-dark-color;
+  background-color: $table-dark-bg;
+
+  th,
+  td,
+  thead th {
+    border-color: $table-dark-border-color;
+  }
+
+  &.table-bordered {
+    border: 0;
+  }
+
+  &.table-striped {
+    tbody tr:nth-of-type(odd) {
+      background-color: $table-dark-accent-bg;
+    }
+  }
+
+  &.table-hover {
+    tbody tr {
+      @include hover {
+        background-color: $table-dark-hover-bg;
+      }
+    }
+  }
+}
+
+
+// Responsive tables
+//
+// Generate series of `.table-responsive-*` classes for configuring the screen
+// size of where your table will overflow.
+
+.table-responsive {
+  @each $breakpoint in map-keys($grid-breakpoints) {
+    $next: breakpoint-next($breakpoint, $grid-breakpoints);
+    $infix: breakpoint-infix($next, $grid-breakpoints);
+
+    &#{$infix} {
+      @include media-breakpoint-down($breakpoint) {
+        display: block;
+        width: 100%;
+        overflow-x: auto;
+        -webkit-overflow-scrolling: touch;
+        -ms-overflow-style: -ms-autohiding-scrollbar; // See https://github.com/twbs/bootstrap/pull/10057
+
+        // Prevent double border on horizontal scroll due to use of `display: block;`
+        &.table-bordered {
+          border: 0;
+        }
+      }
+    }
+  }
+}
diff --git a/scss/placeholders/_tooltip.scss b/scss/placeholders/_tooltip.scss
new file mode 100644
index 0000000000000000000000000000000000000000..7b5db1cf2a5f2e97f5f1ca78bd593e028ab84ade
--- /dev/null
+++ b/scss/placeholders/_tooltip.scss
@@ -0,0 +1,107 @@
+// Base class
+.tooltip {
+  position: absolute;
+  z-index: $zindex-tooltip;
+  display: block;
+  margin: $tooltip-margin;
+  // Our parent element can be arbitrary since tooltips are by default inserted as a sibling of their target element.
+  // So reset our font and text properties to avoid inheriting weird values.
+  @include reset-text();
+  font-size: $font-size-sm;
+  // Allow breaking very long words so they don't overflow the tooltip's bounds
+  word-wrap: break-word;
+  opacity: 0;
+
+  &.show { opacity: $tooltip-opacity; }
+
+  .arrow {
+    position: absolute;
+    display: block;
+    width: $tooltip-arrow-width;
+    height: $tooltip-arrow-height;
+  }
+
+  .arrow::before {
+    position: absolute;
+    border-color: transparent;
+    border-style: solid;
+  }
+
+  &.bs-tooltip-top {
+    padding: $tooltip-arrow-width 0;
+    .arrow {
+      bottom: 0;
+    }
+
+    .arrow::before {
+      margin-left: -($tooltip-arrow-width - 2);
+      content: "";
+      border-width: $tooltip-arrow-width $tooltip-arrow-width 0;
+      border-top-color: $tooltip-arrow-color;
+    }
+  }
+  &.bs-tooltip-right {
+    padding: 0 $tooltip-arrow-width;
+    .arrow {
+      left: 0;
+    }
+
+    .arrow::before {
+      margin-top: -($tooltip-arrow-width - 2);
+      content: "";
+      border-width: $tooltip-arrow-width $tooltip-arrow-width $tooltip-arrow-width 0;
+      border-right-color: $tooltip-arrow-color;
+    }
+  }
+  &.bs-tooltip-bottom {
+    padding: $tooltip-arrow-width 0;
+    .arrow {
+      top: 0;
+    }
+
+    .arrow::before {
+      margin-left: -($tooltip-arrow-width - 2);
+      content: "";
+      border-width: 0 $tooltip-arrow-width $tooltip-arrow-width;
+      border-bottom-color: $tooltip-arrow-color;
+    }
+  }
+  &.bs-tooltip-left {
+    padding: 0 $tooltip-arrow-width;
+    .arrow {
+      right: 0;
+    }
+
+    .arrow::before {
+      right: 0;
+      margin-top: -($tooltip-arrow-width - 2);
+      content: "";
+      border-width: $tooltip-arrow-width 0 $tooltip-arrow-width $tooltip-arrow-width;
+      border-left-color: $tooltip-arrow-color;
+    }
+  }
+  &.bs-tooltip-auto {
+    &[x-placement^="top"] {
+      @extend .bs-tooltip-top;
+    }
+    &[x-placement^="right"] {
+      @extend .bs-tooltip-right;
+    }
+    &[x-placement^="bottom"] {
+      @extend .bs-tooltip-bottom;
+    }
+    &[x-placement^="left"] {
+      @extend .bs-tooltip-left;
+    }
+  }
+}
+
+// Wrapper for the tooltip content
+.tooltip-inner {
+  max-width: $tooltip-max-width;
+  padding: $tooltip-padding-y $tooltip-padding-x;
+  color: $tooltip-color;
+  text-align: center;
+  background-color: $tooltip-bg;
+  @include border-radius($border-radius);
+}
diff --git a/scss/placeholders/_transitions.scss b/scss/placeholders/_transitions.scss
new file mode 100644
index 0000000000000000000000000000000000000000..df5744b25f5a297a93e2e25e1cd1efdcb620a7a1
--- /dev/null
+++ b/scss/placeholders/_transitions.scss
@@ -0,0 +1,36 @@
+// stylelint-disable selector-no-qualifying-type
+
+.fade {
+  opacity: 0;
+  @include transition($transition-fade);
+
+  &.show {
+    opacity: 1;
+  }
+}
+
+.collapse {
+  display: none;
+  &.show {
+    display: block;
+  }
+}
+
+tr {
+  &.collapse.show {
+    display: table-row;
+  }
+}
+
+tbody {
+  &.collapse.show {
+    display: table-row-group;
+  }
+}
+
+.collapsing {
+  position: relative;
+  height: 0;
+  overflow: hidden;
+  @include transition($transition-collapse);
+}
diff --git a/scss/_type.scss b/scss/placeholders/_type.scss
similarity index 77%
rename from scss/_type.scss
rename to scss/placeholders/_type.scss
index b1b8f61cf5fcf0fa14ed049f573751ac527f96b8..14812045291cfad0890850236478bb8611dbd721 100644
--- a/scss/_type.scss
+++ b/scss/placeholders/_type.scss
@@ -4,8 +4,7 @@
 // Headings
 //
 
-h1, h2, h3, h4, h5, h6,
-.h1, .h2, .h3, .h4, .h5, .h6 {
+%h1, %h2, %h3, %h4, %h5, %h6 {
   margin-bottom: $headings-margin-bottom;
   font-family: $headings-font-family;
   font-weight: $headings-font-weight;
@@ -13,35 +12,35 @@ h1, h2, h3, h4, h5, h6,
   color: $headings-color;
 }
 
-h1, .h1 { font-size: $h1-font-size; }
-h2, .h2 { font-size: $h2-font-size; }
-h3, .h3 { font-size: $h3-font-size; }
-h4, .h4 { font-size: $h4-font-size; }
-h5, .h5 { font-size: $h5-font-size; }
-h6, .h6 { font-size: $h6-font-size; }
+%h1 { font-size: $h1-font-size; }
+%h2 { font-size: $h2-font-size; }
+%h3 { font-size: $h3-font-size; }
+%h4 { font-size: $h4-font-size; }
+%h5 { font-size: $h5-font-size; }
+%h6 { font-size: $h6-font-size; }
 
-.lead {
+%lead {
   font-size: $lead-font-size;
   font-weight: $lead-font-weight;
 }
 
 // Type display classes
-.display-1 {
+%display-1 {
   font-size: $display1-size;
   font-weight: $display1-weight;
   line-height: $display-line-height;
 }
-.display-2 {
+%display-2 {
   font-size: $display2-size;
   font-weight: $display2-weight;
   line-height: $display-line-height;
 }
-.display-3 {
+%display-3 {
   font-size: $display3-size;
   font-weight: $display3-weight;
   line-height: $display-line-height;
 }
-.display-4 {
+%display-4 {
   font-size: $display4-size;
   font-weight: $display4-weight;
   line-height: $display-line-height;
@@ -52,7 +51,7 @@ h6, .h6 { font-size: $h6-font-size; }
 // Horizontal rules
 //
 
-hr {
+%hr {
   margin-top: 1rem;
   margin-bottom: 1rem;
   border: 0;
@@ -64,14 +63,12 @@ hr {
 // Emphasis
 //
 
-small,
-.small {
+%small {
   font-size: $small-font-size;
   font-weight: $font-weight-normal;
 }
 
-mark,
-.mark {
+%mark {
   padding: $mark-padding;
   background-color: $mark-bg;
 }
@@ -81,15 +78,15 @@ mark,
 // Lists
 //
 
-.list-unstyled {
+%list-unstyled {
   @include list-unstyled;
 }
 
 // Inline turns list items into inline-block
-.list-inline {
+%list-inline {
   @include list-unstyled;
 }
-.list-inline-item {
+%list-inline-item {
   display: inline-block;
 
   &:not(:last-child) {
@@ -103,18 +100,18 @@ mark,
 //
 
 // Builds on `abbr`
-.initialism {
+%initialism {
   font-size: 90%;
   text-transform: uppercase;
 }
 
 // Blockquotes
-.blockquote {
+%blockquote {
   margin-bottom: $spacer;
   font-size: $blockquote-font-size;
 }
 
-.blockquote-footer {
+%blockquote-footer {
   display: block;
   font-size: 80%; // back to default font-size
   color: $blockquote-small-color;