diff --git a/docs/framework/theme.md b/docs/framework/theme.md
new file mode 100644
index 0000000000000000000000000000000000000000..26f87297f5c9c89be2cc9daf4e80bebb71ecee15
--- /dev/null
+++ b/docs/framework/theme.md
@@ -0,0 +1,464 @@
+# Theme Reference
+
+## Introduction
+
+CiviCRM supports CSS-based theming. You may define a theme which overrides
+or supplements a CSS file such as `civicrm.css` and `bootstrap.css`.
+
+Most installations of CiviCRM are embedded within a CMS (such as Drupal,
+Joomla, or WordPress).  Customizing the look-and-feel therefore includes two
+general areas of work:
+
+ * __CMS Theming__: Use the features and conventions of the CMS to
+    manage the general site-wide appearance.
+ * __Civi Theming__: Use the features and conventions of Civi to tune
+    the appearance of Civi's screens.
+
+As the CiviCRM application continues to evolve, the intention is to align
+these two areas by adopting [Bootstrap CSS](http://getbootstrap.com/)
+throughout CiviCRM.  A site-builder (or theme-developer) will select (or
+write) a Bootstrap-based theme for their CMS -- and this will define the
+look-and-feel within Civi's screens.
+
+However, we cannot achieve that vision in one dramatic leap.  Rather, theming
+in Civi will be in transition for the foreseeable future, so we must discuss
+some more nuanced concepts.  The key concepts in Civi theming are:
+
+* __Look-and-Feel (*Theme*)__: The visual appearance that an end-user will recognize. (*Ex: a flat, high-contrast appearance built around blue and white*)
+* __Package__: The deliverable that an administrator installs/activates. (*Ex: a CiviCRM extension*)
+* __Vocabulary__: The set of HTML/CSS class-names which form a contract between HTML and CSS providers. (*Ex: BootstrapCSS*)
+
+Generally speaking, these are relevant to people acting in different roles:
+
+* A __theme developer__ who wishes to define a new __look-and-feel__ (_theme_) should learn about the __vocabulary__
+  by examining its __style guide__; then, he or she can create a __package__ (e.g. CiviCRM extension) which
+  includes a __CSS file__ for the __vocabulary__.
+* A __site administrator__ who wishes to change the __look-and-feel__ of the site should install the __package__
+  provided by the __theme developer__.
+* An __application developer__ who wishes to provide a pleasant experience should learn about the __vocabulary__
+  by examining its __style guide__. He or she can create pages which load the __CSS file__ and use this __vocabulary__.
+
+We can explore each of these concepts in greater detail.
+
+## Quick Start
+
+To generate an extension with a new, skeletal theme named `newyork`, use [civix](/extensions/civix.md):
+
+```bash
+$ civix generate:module org.civicrm.newyork
+$ cd org.civicrm.newyork
+$ civix generate:theme
+Initialize theme "newyork"
+Write newyork.theme.php
+Write css/civicrm.css
+Write css/bootstrap.css
+```
+
+Note how this provides theme metadata (`newyork.theme.php`) and two empty CSS files (`css/civicrm.css` and
+`css/bootstrap.css`).
+
+## Themes
+
+A *theme* determines the visual appearance that an end-user will recognize.  At time of writing, there are two
+important themes in CiviCRM:
+
+* __Greenwich (Village)__: This has been the standard appearance since roughly CiviCRM 3.x. Visually, you can
+  recognize Greenwich by the use of grey beveled buttons. Technically, it has been developed in vanilla CSS.
+* __Shoreditch__: This is a newer theme developed as an extension during 4.7/5.x. Visually, you can recognize
+  Shoreditch by its flat design. Technically, it has been developed in the Bootstrap(S)CSS framework.
+
+!!! note "What's in a name?"
+
+    During a planning session for Shoreditch in Fort Collins, CO, we got repeatedly confused by the lack of a distinct
+    name for the current and proposed themes.  We started to use names that paid hommage to the original development
+    teams -- naming each after a neighborhood that was close to the original teams' bases of operations.
+
+## Vocabularies {:#vocab}
+
+A __vocabulary__ provides a list of CSS class-names.  It defines a contract between an application-developer (who
+generates HTML data) and a theme-developer (who generates CSS data). The best way to learn about common
+vocabularies is to install the [org.civicrm.styleguide](https://github.com/civicrm/org.civicrm.styleguide/) extension.
+
+There are two important vocabularies which correlate to two important files:
+
+* `crm-*` (aka `civicrm.css`) defines the look-and-feel for any screens based on the __crm-*__ coding convention.
+     * __Strength__: This is the traditional vocabulary used on the most screens. It has some smart conventions for
+       identifying/selecting fields.
+     * __Weakness__: Developed organically. It has gone through some iterations of cleanup/improvement, but its definition
+       and terms are not strongly documented.
+ * BootstrapCSS (aka `bootstrap.css`) defines the look-and-feel for any screens based on the __Bootstrap__ coding convention.
+     * __Strength__: Widely used vocabulary with a larger ecosystem and support tools (e.g. BootstrapSCSS).
+     * __Weakness__: This is newer in the CiviCRM ecosystem. Not included with `civicrm-core` -- and there's no
+       Greenwich for BootstrapCSS.
+
+The basic purpose of a theme is to provide a copy of each CSS file.
+
+!!! note "Shoreditch as bridge"
+
+    At time of writing, [Shoreditch](https://github.com/civicrm/org.civicrm.shoreditch) is the only theme which implements
+    a consistent look-and-feel in both vocabularies. It is intended to be a bridge that provides a consistent
+    look-and-feel while other parts of the application transition from `crm-*` to BootstrapCSS.
+
+!!! note "Additional vocabularies"
+
+    If you need to define a new vocabulary for widgets and concepts that don't exist in `crm-*` (`civicrm.css`) or
+    BootstrapCSS (`bootstrap.css`), then you can simply choose another filename (`superwidgets.css`) and implement a
+    style-guide.  The theme system will allow themes to override any CSS file.
+
+    However, this doesn't mean that *every* CSS file should be overriden.  From the perspective of an application developer,
+    adhoc CSS often isn't intended for consumption/override by others.  From the perspective of a theme developer, it
+    would be overwhelming to override every CSS file from every extension.
+
+    Instead, approach new vocabularies conscientiously -- a new vocabulary should represent a contract in which both
+    application developers and theme developers benefit from a clearer specification.  Use a style-guide to document
+    the contract.
+
+## Mechanics
+
+Suppose we have a theme -- such as Greenwich or Shoreditch -- which defines a file -- such as `civicrm.css`. How
+does this file get loaded on to the screen?
+
+Somewhere within the application, there is a call to [Resources::addStyleFile()](resources.md), as in:
+
+```php
+Civi::resources()->addStyleFile('civicrm', 'css/civicrm.css');
+```
+
+The active theme gets first-priority at picking the actual content of `css/civicrm.css`. If it
+doesn't provide one, then it falls back to whatever default would normally be loaded.
+
+Internally, `addStyleFile()` accesses the theming service (`Civi::service('themes')`). The
+theme service identifies the active-theme and then asks for the concrete URL for the CSS file.
+
+You can simulate this through the command line with [`cv`](https://github.com/civicrm/cv).
+
+```
+$ cv ev 'return Civi::service("themes")->getActiveThemeKey();'
+"greenwich"
+$ cv ev 'return Civi::service("themes")->resolveUrls("greenwich", "civicrm", "css/civicrm.css");'
+[
+    "http://dmaster.l/sites/all/modules/civicrm/css/civicrm.css?r=gWD8J"
+]
+```
+
+Each theme has some configuration and metadata.  You can inspect the metadata using `getAll()`.
+
+```
+$ cv ev 'return Civi::service("themes")->getAll();'
+{
+    ...
+    "greenwich": {
+        "name": "greenwich",
+        "url_callback": "\\Civi\\Core\\Themes\\Resolvers::simple",
+        "search_order": [
+            "greenwich",
+            "_fallback_"
+        ],
+        "ext": "civicrm",
+        "title": "Greenwich",
+        "help": "CiviCRM 4.x look-and-feel"
+    }
+    ...
+}
+```
+
+Internally, `getAll()` emits `hook_civicrm_themes`.  This allows third-party packages to register themes.  The metadata
+is cached, but you can clear that cache with a general system flush (`cv flush`).
+
+## Packaging {:#pkg}
+
+*Packaging* is the process of putting the CSS file(s) into a deliverable format that can be installed/activated by an
+administator.  CiviCRM supports many package types, such as "CiviCRM extensions", "Drupal modules", and "WordPress
+plugins".
+
+### CiviCRM Extension {:#pkg-ext}
+
+To define a new theme, create an extension, e.g.
+
+```bash
+civix generate:module org.civicrm.newyork
+```
+
+and generate a skeletal theme file:
+
+```bash
+cd org.civicrm.newyork
+civix generate:theme
+```
+
+!!! tip "Multiple subthemes"
+
+    If you prefer to put multiple subthemes in the same extension, then you can pass an extra parameter.
+    For example, this would generate themes named `astoria` and `wallstreet`:
+
+    ```
+    civix generate:theme astoria
+    civix generate:theme wallstreet
+    ```
+
+The `generate:theme` command creates a theme definition (eg `newyork.theme.php`) which will be returned via
+`hook_civicrm_themes`.  You might edit this file to include a nicer `title`.
+
+```php
+// FILE: newyork.theme.php
+array(
+  'name' => 'newyork',
+  'title' => 'New York',
+  ...
+)
+```
+
+Additionally, it creates placeholder copies of `civicrm.css` and `bootstrap.css` (which you can use or edit or replace per taste).
+
+Now activate the theme, e.g.
+
+```bash
+cv en newyork
+cv api setting.create theme_frontend=newyork theme_backend=newyork
+```
+
+Whenever a CiviCRM screen adds a CSS file via `addStyleFile()`, it will
+perform a search for the file -- first, looking in the active theme; then,
+looking for a fallback in `civicrm-core`.  A typical directory tree would
+look like this:
+
+```
+org.civicrm.newyork/info.xml
+org.civicrm.newyork/newyork.php
+org.civicrm.newyork/css/civicrm.css
+org.civicrm.newyork/css/bootstrap.css
+```
+
+### Drupal/Joomla/WordPress {:#pkg-cms}
+
+In principle, you may package a theme using anything that supports [CiviCRM hooks](../hooks/index.md) -- just implement
+`hook_civicrm_themes`.  At time of writing, this technique has not actually been used yet, but a few tips may help:
+
+ * __Define the extension key__:  The previous example defines a
+   fully-qualified exension-key (`ext`) with value
+   `org.civicrm.newyork`.  For other packages, the naming convention
+   is different.  For example, a Drupal module named `foobar` would have the
+   extension-key `drupal.foobar`.  (These prefixes are not frequently used;
+   we may encounter bugs when using different prefixes.  Patchwelcome.)
+ * __Exclude Files__: If the the CMS theme already loads a copy of
+   `bootstrap.css` through the CMS, then it may be redundant to load a copy of `bootstrap.css`
+   through Civi's theming layer. See "[Advanced: excludes](#excludes)".
+ * __Define a callback__:  When loading a CSS file such as `civicrm.css`, the default loader
+   tries to read it from your package. However, if your package has a different file structure
+   (or if there's a bug in locating your package's folder), you should define a custom
+   callback function. See "[Advanced: url_callback](#url_callback)".
+
+### Legacy {:#pkg-legacy}
+
+Prior to CiviCRM v5.8, Civi did not support `hook_civicrm_themes`. Instead, you could
+manually deploy CSS files and then configure some settings:
+
+ * `customCSSURL`: Loads an extra CSS file on every CiviCRM screen.
+ * `disable_core_css`: Disables the standard call to `addStyleFile('civicrm', 'css/civicrm.css')`.
+
+However, these settings have notable limitations which spurred the development of
+`hook_civicrm_themes`:
+
+ * They don't provide a full packaging format. When defining a full, cogent look-and-feel,
+   it's useful to bundle related files (e.g. `civicrm.css`, `bootstrap.css`, images, icons).
+   This makes it easier to share/redistribute/collaborate on the new look-and-feel.
+ * They apply to all CiviCRM screens equally. If you want to provide a different look-and-feel
+   on different screens (e.g. frontend vs backend), there's no way to selectively adjust
+   these options.
+
+For new theming projects, it's better to package the customization using an
+extension (or Drupal module, WordPress plugin, ad nauseum). However, for existing
+projects, the settings will continue to work.
+
+## Advanced
+
+The metadata for the theme allows several more fields. These fields are most useful if
+you intend to bundle multiple subthemes into the same package.
+
+### <code>excludes</code>
+
+CiviCRM theming supports fallbacks: if you don't define `civicrm.css` in
+your theme, then it will fallback to using a version that is bundled in
+`civicrm-core`.  But what if you want to *exclude* the file completely?  For
+example, if you have provided styling rules through a CMS theme, then loading
+`civicrm.css` could be redundant.  Use the `excludes` option to disable a file:
+
+```php
+// FILE: newyork.php
+function newyork_civicrm_themes(&$themes) {
+  $themes['newyork'] = array(
+    'ext' => 'org.civicrm.newyork',
+    'title' => 'New York',
+    'excludes' => array('civicrm:css/bootstrap.css'),
+  );
+}
+```
+
+### <code>prefix</code>
+
+If you have several variations on a theme, you may wish to define all of
+them in one extension.  For example, the `newyork` extension might define
+themes for `astoria` and `wallstreet`.  You can load each variant from a
+subfolder:
+
+```php
+// FILE: newyork.php
+function newyork_civicrm_themes(&$themes) {
+  $themes['astoria'] = array(
+    'ext' => 'org.civicrm.newyork',
+    'title' => 'Astoria',
+    'prefix' => 'astoria/',
+  );
+  $themes['wallstreet'] = array(
+    'ext' => 'org.civicrm.newyork',
+    'title' => 'Wall Street',
+    'prefix' => 'wallstreet/',
+  );
+}
+```
+
+The corresponding file structure would be:
+
+```
+org.civicrm.newyork/info.xml
+org.civicrm.newyork/newyork.php
+org.civicrm.newyork/astoria/css/civicrm.css
+org.civicrm.newyork/astoria/css/bootstrap.css
+org.civicrm.newyork/wallstreet/css/civicrm.css
+org.civicrm.newyork/wallstreet/css/bootstrap.css
+```
+
+### <code>search_order</code>
+
+Sometimes you may want to share files among themes; for example, the
+`astoria` and `wallstreet` themes might use a common version of
+`civicrm.css` (but have their own versions of `bootstrap.css`).  You may
+manipulate the `search_order` to define your own fallback sequence:
+
+```php
+// FILE: newyork.php
+function newyork_civicrm_themes(&$themes) {
+  $themes['astoria'] = array(
+    'ext' => 'org.civicrm.newyork',
+    'title' => 'Astoria',
+    'prefix' => 'astoria/',
+    'search_order' => array('astoria', '_newyork_common_', '_fallback_'),
+  );
+  $themes['wallstreet'] = array(
+    'ext' => 'org.civicrm.newyork',
+    'title' => 'Wall Street',
+    'prefix' => 'wallstreet/',
+    'search_order' => array('wallstreet', '_newyork_common_', '_fallback_'),
+  );
+  $themes['_newyork_common_'] = array(
+    'ext' => 'org.civicrm.newyork',
+    'title' => 'New York (Base Theme)',
+    'prefix' => 'common/',
+  );
+  // Note: "_newyork_common_" begins with "_".  It is a hidden, abstract
+  // theme which cannot be directly activated.
+}
+```
+
+The corresponding file structure would be:
+
+```
+org.civicrm.newyork/info.xml
+org.civicrm.newyork/newyork.php
+org.civicrm.newyork/common/css/civicrm.css
+org.civicrm.newyork/astoria/css/bootstrap.css
+org.civicrm.newyork/wallstreet/css/bootstrap.css
+```
+
+### <code>url_callback</code>
+
+The previous theming examples are based on _file-name conventions_.
+However, file-name conventions are fairly static and may be unsuitable in
+cases like:
+
+ * Dynamically generated themes defined through an admin GUI
+ * Large theme libraries with complex rules for sharing/compiling CSS files
+ * Integration with other theming systems that use different file-names
+
+In all these cases, it may be useful to define a `url_callback` which
+provides more dynamic, fine-grained control over CSS loading.
+
+```php
+// FILE: newyork.php
+function newyork_civicrm_themes(&$themes) {
+  foreach (array('blue', 'white', 'hicontrast') as $colorScheme) {
+    $themes["newyork-{$colorScheme}"] = array(
+      'ext' => "org.civicrm.newyork",
+      'title' => "New York ({$colorScheme})",
+      'url_callback' => "_newyork_css_url",
+    );
+  }
+}
+
+/**
+ * Determine the URL for a CSS resource file.
+ *
+ * @param \Civi\Core\Themes $themes
+ * @param string $themeKey
+ *   Identify the active theme (ex: 'newyork-blue', 'newyork-hicontrast').
+ * @param string $cssExt
+ *   Identify the requested CSS file (ex: 'civicrm', 'org.civicrm.volunteer').
+ * @param string $cssFile
+ *   Identify the requested CSS file (ex: 'css/civicrm.css', 'css/bootstrap.css').
+ * @return array|\Civi\Core\Themes::PASSTHRU
+ *   A list of zero or more CSS URLs.
+ *   To pass responsibility to another URL callback, return
+ *   the constant \Civi\Core\Themes::PASSTHRU.
+ */
+function _newyork_css_url($themes, $themeKey, $cssExt, $cssFile) {
+  return array('http://example.com/css/myfile.css');
+}
+```
+
+The logic in `_newyork_css_url()` is fairly open-ended. A few tricks that may be useful:
+
+ * Wrap other themes using `$themes->resolveUrl(...)`
+ * Wrap other callbacks like `\Civi\Core\Themes\Resolvers::simple(...)` or `\Civi\Core\Themes\Resolvers::fallback(...)`
+ * Locate files in an extension using `Civi::resources()->getPath(...)` or `Civi::resources()->getUrl(...)`
+ * Generate files in a datadir using `Civi::paths()->getPath(...)` or `Civi::paths()->getUrl(...)`
+
+### Non-standard CSS files
+
+Generally, one should only override the `civicrm.css` and `bootstrap.css`
+files.  If some styling issue cannot be addressed well through those files,
+then you should have some discussion about how to improve the coding-conventions
+or the style-guide.
+
+However, there may be edge-cases where you wish to override other CSS files.
+Your file structure should match the original file structure.  If you wish
+to override a CSS file defined by another extension, then include the
+extension as part of the name.
+
+<table>
+  <thead>
+  <tr><td><strong>Original File</strong></td><td><strong>Theme File</strong></td></tr>
+  </thead>
+  <tbody>
+  <tr><td>civicrm-core/<code>css/dashboard.css</code></td><td>org.civicrm.newyork/<code>css/dashboard.css</code></td></tr>
+  <tr><td>civicrm-core/<code>ang/crmMailing.css</code></td><td>org.civicrm.newyork/<code>ang/crmMailing.css</code></td></tr>
+  <tr><td>org.civicrm.volunteer/<code>css/main.css</code></td><td>org.civicrm.newyork/<code>org.civicrm.volunteer-css/dashboard.css</code></td></tr>
+  <tr><td>org.civicrm.rules/<code>style/admin.css</code></td><td>org.civicrm.newyork/<code>org.civicrm.rules-style/admin.css</code></td></tr>
+  </tbody>
+</table>
+
+If you use a multitheme/prefixed configuration, then theme prefixes apply
+accordingly.
+
+<table>
+  <thead>
+  <tr><td><strong>Original File</strong></td><td><strong>Theme File</strong></td></tr>
+  </thead>
+  <tbody>
+  <tr><td>civicrm-core/<code>css/dashboard.css</code></td><td>org.civicrm.newyork/astoria/<code>css/dashboard.css</code></td></tr>
+  <tr><td>civicrm-core/<code>ang/crmMailing.css</code></td><td>org.civicrm.newyork/astoria/<code>ang/crmMailing.css</code></td></tr>
+  <tr><td>org.civicrm.volunteer/<code>css/main.css</code></td><td>org.civicrm.newyork/astoria/<code>org.civicrm.volunteer-css/dashboard.css</code></td></tr>
+  <tr><td>org.civicrm.rules/<code>style/admin.css</code></td><td>org.civicrm.newyork/astoria/<code>org.civicrm.rules-style/admin.css</code></td></tr>
+  </tbody>
+</table>
+
+
diff --git a/mkdocs.yml b/mkdocs.yml
index 85bc2e68822e481ad6b2edab71dfdb35de48cb28..f08994da5563d34e3032c46b6fcb16950a8bed10 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -248,6 +248,7 @@ pages:
     - Templates: framework/templates/index.md
     - Customizing Templates: framework/templates/customizing.md
     - Extending Smarty: framework/templates/extending-smarty.md
+  - Theme Reference: framework/theme.md
   - Token Reference: framework/token.md
   - UI Reference: framework/ui.md
   - Upgrade Reference: framework/upgrade.md