diff --git a/cms/envs/aws.py b/cms/envs/aws.py
index 3d7093431d41ec0ddb65ae34e851dd28a6c579e5..bdb670eb66d552fdeaeba7c9b3528290949e3013 100644
--- a/cms/envs/aws.py
+++ b/cms/envs/aws.py
@@ -177,6 +177,7 @@ ASSET_IGNORE_REGEX = ENV_TOKENS.get('ASSET_IGNORE_REGEX', ASSET_IGNORE_REGEX)
 
 # Theme overrides
 THEME_NAME = ENV_TOKENS.get('THEME_NAME', None)
+COMPREHENSIVE_THEME_DIR = path(ENV_TOKENS.get('COMPREHENSIVE_THEME_DIR', COMPREHENSIVE_THEME_DIR))
 
 #Timezone overrides
 TIME_ZONE = ENV_TOKENS.get('TIME_ZONE', TIME_ZONE)
diff --git a/cms/envs/common.py b/cms/envs/common.py
index 6cfcede38d2f363afdc1df7a2474d0a9a26c666e..71493e06ec427a2e50a907574bba09afadbb42f3 100644
--- a/cms/envs/common.py
+++ b/cms/envs/common.py
@@ -31,7 +31,8 @@ import lms.envs.common
 # Although this module itself may not use these imported variables, other dependent modules may.
 from lms.envs.common import (
     USE_TZ, TECH_SUPPORT_EMAIL, PLATFORM_NAME, BUGS_EMAIL, DOC_STORE_CONFIG, DATA_DIR, ALL_LANGUAGES, WIKI_ENABLED,
-    update_module_store_settings, ASSET_IGNORE_REGEX, COPYRIGHT_YEAR, PARENTAL_CONSENT_AGE_LIMIT, COMP_THEME_DIR,
+    update_module_store_settings, ASSET_IGNORE_REGEX, COPYRIGHT_YEAR,
+    PARENTAL_CONSENT_AGE_LIMIT, COMPREHENSIVE_THEME_DIR,
     # The following PROFILE_IMAGE_* settings are included as they are
     # indirectly accessed through the email opt-in API, which is
     # technically accessible through the CMS via legacy URLs.
@@ -467,12 +468,12 @@ EMBARGO_SITE_REDIRECT_URL = None
 
 PIPELINE_ENABLED = True
 
-# Process static files using RequireJS Optimizer
-STATICFILES_STORAGE = 'openedx.core.lib.django_require.staticstorage.OptimizedCachedRequireJsStorage'
+STATICFILES_STORAGE = 'openedx.core.storage.ProductionStorage'
 
 # List of finder classes that know how to find static files in various locations.
 # Note: the pipeline finder is included to be able to discover optimized files
 STATICFILES_FINDERS = [
+    'openedx.core.djangoapps.theming.finders.ComprehensiveThemeFinder',
     'django.contrib.staticfiles.finders.FileSystemFinder',
     'django.contrib.staticfiles.finders.AppDirectoriesFinder',
     'pipeline.finders.PipelineFinder',
diff --git a/cms/envs/devstack.py b/cms/envs/devstack.py
index 127eb8a3a1f8899a73052c8e8b339c8c0906e016..c19db5e9b015c7b2b015a28c8288ab828c46281b 100644
--- a/cms/envs/devstack.py
+++ b/cms/envs/devstack.py
@@ -37,10 +37,11 @@ FEATURES['PREVIEW_LMS_BASE'] = "preview." + LMS_BASE
 
 # Skip packaging and optimization in development
 PIPELINE_ENABLED = False
-STATICFILES_STORAGE = 'pipeline.storage.NonPackagingPipelineStorage'
+STATICFILES_STORAGE = 'openedx.core.storage.DevelopmentStorage'
 
 # Revert to the default set of finders as we don't want the production pipeline
 STATICFILES_FINDERS = [
+    'openedx.core.djangoapps.theming.finders.ComprehensiveThemeFinder',
     'django.contrib.staticfiles.finders.FileSystemFinder',
     'django.contrib.staticfiles.finders.AppDirectoriesFinder',
 ]
diff --git a/cms/static/images/default-theme/logo.png b/cms/static/images/studio-logo.png
similarity index 100%
rename from cms/static/images/default-theme/logo.png
rename to cms/static/images/studio-logo.png
diff --git a/cms/templates/widgets/header.html b/cms/templates/widgets/header.html
index 4014139a702e8441f7a2a8f41513b4393b0c7443..37270f3af527547bd5a930514d7fcc6712db37bf 100644
--- a/cms/templates/widgets/header.html
+++ b/cms/templates/widgets/header.html
@@ -12,11 +12,7 @@
 
     <div class="wrapper wrapper-l">
       <h1 class="branding"><a href="/">
-        % if settings.FEATURES.get('IS_EDX_DOMAIN', False):
-          <img src="${static.url("images/edx-theme/edx-studio-logo.png")}" alt="${settings.STUDIO_NAME}" />
-        % else:
-          <img src="${static.url("images/default-theme/logo.png")}" alt="${settings.STUDIO_NAME}" />
-        % endif
+        <img src="${static.url("images/studio-logo.png")}" alt="${settings.STUDIO_NAME}" />
       </a></h1>
 
       % if context_course:
diff --git a/common/test/acceptance/pages/lms/learner_profile.py b/common/test/acceptance/pages/lms/learner_profile.py
index f71562de3a7073ef746196b99df9caf017d4b980..dec050f022ae670dab1f03b8e8538819c7d0ab42 100644
--- a/common/test/acceptance/pages/lms/learner_profile.py
+++ b/common/test/acceptance/pages/lms/learner_profile.py
@@ -175,7 +175,7 @@ class LearnerProfilePage(FieldsMixin, PageObject):
         """
         self.wait_for_field('image')
         default_links = self.q(css='.image-frame').attrs('src')
-        return 'default-profile' in default_links[0] if default_links else False
+        return 'profiles/default' in default_links[0] if default_links else False
 
     def mouse_hover(self, element):
         """
diff --git a/common/test/test_microsites/test_microsite/templates/head-extra.html b/common/test/test_microsites/test_microsite/templates/head-extra.html
new file mode 100644
index 0000000000000000000000000000000000000000..82d60e754c44e2338692258e8669265c40670509
--- /dev/null
+++ b/common/test/test_microsites/test_microsite/templates/head-extra.html
@@ -0,0 +1,7 @@
+<%namespace name='static' file='../../static_content.html'/>
+<%! from microsite_configuration import microsite %>
+<% style_overrides_file = microsite.get_value('css_overrides_file') %>
+
+% if style_overrides_file:
+  <link rel="stylesheet" type="text/css" href="${static.url(style_overrides_file)}" />
+% endif
diff --git a/lms/djangoapps/branding/__init__.py b/lms/djangoapps/branding/__init__.py
index 96287a29f94b6ccb6cbcd7b27758d085f48c12a4..a7f8c512c176509c55cb68acd852fd77fb0f5b1c 100644
--- a/lms/djangoapps/branding/__init__.py
+++ b/lms/djangoapps/branding/__init__.py
@@ -81,4 +81,4 @@ def get_logo_url():
     elif university:
         return staticfiles_storage.url('images/{uni}-on-edx-logo.png'.format(uni=university))
     else:
-        return staticfiles_storage.url('images/default-theme/logo.png')
+        return staticfiles_storage.url('images/logo.png')
diff --git a/lms/djangoapps/branding/views.py b/lms/djangoapps/branding/views.py
index e94ffded33d04f351d801e5d9bd68b17d55ec62d..85d7f9a85dd300fbe8bc9fa3f0e7dc8f567dd32c 100644
--- a/lms/djangoapps/branding/views.py
+++ b/lms/djangoapps/branding/views.py
@@ -232,7 +232,7 @@ def footer(request):
                 "title": "Powered by Open edX",
                 "image": "http://example.com/openedx.png"
             },
-            "logo_image": "http://example.com/static/images/default-theme/logo.png",
+            "logo_image": "http://example.com/static/images/logo.png",
             "copyright": "EdX, Open edX, and the edX and Open edX logos are \
                 registered trademarks or trademarks of edX Inc."
         }
diff --git a/lms/djangoapps/courseware/tests/test_comp_theming.py b/lms/djangoapps/courseware/tests/test_comprehensive_theming.py
similarity index 85%
rename from lms/djangoapps/courseware/tests/test_comp_theming.py
rename to lms/djangoapps/courseware/tests/test_comprehensive_theming.py
index 65803687b4118a39a184ffac6a6f7f44d84ef80c..ec734fec1dd168cd1d55db3b0d62ae01320f752f 100644
--- a/lms/djangoapps/courseware/tests/test_comp_theming.py
+++ b/lms/djangoapps/courseware/tests/test_comprehensive_theming.py
@@ -1,13 +1,12 @@
 """Tests of comprehensive theming."""
 
-import unittest
 from django.conf import settings
 from django.test import TestCase
 
 from path import path           # pylint: disable=no-name-in-module
 from django.contrib import staticfiles
 
-from openedx.core.djangoapps.theming.test_util import with_comp_theme
+from openedx.core.djangoapps.theming.test_util import with_comprehensive_theme
 from openedx.core.lib.tempdir import mkdtemp_clean
 
 
@@ -20,8 +19,7 @@ class TestComprehensiveTheming(TestCase):
         # Clear the internal staticfiles caches, to get test isolation.
         staticfiles.finders.get_finder.cache_clear()
 
-    @with_comp_theme(settings.REPO_ROOT / 'themes/red-theme')
-    @unittest.skip("Disabled until we can release theming to production")
+    @with_comprehensive_theme(settings.REPO_ROOT / 'themes/red-theme')
     def test_red_footer(self):
         resp = self.client.get('/')
         self.assertEqual(resp.status_code, 200)
@@ -42,7 +40,7 @@ class TestComprehensiveTheming(TestCase):
         with open(template_dir / "footer.html", "w") as footer:
             footer.write("<footer>TEMPORARY THEME</footer>")
 
-        @with_comp_theme(tmp_theme)
+        @with_comprehensive_theme(tmp_theme)
         def do_the_test(self):
             """A function to do the work so we can use the decorator."""
             resp = self.client.get('/')
@@ -56,7 +54,7 @@ class TestComprehensiveTheming(TestCase):
         before_finders = list(settings.STATICFILES_FINDERS)
         before_dirs = list(settings.STATICFILES_DIRS)
 
-        @with_comp_theme(settings.REPO_ROOT / 'themes/red-theme')
+        @with_comprehensive_theme(settings.REPO_ROOT / 'themes/red-theme')
         def do_the_test(self):
             """A function to do the work so we can use the decorator."""
             self.assertEqual(list(settings.STATICFILES_FINDERS), before_finders)
@@ -65,12 +63,11 @@ class TestComprehensiveTheming(TestCase):
 
         do_the_test(self)
 
-    @unittest.skip("Disabled until we can release theming to production")
     def test_default_logo_image(self):
         result = staticfiles.finders.find('images/logo.png')
         self.assertEqual(result, settings.REPO_ROOT / 'lms/static/images/logo.png')
 
-    @with_comp_theme(settings.REPO_ROOT / 'themes/red-theme')
+    @with_comprehensive_theme(settings.REPO_ROOT / 'themes/red-theme')
     def test_overridden_logo_image(self):
         result = staticfiles.finders.find('images/logo.png')
         self.assertEqual(result, settings.REPO_ROOT / 'themes/red-theme/lms/static/images/logo.png')
diff --git a/lms/envs/aws.py b/lms/envs/aws.py
index 45a614f255fe9bea25defffc02ba79779202604f..5fcaa2f4f1d309ae1ca4588290053b87900dba52 100644
--- a/lms/envs/aws.py
+++ b/lms/envs/aws.py
@@ -237,7 +237,7 @@ BULK_EMAIL_ROUTING_KEY_SMALL_JOBS = LOW_PRIORITY_QUEUE
 
 # Theme overrides
 THEME_NAME = ENV_TOKENS.get('THEME_NAME', None)
-COMP_THEME_DIR = path(ENV_TOKENS.get('COMP_THEME_DIR', COMP_THEME_DIR))
+COMPREHENSIVE_THEME_DIR = path(ENV_TOKENS.get('COMPREHENSIVE_THEME_DIR', COMPREHENSIVE_THEME_DIR))
 
 # Marketing link overrides
 MKTG_URL_LINK_MAP.update(ENV_TOKENS.get('MKTG_URL_LINK_MAP', {}))
@@ -701,10 +701,7 @@ PROFILE_IMAGE_BACKEND = ENV_TOKENS.get('PROFILE_IMAGE_BACKEND', PROFILE_IMAGE_BA
 PROFILE_IMAGE_SECRET_KEY = AUTH_TOKENS.get('PROFILE_IMAGE_SECRET_KEY', PROFILE_IMAGE_SECRET_KEY)
 PROFILE_IMAGE_MAX_BYTES = ENV_TOKENS.get('PROFILE_IMAGE_MAX_BYTES', PROFILE_IMAGE_MAX_BYTES)
 PROFILE_IMAGE_MIN_BYTES = ENV_TOKENS.get('PROFILE_IMAGE_MIN_BYTES', PROFILE_IMAGE_MIN_BYTES)
-if FEATURES['IS_EDX_DOMAIN']:
-    PROFILE_IMAGE_DEFAULT_FILENAME = 'images/edx-theme/default'
-else:
-    PROFILE_IMAGE_DEFAULT_FILENAME = ENV_TOKENS.get('PROFILE_IMAGE_DEFAULT_FILENAME', PROFILE_IMAGE_DEFAULT_FILENAME)
+PROFILE_IMAGE_DEFAULT_FILENAME = 'images/profiles/default'
 
 # EdxNotes config
 
diff --git a/lms/envs/common.py b/lms/envs/common.py
index 176659cf0a4a0f250e33066941b9e9529d054902..e805a586ca4a62770ba009c109cff53386cb46b6 100644
--- a/lms/envs/common.py
+++ b/lms/envs/common.py
@@ -426,7 +426,7 @@ COURSES_ROOT = ENV_ROOT / "data"
 DATA_DIR = COURSES_ROOT
 
 # comprehensive theming system
-COMP_THEME_DIR = ""
+COMPREHENSIVE_THEME_DIR = ""
 
 # TODO: Remove the rest of the sys.path modification here and in cms/envs/common.py
 sys.path.append(REPO_ROOT)
@@ -1087,7 +1087,7 @@ FOOTER_OPENEDX_LOGO_IMAGE = "https://files.edx.org/openedx-logos/edx-openedx-log
 
 # This is just a placeholder image.
 # Site operators can customize this with their organization's image.
-FOOTER_ORGANIZATION_IMAGE = "images/default-theme/logo.png"
+FOOTER_ORGANIZATION_IMAGE = "images/logo.png"
 
 # These are referred to both by the Django asset pipeline
 # AND by the branding footer API, which needs to decide which
@@ -1197,12 +1197,12 @@ X_FRAME_OPTIONS = 'ALLOW'
 
 PIPELINE_ENABLED = True
 
-# Process static files using RequireJS Optimizer
-STATICFILES_STORAGE = 'openedx.core.lib.django_require.staticstorage.OptimizedCachedRequireJsStorage'
+STATICFILES_STORAGE = 'openedx.core.storage.ProductionStorage'
 
 # List of finder classes that know how to find static files in various locations.
 # Note: the pipeline finder is included to be able to discover optimized files
 STATICFILES_FINDERS = [
+    'openedx.core.djangoapps.theming.finders.ComprehensiveThemeFinder',
     'django.contrib.staticfiles.finders.FileSystemFinder',
     'django.contrib.staticfiles.finders.AppDirectoriesFinder',
     'pipeline.finders.PipelineFinder',
@@ -2550,7 +2550,7 @@ PDF_RECEIPT_TAX_ID_LABEL = 'Tax ID'
 PDF_RECEIPT_LOGO_PATH = PROJECT_ROOT + '/static/images/openedx-logo-tag.png'
 # Height of the Logo in mm
 PDF_RECEIPT_LOGO_HEIGHT_MM = 12
-PDF_RECEIPT_COBRAND_LOGO_PATH = PROJECT_ROOT + '/static/images/default-theme/logo.png'
+PDF_RECEIPT_COBRAND_LOGO_PATH = PROJECT_ROOT + '/static/images/logo.png'
 # Height of the Co-brand Logo in mm
 PDF_RECEIPT_COBRAND_LOGO_HEIGHT_MM = 12
 
@@ -2647,7 +2647,7 @@ PROFILE_IMAGE_BACKEND = {
         'base_url': os.path.join(MEDIA_URL, 'profile-images/'),
     },
 }
-PROFILE_IMAGE_DEFAULT_FILENAME = 'images/default-theme/default-profile'
+PROFILE_IMAGE_DEFAULT_FILENAME = 'images/profiles/default'
 PROFILE_IMAGE_DEFAULT_FILE_EXTENSION = 'png'
 # This secret key is used in generating unguessable URLs to users'
 # profile images.  Once it has been set, changing it will make the
diff --git a/lms/envs/devstack.py b/lms/envs/devstack.py
index 897768757b56348a6195eb993ee61d3aafa31ba9..154e000656e92ade269629fc61a36ff55c703a5e 100644
--- a/lms/envs/devstack.py
+++ b/lms/envs/devstack.py
@@ -86,12 +86,12 @@ def should_show_debug_toolbar(_):
 
 ########################### PIPELINE #################################
 
-# Skip packaging and optimization in development
 PIPELINE_ENABLED = False
-STATICFILES_STORAGE = 'pipeline.storage.NonPackagingPipelineStorage'
+STATICFILES_STORAGE = 'openedx.core.storage.DevelopmentStorage'
 
 # Revert to the default set of finders as we don't want the production pipeline
 STATICFILES_FINDERS = [
+    'openedx.core.djangoapps.theming.finders.ComprehensiveThemeFinder',
     'django.contrib.staticfiles.finders.FileSystemFinder',
     'django.contrib.staticfiles.finders.AppDirectoriesFinder',
 ]
diff --git a/lms/static/images/default-theme/logo-large.png b/lms/static/images/logo-large.png
similarity index 100%
rename from lms/static/images/default-theme/logo-large.png
rename to lms/static/images/logo-large.png
diff --git a/lms/static/images/default-theme/logo.png b/lms/static/images/logo.png
similarity index 100%
rename from lms/static/images/default-theme/logo.png
rename to lms/static/images/logo.png
diff --git a/lms/static/images/default-theme/default-profile_120.png b/lms/static/images/profiles/default_120.png
similarity index 100%
rename from lms/static/images/default-theme/default-profile_120.png
rename to lms/static/images/profiles/default_120.png
diff --git a/lms/static/images/default-theme/default-profile_30.png b/lms/static/images/profiles/default_30.png
similarity index 100%
rename from lms/static/images/default-theme/default-profile_30.png
rename to lms/static/images/profiles/default_30.png
diff --git a/lms/static/images/default-theme/default-profile_50.png b/lms/static/images/profiles/default_50.png
similarity index 100%
rename from lms/static/images/default-theme/default-profile_50.png
rename to lms/static/images/profiles/default_50.png
diff --git a/lms/static/images/default-theme/default-profile_500.png b/lms/static/images/profiles/default_500.png
similarity index 100%
rename from lms/static/images/default-theme/default-profile_500.png
rename to lms/static/images/profiles/default_500.png
diff --git a/lms/templates/courseware/course_about.html b/lms/templates/courseware/course_about.html
index a41bd48446dc05935bf748dfd549619e81989d5d..60b862199a68a961fb8cf55a6642f64ddee3c9a6 100644
--- a/lms/templates/courseware/course_about.html
+++ b/lms/templates/courseware/course_about.html
@@ -10,18 +10,6 @@ from edxmako.shortcuts import marketing_link
 
 <%inherit file="../main.html" />
 <%block name="headextra">
-
-  <%
-    if self.theme_enabled():
-      google_analytics_file = u'../{ga}'.format(
-        ga=microsite.get_value('google_analytics_file', 'theme-google-analytics.html')
-      )
-    else:
-      google_analytics_file = '../google_analytics.html'
-  %>
-
-  <%include file="${google_analytics_file}" />
-
   ## OG (Open Graph) title and description added below to give social media info to display
   ## (https://developers.facebook.com/docs/opengraph/howtos/maximizing-distribution-media-content#tags)
   <meta property="og:title" content="${get_course_about_section(request, course, 'title')}" />
diff --git a/lms/templates/google_analytics.html b/lms/templates/google_analytics.html
deleted file mode 100644
index 44ef9e76d634e8576476a7074aa7fd9499760427..0000000000000000000000000000000000000000
--- a/lms/templates/google_analytics.html
+++ /dev/null
@@ -1,13 +0,0 @@
-% if settings.GOOGLE_ANALYTICS_ACCOUNT:
-    <script type="text/javascript">
-    var _gaq = _gaq || [];
-    _gaq.push(['_setAccount', '${settings.GOOGLE_ANALYTICS_ACCOUNT}']);
-    _gaq.push(['_trackPageview']);
-
-    (function() {
-      var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
-      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
-      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
-    })();
-    </script>
-% endif
diff --git a/lms/templates/google_tag_manager.html b/lms/templates/google_tag_manager.html
deleted file mode 100644
index b3c6892d0eea48d0e963040c6f16f65582ca6d0f..0000000000000000000000000000000000000000
--- a/lms/templates/google_tag_manager.html
+++ /dev/null
@@ -1,4 +0,0 @@
-<%doc>
-    Yet, installing google tag manager for microsite(s).
-    So intentionally left it blank
-</%doc>
diff --git a/lms/templates/header.html b/lms/templates/header.html
index b3732c39128fa96c1a6c7aa9aaf2db869d3322a3..00526f0ef6d92133d1eed12b27857adb87d1220c 100644
--- a/lms/templates/header.html
+++ b/lms/templates/header.html
@@ -1,3 +1,4 @@
+## mako
 <%namespace name='static' file='static_content.html'/>
 <%!
 from microsite_configuration import microsite
@@ -5,13 +6,8 @@ from microsite_configuration import microsite
 <%
 theme_enabled = settings.FEATURES.get("USE_CUSTOM_THEME", False)
 is_microsite = microsite.is_request_in_microsite()
-style_overrides_file = microsite.get_value('css_overrides_file')
 %>
 
-% if style_overrides_file:
-  <link rel="stylesheet" type="text/css" href="${static.url(style_overrides_file)}" />
-% endif
-
 % if theme_enabled and not is_microsite:
   <%include file="theme-header.html" />
 % else:
diff --git a/lms/templates/main.html b/lms/templates/main.html
index 1e450583ececd3bcf6c16fe7208cb182d11a4b6f..4af999ae834bc2b447e156d8481fa2be8e321184 100644
--- a/lms/templates/main.html
+++ b/lms/templates/main.html
@@ -61,7 +61,17 @@ from branding import api as branding_api
   <link rel="icon" type="image/x-icon" href="${static.url(microsite.get_value('favicon_path', settings.FAVICON_PATH))}" />
 
   <%static:css group='style-vendor'/>
-  <%static:css group='style-main'/>
+  ## We could do <%static:css group='style-main'/>, but that's only useful
+  ## if the group contains multiple files, and the 'style-main' group doesn't.
+  ## Instead, we'll construct this <link> element manually, to improve clarity.
+  ## When nothing in the system is referencing the 'style-main' group, it can
+  ## be removed from the environment file.
+  <%
+  application_css_path = "css/lms-main{rtl}.css".format(
+    rtl="-rtl" if get_language_bidi() else "",
+  )
+  %>
+  <link rel="stylesheet" href="${static.url(application_css_path)}" type="text/css" media="all" />
 
   % if disable_courseware_js:
     <%static:js group='base_vendor'/>
@@ -84,31 +94,7 @@ from branding import api as branding_api
 
   <%block name="headextra"/>
 
-<%
-  if theme_enabled() and not is_microsite():
-    header_extra_file = 'theme-head-extra.html'
-    header_file = 'theme-header.html'
-    google_analytics_file = 'theme-google-analytics.html'
-
-    style_overrides_file = None
-
-  else:
-    header_extra_file = microsite.get_template_path('header_extra.html')
-
-    if settings.FEATURES['IS_EDX_DOMAIN'] and not is_microsite():
-        header_file = microsite.get_template_path('navigation-edx.html')
-    else:
-        header_file = microsite.get_template_path('navigation.html')
-
-    google_analytics_file = microsite.get_template_path('google_analytics.html')
-
-    style_overrides_file = microsite.get_value('css_overrides_file')
-  google_tag_manager_file = microsite.get_template_path('google_tag_manager.html')
-%>
-
-  % if header_extra_file:
-    <%include file="${header_extra_file}" />
-  % endif
+  <%static:optional_include_mako file="head-extra.html" with_microsite="True" />
 
   <%include file="widgets/optimizely.html" />
   <%include file="widgets/segment-io.html" />
@@ -116,16 +102,25 @@ from branding import api as branding_api
   <meta name="path_prefix" content="${EDX_ROOT_URL}">
   <meta name="google-site-verification" content="_mipQ4AtZQDNmbtOkwehQDOgCxUUV2fb_C0b6wbiRHY" />
 
-  <%include file="${google_analytics_file}" />
-
-% if style_overrides_file:
-  <link rel="stylesheet" type="text/css" href="${static.url(style_overrides_file)}" />
+<% ga_acct = microsite.get_value("GOOGLE_ANALYTICS_ACCOUNT", settings.GOOGLE_ANALYTICS_ACCOUNT) %>
+% if ga_acct:
+    <script type="text/javascript">
+    var _gaq = _gaq || [];
+    _gaq.push(['_setAccount', '${ga_acct}']);
+    _gaq.push(['_trackPageview']);
+
+    (function() {
+      var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
+      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
+      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
+    })();
+    </script>
 % endif
 
 </head>
 
 <body class="${static.dir_rtl()} <%block name='bodyclass'/> lang_${LANGUAGE_CODE}">
-<%include file="${google_tag_manager_file}" />
+<%static:optional_include_mako file="body-initial.html" with_microsite="True" />
 <div id="page-prompt"></div>
 % if not disable_window_wrap:
   <div class="window-wrap" dir="${static.dir_rtl()}">
@@ -133,7 +128,7 @@ from branding import api as branding_api
     <a class="nav-skip" href="<%block name="nav_skip">#content</%block>">${_("Skip to main content")}</a>
 
     % if not disable_header:
-        <%include file="${header_file}" />
+        <%include file="${microsite.get_template_path('header.html')}" />
     % endif
 
     <div class="content-wrapper" id="content">
@@ -142,16 +137,7 @@ from branding import api as branding_api
     </div>
 
     % if not disable_footer:
-        <%block name="footer">
-          ## Can be overridden by child templates wanting to hide the footer.
-          % if theme_enabled() and not is_microsite():
-            <%include file="theme-footer.html" />
-          % elif settings.FEATURES.get('IS_EDX_DOMAIN', False) and not is_microsite():
-              <%include file="footer-edx-v3.html" />
-          % else:
-            <%include file="${microsite.get_template_path('footer.html')}" />
-          % endif
-        </%block>
+        <%include file="themable-footer.html" />
     % endif
 
 % if not disable_window_wrap:
@@ -162,6 +148,7 @@ from branding import api as branding_api
   <%include file="widgets/segment-io-footer.html" />
   <script type="text/javascript" src="${static.url('js/vendor/noreferrer.js')}" charset="utf-8"></script>
   <script type="text/javascript" src="${static.url('js/utils/navigation.js')}" charset="utf-8"></script>
+  <%static:optional_include_mako file="body-extra.html" with_microsite="True" />
 </body>
 </html>
 
diff --git a/lms/templates/main_django.html b/lms/templates/main_django.html
index c8d2aac2d2d6f0827306fcafe532251ad53e974a..a7245f0cef2caa8984631aa9a625f08720239e3b 100644
--- a/lms/templates/main_django.html
+++ b/lms/templates/main_django.html
@@ -1,8 +1,6 @@
 <!DOCTYPE html>
-{% load pipeline %}
-{% load sekizai_tags i18n microsite %}
+{% load sekizai_tags i18n microsite pipeline optional_include %}
 {% load url from future %}
-{% load staticfiles %}
 <html lang="{{LANGUAGE_CODE}}">
 <head>
   <meta charset="UTF-8">
@@ -21,7 +19,7 @@
   {% block headextra %}{% endblock %}
   {% render_block "css" %}
 
-  {% microsite_css_overrides_file %}
+  {% optional_include "head-extra.html" %}
 
   <meta name="path_prefix" content="{{EDX_ROOT_URL}}">
 </head>
@@ -30,23 +28,15 @@
   <div class="window-wrap" dir="${static.dir_rtl()}">
     <a class="nav-skip" href="{% block nav_skip %}#content{% endblock %}">{% trans "Skip to main content" %}</a>
     {% with course=request.course %}
-      {% if IS_EDX_DOMAIN %}
-        {% include "navigation-edx.html" %}
-      {% else %}
-        {% include "navigation.html" %}
-      {% endif %}
+      {% include "header.html" %}
     {% endwith %}
     <div class="content-wrapper" id="content">
       {% block body %}{% endblock %}
       {% block bodyextra %}{% endblock %}
     </div>
-    {% if IS_REQUEST_IN_MICROSITE %}
-    {# For now we don't support overriden Django templates in microsites. Leave footer blank for now which is better than saying Edx.#}
-    {% elif IS_EDX_DOMAIN %}
-      {% include "footer-edx-v3.html" %}
-    {% else %}
+    {% with course=request.course %}
       {% include "footer.html" %}
-    {% endif %}
+    {% endwith %}
 
   </div>
 
diff --git a/lms/templates/themable-footer.html b/lms/templates/themable-footer.html
new file mode 100644
index 0000000000000000000000000000000000000000..09893ad4e8012a018537d5d5190853c9eb62edcd
--- /dev/null
+++ b/lms/templates/themable-footer.html
@@ -0,0 +1,20 @@
+## mako
+<%!
+from microsite_configuration import microsite
+%>
+<%
+theme_enabled = settings.FEATURES.get("USE_CUSTOM_THEME", False)
+is_microsite = microsite.is_request_in_microsite()
+%>
+
+## This file only exists as an additional layer of indirection to preserve
+## backwards compatibility with microsites and Stanford theming
+## (as much as possible). If you are writing your own theme using the
+## "comprehensive theming" system, do NOT override this file. You should
+## override "footer.html" instead.
+
+% if theme_enabled and not is_microsite:
+  <%include file="theme-footer.html" />
+% else:
+  <%include file="${microsite.get_template_path('footer.html')}" />
+% endif
diff --git a/openedx/core/djangoapps/theming/core.py b/openedx/core/djangoapps/theming/core.py
index 45b8e33c1a16b83bd058c4bd06382750eeab06f2..bd2e4b5d0d63560b8406a67c474c2ab93277fcbd 100644
--- a/openedx/core/djangoapps/theming/core.py
+++ b/openedx/core/djangoapps/theming/core.py
@@ -1,6 +1,7 @@
 """
 Core logic for Comprehensive Theming.
 """
+from path import Path
 
 from django.conf import settings
 
@@ -28,21 +29,26 @@ def comprehensive_theme_changes(theme_dir):
         'settings': {},
         'mako_paths': [],
     }
+    root = Path(settings.PROJECT_ROOT)
+    if root.name == "":
+        root = root.parent
 
-    templates_dir = theme_dir / "lms" / "templates"
+    component_dir = theme_dir / root.name
+
+    templates_dir = component_dir / "templates"
     if templates_dir.isdir():
         changes['settings']['TEMPLATE_DIRS'] = [templates_dir] + settings.DEFAULT_TEMPLATE_ENGINE['DIRS']
         changes['mako_paths'].append(templates_dir)
 
-    staticfiles_dir = theme_dir / "lms" / "static"
+    staticfiles_dir = component_dir / "static"
     if staticfiles_dir.isdir():
         changes['settings']['STATICFILES_DIRS'] = [staticfiles_dir] + settings.STATICFILES_DIRS
 
-    locale_dir = theme_dir / "lms" / "conf" / "locale"
+    locale_dir = component_dir / "conf" / "locale"
     if locale_dir.isdir():
         changes['settings']['LOCALE_PATHS'] = [locale_dir] + settings.LOCALE_PATHS
 
-    favicon = theme_dir / "lms" / "static" / "images" / "favicon.ico"
+    favicon = component_dir / "static" / "images" / "favicon.ico"
     if favicon.isfile():
         changes['settings']['FAVICON_PATH'] = str(favicon)
 
diff --git a/openedx/core/djangoapps/theming/finders.py b/openedx/core/djangoapps/theming/finders.py
new file mode 100644
index 0000000000000000000000000000000000000000..cbf4366f5a6f1e2fbe8613a3a612765e8cdeedbb
--- /dev/null
+++ b/openedx/core/djangoapps/theming/finders.py
@@ -0,0 +1,79 @@
+"""
+Static file finders for Django.
+https://docs.djangoproject.com/en/1.8/ref/settings/#std:setting-STATICFILES_FINDERS
+Yes, this interface is private and undocumented, but we need to access it anyway.
+
+In order to deploy Open edX in production, it's important to be able to collect
+and process static assets: images, CSS, JS, fonts, etc. Django's collectstatic
+system is the accepted way to do that in Django-based projects, but that system
+doesn't handle every kind of collection and processing that web developers need.
+Other open source projects like `Django-Pipeline`_ and `Django-Require`_ hook
+into Django's collectstatic system to provide features like minification,
+compression, Sass pre-processing, and require.js optimization for assets before
+they are pushed to production. To make sure that themed assets are collected
+and served by the system (in addition to core assets), we need to extend this
+interface, as well.
+
+.. _Django-Pipeline: http://django-pipeline.readthedocs.org/
+.. _Django-Require: https://github.com/etianen/django-require
+"""
+from path import Path
+from django.conf import settings
+from django.core.exceptions import ImproperlyConfigured
+from django.contrib.staticfiles import utils
+from django.contrib.staticfiles.finders import BaseFinder
+from openedx.core.djangoapps.theming.storage import CachedComprehensiveThemingStorage
+
+
+class ComprehensiveThemeFinder(BaseFinder):
+    """
+    A static files finder that searches the active comprehensive theme
+    for static files. If the ``COMPREHENSIVE_THEME_DIR`` setting is unset,
+    or the ``COMPREHENSIVE_THEME_DIR`` does not exist on the file system,
+    this finder will never find any files.
+    """
+    def __init__(self, *args, **kwargs):
+        super(ComprehensiveThemeFinder, self).__init__(*args, **kwargs)
+
+        theme_dir = getattr(settings, "COMPREHENSIVE_THEME_DIR", "")
+        if not theme_dir:
+            self.storage = None
+            return
+
+        if not isinstance(theme_dir, basestring):
+            raise ImproperlyConfigured("Your COMPREHENSIVE_THEME_DIR setting must be a string")
+
+        root = Path(settings.PROJECT_ROOT)
+        if root.name == "":
+            root = root.parent
+
+        component_dir = Path(theme_dir) / root.name
+        static_dir = component_dir / "static"
+        self.storage = CachedComprehensiveThemingStorage(location=static_dir)
+
+    def find(self, path, all=False):  # pylint: disable=redefined-builtin
+        """
+        Looks for files in the default file storage, if it's local.
+        """
+        if not self.storage:
+            return []
+
+        if path.startswith(self.storage.prefix):
+            # strip the prefix
+            path = path[len(self.storage.prefix):]
+
+        if self.storage.exists(path):
+            match = self.storage.path(path)
+            if all:
+                match = [match]
+            return match
+
+        return []
+
+    def list(self, ignore_patterns):
+        """
+        List all files of the storage.
+        """
+        if self.storage and self.storage.exists(''):
+            for path in utils.get_files(self.storage, ignore_patterns):
+                yield path, self.storage
diff --git a/openedx/core/djangoapps/theming/startup.py b/openedx/core/djangoapps/theming/startup.py
index ae217804b7358e9c6d24b289eb013031c7594993..8642a7655527af01052087c6cdd6aa3bf062a983 100644
--- a/openedx/core/djangoapps/theming/startup.py
+++ b/openedx/core/djangoapps/theming/startup.py
@@ -10,5 +10,5 @@ from .core import enable_comprehensive_theme
 
 def run():
     """Enable comprehensive theming, if we should."""
-    if settings.COMP_THEME_DIR:
-        enable_comprehensive_theme(theme_dir=path(settings.COMP_THEME_DIR))
+    if settings.COMPREHENSIVE_THEME_DIR:
+        enable_comprehensive_theme(theme_dir=path(settings.COMPREHENSIVE_THEME_DIR))
diff --git a/openedx/core/djangoapps/theming/storage.py b/openedx/core/djangoapps/theming/storage.py
new file mode 100644
index 0000000000000000000000000000000000000000..3fb5311b5a6b4f591d76167a5578380eec7245bf
--- /dev/null
+++ b/openedx/core/djangoapps/theming/storage.py
@@ -0,0 +1,88 @@
+"""
+Comprehensive Theming support for Django's collectstatic functionality.
+See https://docs.djangoproject.com/en/1.8/ref/contrib/staticfiles/
+"""
+from path import Path
+import os.path
+from django.conf import settings
+from django.core.exceptions import ImproperlyConfigured
+from django.contrib.staticfiles.storage import StaticFilesStorage, CachedFilesMixin
+from django.utils._os import safe_join
+
+
+class ComprehensiveThemingAwareMixin(object):
+    """
+    Mixin for Django storage system to make it aware of the currently-active
+    comprehensive theme, so that it can generate theme-scoped URLs for themed
+    static assets.
+    """
+    def __init__(self, *args, **kwargs):
+        super(ComprehensiveThemingAwareMixin, self).__init__(*args, **kwargs)
+        theme_dir = getattr(settings, "COMPREHENSIVE_THEME_DIR", "")
+        if not theme_dir:
+            self.theme_location = None
+            return
+
+        if not isinstance(theme_dir, basestring):
+            raise ImproperlyConfigured("Your COMPREHENSIVE_THEME_DIR setting must be a string")
+
+        root = Path(settings.PROJECT_ROOT)
+        if root.name == "":
+            root = root.parent
+
+        component_dir = Path(theme_dir) / root.name
+        self.theme_location = component_dir / "static"
+
+    @property
+    def prefix(self):
+        """
+        This is used by the ComprehensiveThemeFinder in the collection step.
+        """
+        theme_dir = getattr(settings, "COMPREHENSIVE_THEME_DIR", "")
+        if not theme_dir:
+            return None
+        theme_name = os.path.basename(os.path.normpath(theme_dir))
+        return "themes/{name}/".format(name=theme_name)
+
+    def themed(self, name):
+        """
+        Given a name, return a boolean indicating whether that name exists
+        as a themed asset in the comprehensive theme.
+        """
+        # Nothing can be themed if we don't have a theme location.
+        if not self.theme_location:
+            return False
+
+        path = safe_join(self.theme_location, name)
+        return os.path.exists(path)
+
+    def path(self, name):
+        """
+        Get the path to the real asset on disk
+        """
+        if self.themed(name):
+            base = self.theme_location
+        else:
+            base = self.location
+        path = safe_join(base, name)
+        return os.path.normpath(path)
+
+    def url(self, name, *args, **kwargs):
+        """
+        Add the theme prefix to the asset URL
+        """
+        if self.themed(name):
+            name = self.prefix + name
+        return super(ComprehensiveThemingAwareMixin, self).url(name, *args, **kwargs)
+
+
+class CachedComprehensiveThemingStorage(
+        ComprehensiveThemingAwareMixin,
+        CachedFilesMixin,
+        StaticFilesStorage
+):
+    """
+    Used by the ComprehensiveThemeFinder class. Mixes in support for cached
+    files and comprehensive theming in static files.
+    """
+    pass
diff --git a/openedx/core/djangoapps/theming/templatetags/__init__.py b/openedx/core/djangoapps/theming/templatetags/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/openedx/core/djangoapps/theming/templatetags/optional_include.py b/openedx/core/djangoapps/theming/templatetags/optional_include.py
new file mode 100644
index 0000000000000000000000000000000000000000..77e6ae2ffb8eb7b778f905cb13872a60f962c046
--- /dev/null
+++ b/openedx/core/djangoapps/theming/templatetags/optional_include.py
@@ -0,0 +1,77 @@
+"""
+The functions in this module are based on the contents of
+https://github.com/django/django/blob/1.8.5/django/template/loader_tags.py --
+specifically, the do_include function. It has been modified as little as
+possible, in order to match the behavior of the {% include %} template tag,
+except for making it optional.
+"""
+# Because we want to match the original loader_tags.py file as closely as
+# possible, we should disable pylint so it doesn't complain about the violations
+# that are already in that file
+# pylint: skip-file
+from django.template.base import (
+    TemplateSyntaxError, Library, token_kwargs, TemplateDoesNotExist
+)
+from django.template.loader_tags import IncludeNode
+
+register = Library()
+
+
+class OptionalIncludeNode(IncludeNode):
+    def render(self, context):
+        try:
+            return super(OptionalIncludeNode, self).render(context)
+        except TemplateDoesNotExist:
+            return ''
+
+
+@register.tag('optional_include')
+def do_include(parser, token):
+    """
+    Loads a template and renders it with the current context, if it exists.
+    You can pass additional context using keyword arguments.
+
+    Example::
+
+        {% optional_include "foo/some_include" %}
+        {% optional_include "foo/some_include" with bar="BAZZ!" baz="BING!" %}
+
+    Use the ``only`` argument to exclude the current context when rendering
+    the included template::
+
+        {% optional_include "foo/some_include" only %}
+        {% optional_include "foo/some_include" with bar="1" only %}
+    """
+    bits = token.split_contents()
+    if len(bits) < 2:
+        msg = (
+            "%r tag takes at least one argument: the name of the template "
+            "to be optionally included."
+        ) % bits[0]
+        raise TemplateSyntaxError(msg)
+    options = {}
+    remaining_bits = bits[2:]
+    while remaining_bits:
+        option = remaining_bits.pop(0)
+        if option in options:
+            raise TemplateSyntaxError('The %r option was specified more '
+                                      'than once.' % option)
+        if option == 'with':
+            value = token_kwargs(remaining_bits, parser, support_legacy=False)
+            if not value:
+                raise TemplateSyntaxError('"with" in %r tag needs at least '
+                                          'one keyword argument.' % bits[0])
+        elif option == 'only':
+            value = True
+        else:
+            raise TemplateSyntaxError('Unknown argument for %r tag: %r.' %
+                                      (bits[0], option))
+        options[option] = value
+    isolated_context = options.get('only', False)
+    namemap = options.get('with', {})
+    node = OptionalIncludeNode(
+        parser.compile_filter(bits[1]),
+        extra_context=namemap,
+        isolated_context=isolated_context,
+    )
+    return node
diff --git a/openedx/core/djangoapps/theming/test_util.py b/openedx/core/djangoapps/theming/test_util.py
index 3a8dc011acb8ec57e572be5bb8a665fcfcd6c583..63220f94a74380f74a5937d6d3c8fd82931c7465 100644
--- a/openedx/core/djangoapps/theming/test_util.py
+++ b/openedx/core/djangoapps/theming/test_util.py
@@ -16,7 +16,7 @@ import edxmako
 from .core import comprehensive_theme_changes
 
 
-def with_comp_theme(theme_dir):
+def with_comprehensive_theme(theme_dir):
     """
     A decorator to run a test with a particular comprehensive theme.
 
@@ -34,7 +34,7 @@ def with_comp_theme(theme_dir):
     def _decorator(func):                       # pylint: disable=missing-docstring
         @wraps(func)
         def _decorated(*args, **kwargs):        # pylint: disable=missing-docstring
-            with override_settings(COMP_THEME_DIR=theme_dir, **changes['settings']):
+            with override_settings(COMPREHENSIVE_THEME_DIR=theme_dir, **changes['settings']):
                 with edxmako.save_lookups():
                     for template_dir in changes['mako_paths']:
                         edxmako.paths.add_lookup('main', template_dir, prepend=True)
@@ -60,8 +60,8 @@ def with_is_edx_domain(is_edx_domain):
     # decorators, which is confusing.
     def _decorator(func):                       # pylint: disable=missing-docstring
         if is_edx_domain:
-            # This applies @with_comp_theme to the func.
-            func = with_comp_theme(settings.REPO_ROOT / "themes" / "edx.org")(func)
+            # This applies @with_comprehensive_theme to the func.
+            func = with_comprehensive_theme(settings.REPO_ROOT / "themes" / "edx.org")(func)
 
         # This applies @patch.dict() to the func to set IS_EDX_DOMAIN.
         func = patch.dict('django.conf.settings.FEATURES', {"IS_EDX_DOMAIN": is_edx_domain})(func)
diff --git a/openedx/core/storage.py b/openedx/core/storage.py
new file mode 100644
index 0000000000000000000000000000000000000000..6607b27c0c0d481f3e2c34b7c397c80a232e858d
--- /dev/null
+++ b/openedx/core/storage.py
@@ -0,0 +1,35 @@
+"""
+Django storage backends for Open edX.
+"""
+from django.contrib.staticfiles.storage import StaticFilesStorage, CachedFilesMixin
+from pipeline.storage import PipelineMixin, NonPackagingMixin
+from require.storage import OptimizedFilesMixin
+from openedx.core.djangoapps.theming.storage import ComprehensiveThemingAwareMixin
+
+
+class ProductionStorage(
+        ComprehensiveThemingAwareMixin,
+        OptimizedFilesMixin,
+        PipelineMixin,
+        CachedFilesMixin,
+        StaticFilesStorage
+):
+    """
+    This class combines Django's StaticFilesStorage class with several mixins
+    that provide additional functionality. We use this version on production.
+    """
+    pass
+
+
+class DevelopmentStorage(
+        ComprehensiveThemingAwareMixin,
+        NonPackagingMixin,
+        PipelineMixin,
+        StaticFilesStorage
+):
+    """
+    This class combines Django's StaticFilesStorage class with several mixins
+    that provide additional functionality. We use this version for development,
+    so that we can skip packaging and optimization.
+    """
+    pass
diff --git a/pavelib/assets.py b/pavelib/assets.py
index eac7756b31fba22a79805376b73767c142b78347..21947628dcbb770d29254e20276295578c3c891c 100644
--- a/pavelib/assets.py
+++ b/pavelib/assets.py
@@ -45,18 +45,18 @@ def configure_paths():
             css_dir.mkdir_p()
             SASS_DIRS.append(sass_dir)
 
-    if edxapp_env.env_tokens.get("COMP_THEME_DIR", ""):
-        theme_dir = path(edxapp_env.env_tokens["COMP_THEME_DIR"])
+    if edxapp_env.env_tokens.get("COMPREHENSIVE_THEME_DIR", ""):
+        theme_dir = path(edxapp_env.env_tokens["COMPREHENSIVE_THEME_DIR"])
         lms_sass = theme_dir / "lms" / "static" / "sass"
         lms_css = theme_dir / "lms" / "static" / "css"
         if lms_sass.isdir():
             lms_css.mkdir_p()
             SASS_DIRS.append(lms_sass)
-        studio_sass = theme_dir / "studio" / "static" / "sass"
-        studio_css = theme_dir / "studio" / "static" / "css"
-        if studio_sass.isdir():
-            studio_css.mkdir_p()
-            SASS_DIRS.append(studio_sass)
+        cms_sass = theme_dir / "cms" / "static" / "sass"
+        cms_css = theme_dir / "cms" / "static" / "css"
+        if cms_sass.isdir():
+            cms_css.mkdir_p()
+            SASS_DIRS.append(cms_sass)
 
 configure_paths()
 
diff --git a/themes/README.rst b/themes/README.rst
index 88fe30dc179f3a3434c4fbe43450e2d6e4aaa1e6..90f42b62154410871996f991ac96e378555dacfd 100644
--- a/themes/README.rst
+++ b/themes/README.rst
@@ -90,6 +90,28 @@ in the appropriate place, and making the changes you need.  Keep in mind that
 in the future if you upgrade the Open edX code, you may have to update the
 copied template in your theme also.
 
+Template Names
+==============
+
+Here are the list of template names that you *should* use in your comprehensive
+theme (so far):
+
+* ``header.html``
+* ``footer.html``
+
+You should **not** use the following names in your comprehensive theme:
+
+* ``themable-footer.html``
+
+If you look at the ``main.html`` template file, you will notice that it includes
+``header.html`` and ``themable-footer.html``, rather than ``footer.html``.
+You might be inclined to override ``themable-footer.html`` as a result. DO NOT
+DO THIS. ``themable-footer.html`` is an additional layer of indirection that
+is necessary to avoid breaking microsites, which also refers to a file named
+``footer.html``. The goal is to eventually make comprehensive theming do
+everything that microsites does now, and then deprecate and remove microsites
+from the codebase. At that point, the ``themable-footer.html`` file will go
+away, since the additional layer of indirection will no longer be necessary.
 
 Installing your theme
 ---------------------
@@ -101,9 +123,9 @@ directory. There are two ways to do this.
 
     #.  As the vagrant user, edit (or create)
         /edx/app/edx_ansible/server-vars.yml to add the
-        ``edxapp_comp_theme_dir`` value::
+        ``edxapp_comprehensive_theme_dir`` value::
 
-            edxapp_comp_theme_dir: '/full/path/to/my-theme'
+            edxapp_comprehensive_theme_dir: '/full/path/to/my-theme'
 
     #.  Run the update script::
 
@@ -111,13 +133,18 @@ directory. There are two ways to do this.
             $ sudo /edx/bin/update edx-platform HEAD
 
 #.  Otherwise, edit the /edx/app/edxapp/lms.env.json file to add the
-    ``COMP_THEME_DIR`` value::
+    ``COMPREHENSIVE_THEME_DIR`` value::
 
-        "COMP_THEME_DIR": "/full/path/to/my-theme",
+        "COMPREHENSIVE_THEME_DIR": "/full/path/to/my-theme",
 
 Restart your site.  Your changes should now be visible.
 
 
+Comprehensive Theming
+=====================
+* The ``PROFILE_IMAGE_DEFAULT_FILENAME`` Django setting is now ignored.
+
+
 "Stanford" theming
 ==================
 
@@ -154,3 +181,54 @@ name in the ``@import`` line.
 Run the ``update_assets`` command to recompile the theme::
 
     $ paver update_assets lms --settings=aws
+
+Microsites
+==========
+
+If you want to continue using the "Microsites" theming system, there are a few
+changes you'll need to make. A few templates have been renamed, or folded into
+other templates:
+
+* ``header_extra.html`` has been renamed to ``head-extra.html``. This file
+  was always inserted into the ``<head>`` element of the page, rather than
+  the header of the ``<body>`` element, so this change makes the name more
+  accurate.
+
+* ``google_analytics.html`` has been removed. The contents of this template
+  can and should be added to the ``head-extra.html`` template.
+
+* ``google_tag_manager.html`` has been renamed to ``body-initial.html``.
+
+In addition, there are some other changes you'll need to make:
+
+* The ``google_analytics_file`` config value is now ignored. If your Open edX
+  installation has a Google Analytics account ID set, the Google Analytics
+  JavaScript will be included automatically on your site using that account ID.
+  You can set this account ID either using the "GOOGLE_ANALYTICS_ACCOUNT" value
+  in the Django settings, or by setting the newly-added "GOOGLE_ANALYTICS_ACCOUNT"
+  config value in your microsite configuration.
+
+* If you don't want the Google Analytics JavaScript to be output at all in your
+  microsite, set the "GOOGLE_ANALYTICS_ACCOUNT" config value to the empty string.
+  If you want to customize the way that Google Analytics is loaded, set the
+  "GOOGLE_ANALYTICS_ACCOUNT" config value to the empty string, and then load
+  Google Analytics yourself (with whatever customizations you want) in your
+  ``head-extra.html`` template.
+
+* The ``css_overrides_file`` config value is now ignored. To add a CSS override
+  file to your microsite, create a ``head-extra.html`` template with the
+  following content:
+
+  .. code-block:: mako
+
+    <%namespace name='static' file='../../static_content.html'/>
+    <%! from microsite_configuration import microsite %>
+    <% style_overrides_file = microsite.get_value('css_overrides_file') %>
+
+    % if style_overrides_file:
+      <link rel="stylesheet" type="text/css" href="${static.url(style_overrides_file)}" />
+    % endif
+
+  If you already have a ``head-extra.html`` template, you can modify it to
+  output this ``<link rel="stylesheet">`` tag, in addition to whatever else you
+  already have in that template.
diff --git a/cms/static/images/edx-theme/edx-studio-logo.png b/themes/edx.org/cms/static/images/studio-logo.png
similarity index 100%
rename from cms/static/images/edx-theme/edx-studio-logo.png
rename to themes/edx.org/cms/static/images/studio-logo.png
diff --git a/lms/static/images/edx-theme/edx-logo-bw.png b/themes/edx.org/lms/static/images/logo-large.png
similarity index 100%
rename from lms/static/images/edx-theme/edx-logo-bw.png
rename to themes/edx.org/lms/static/images/logo-large.png
diff --git a/lms/static/images/edx-theme/edx-header-logo.png b/themes/edx.org/lms/static/images/logo.png
similarity index 100%
rename from lms/static/images/edx-theme/edx-header-logo.png
rename to themes/edx.org/lms/static/images/logo.png
diff --git a/lms/static/images/edx-theme/default_120.png b/themes/edx.org/lms/static/images/profiles/default_120.png
similarity index 100%
rename from lms/static/images/edx-theme/default_120.png
rename to themes/edx.org/lms/static/images/profiles/default_120.png
diff --git a/lms/static/images/edx-theme/default_30.png b/themes/edx.org/lms/static/images/profiles/default_30.png
similarity index 100%
rename from lms/static/images/edx-theme/default_30.png
rename to themes/edx.org/lms/static/images/profiles/default_30.png
diff --git a/lms/static/images/edx-theme/default_50.png b/themes/edx.org/lms/static/images/profiles/default_50.png
similarity index 100%
rename from lms/static/images/edx-theme/default_50.png
rename to themes/edx.org/lms/static/images/profiles/default_50.png
diff --git a/lms/static/images/edx-theme/default_500.png b/themes/edx.org/lms/static/images/profiles/default_500.png
similarity index 100%
rename from lms/static/images/edx-theme/default_500.png
rename to themes/edx.org/lms/static/images/profiles/default_500.png
diff --git a/themes/edx.org/lms/templates/footer.html b/themes/edx.org/lms/templates/footer.html
new file mode 100644
index 0000000000000000000000000000000000000000..992d43744e611db3b24cfabe5e30889540f0c547
--- /dev/null
+++ b/themes/edx.org/lms/templates/footer.html
@@ -0,0 +1,83 @@
+## mako
+<%!
+  from django.utils.translation import ugettext as _
+  from branding.api import get_footer
+%>
+<% footer = get_footer(is_secure=is_secure) %>
+<%namespace name='static' file='static_content.html'/>
+
+## WARNING: These files are specific to edx.org and are not used in installations outside of that domain. Open edX users will want to use the file "footer.html" for any changes or overrides.
+<footer id="footer-edx-v3" role="contentinfo" aria-label="${_("Page Footer")}"
+  ## When rendering the footer through the branding API,
+  ## the direction may not be set on the parent element,
+  ## so we set it here.
+  % if bidi:
+    dir=${bidi}
+  % endif
+>
+    <h2 class="sr footer-about-title">${_("About edX")}</h2>
+    <div class="footer-content-wrapper">
+      <div class="footer-logo">
+          <img alt="edX logo" src="${footer['logo_image']}">
+      </div>
+
+      <div class="site-details">
+          <nav class="site-nav" aria-label="${_("About edX")}">
+              % for link in footer["navigation_links"]:
+              <a href="${link['url']}">${link['title']}</a>
+              % endfor
+          </nav>
+          <nav class="legal-notices" aria-label="${_("Legal")}">
+              % for link in footer["legal_links"]:
+              <a href="${link['url']}">${link['title']}</a>
+              % endfor
+          </nav>
+          <p class="copyright">${footer['copyright']}</p>
+
+          ## The OpenEdX link may be hidden when this view is served
+          ## through an API to partner sites (such as marketing sites or blogs),
+          ## which are not technically powered by OpenEdX.
+          % if not hide_openedx_link:
+          <div class="openedx-link">
+            <a href="${footer['openedx_link']['url']}" title="${footer['openedx_link']['title']}">
+              <img alt="${footer['openedx_link']['title']}" src="${footer['openedx_link']['image']}" width="140">
+            </a>
+          </div>
+          % endif
+      </div>
+
+      <div class="external-links">
+        <div class="social-media-links">
+          % for link in footer['social_links']:
+          <a href="${link['url']}" class="sm-link external" title="${link['title']}" rel="noreferrer">
+            <span class="icon fa ${link['icon-class']}" aria-hidden="true"></span>
+            <span class="sr">${link['action']}</span>
+          </a>
+          % endfor
+        </div>
+
+        <div class="mobile-app-links">
+          % for link in footer['mobile_links']:
+          <a href="${link['url']}" class="app-link external">
+            <img alt="${link['title']}" src="${link['image']}">
+          </a>
+          % endfor
+        </div>
+      </div>
+    </div>
+</footer>
+% if include_dependencies:
+  <%static:js group='base_vendor'/>
+  <%static:css group='style-vendor'/>
+  <%include file="widgets/segment-io.html" />
+  <%include file="widgets/segment-io-footer.html" />
+% endif
+% if footer_css_urls:
+  % for url in footer_css_urls:
+    <link rel="stylesheet" type="text/css" href="${url}"></link>
+  % endfor
+% endif
+% if footer_js_url:
+  <script type="text/javascript" src="${footer_js_url}"></script>
+% endif
+
diff --git a/themes/edx.org/lms/templates/header.html b/themes/edx.org/lms/templates/header.html
new file mode 100644
index 0000000000000000000000000000000000000000..f5790b4319a75b21fd84d3c1ee7e05cd91382650
--- /dev/null
+++ b/themes/edx.org/lms/templates/header.html
@@ -0,0 +1,142 @@
+## mako
+<%namespace name='static' file='static_content.html'/>
+<%namespace file='main.html' import="login_query"/>
+<%!
+from django.core.urlresolvers import reverse
+from django.utils.translation import ugettext as _
+
+from microsite_configuration import microsite
+from microsite_configuration.templatetags.microsite import platform_name
+
+# App that handles subdomain specific branding
+import branding
+# app that handles site status messages
+from status.status import get_site_status_msg
+%>
+
+## Provide a hook for themes to inject branding on top.
+<%block name="navigation_top" />
+
+<%block>
+<%
+try:
+    course_id = course.id
+except:
+    # can't figure out a better way to get at a possibly-defined course var
+    course_id = None
+site_status_msg = get_site_status_msg(course_id)
+%>
+% if site_status_msg:
+<div class="site-status">
+  <div class="inner-wrapper">
+    <span class="white-error-icon"></span>
+    <p>${site_status_msg}</p>
+  </div>
+</div>
+% endif
+</%block>
+
+<header class="${"global slim" if course and not disable_courseware_header else "global-new"}" aria-label="Main" role="banner">
+  <div class="${'rwd ' if responsive else ''}wrapper-header nav-container">
+    <h1 class="logo" itemscope="" itemtype="http://schema.org/Organization">
+      <a href="${marketing_link('ROOT')}" itemprop="url">
+        <%block name="navigation_logo">
+            <img src="${static.url("images/logo.png")}" alt="${_("{platform_name} Home Page").format(platform_name=platform_name())}" itemprop="logo" />
+        </%block>
+      </a>
+    </h1>
+
+    % if course and not disable_courseware_header:
+    <h2 class="course-header">
+      <span class="provider">${course.display_org_with_default | h}:</span>
+      <span class="course-number">${course.display_number_with_default | h}</span>
+      <span class="course-name">${course.display_name_with_default}</span>
+    </h2>
+    % endif
+
+    % if user.is_authenticated():
+      % if not course or disable_courseware_header:
+        % if not nav_hidden:
+    <nav aria-label="Main" class="nav-main">
+      <ul class="left nav-global authenticated">
+        <%block name="navigation_global_links_authenticated">
+          <li class="nav-global-01">
+            <a href="${marketing_link('HOW_IT_WORKS')}">${_("How it Works")}</a>
+          </li>
+          <li class="nav-global-02">
+            <a href="${marketing_link('COURSES')}">${_("Find Courses")}</a>
+          </li>
+          <li class="nav-global-03">
+            <a href="${marketing_link('SCHOOLS')}">${_("Schools & Partners")}</a>
+          </li>
+        </%block>
+      </ul>
+    </nav>
+        % endif
+      % endif
+
+    <ul class="user">
+      <li class="primary">
+        <a href="${reverse('dashboard')}" class="user-link">
+          <span class="sr">${_("Dashboard for:")}</span>
+          <div>${user.username}</div>
+        </a>
+      </li>
+      <li class="primary">
+        <a href="#" class="dropdown" aria-haspopup="true" aria-expanded="false"><span class="sr">${_("More options dropdown")}</span> &#9662;</a>
+        <ul class="dropdown-menu" aria-label="More Options" role="menu">
+          <%block name="navigation_dropdown_menu_links" >
+            <li><a href="${reverse('dashboard')}">${_("Dashboard")}</a></li>
+            <li><a href="${reverse('learner_profile', kwargs={'username': user.username})}">${_("Profile")}</a></li>
+            <li><a href="${reverse('account_settings')}">${_("Account")}</a></li>
+          </%block>
+          <li><a href="${reverse('logout')}" role="menuitem">${_("Sign Out")}</a></li>
+        </ul>
+      </li>
+    </ul>
+
+      % if should_display_shopping_cart_func(): # see shoppingcart.context_processor.user_has_cart_context_processor
+    <ul class="user">
+      <li class="primary">
+        <a class="shopping-cart" href="${reverse('shoppingcart.views.show_cart')}">
+          <i class="icon fa fa-shopping-cart" aria-hidden="true"></i> ${_("Shopping Cart")}
+        </a>
+      </li>
+    </ul>
+      % endif
+
+    % else:
+    <nav aria-label="Account" class="nav-account-management">
+      <div class="right nav-courseware">
+        <div class="nav-courseware-01">
+          % if not settings.FEATURES['DISABLE_LOGIN_BUTTON']:
+              % if course and settings.FEATURES.get('RESTRICT_ENROLL_BY_REG_METHOD') and course.enrollment_domain:
+              <a class="cta cta-login" href="${reverse('course-specific-login', args=[course.id.to_deprecated_string()])}${login_query()}">${_("Sign in")}</a>
+              % else:
+              <a class="cta cta-login" href="/login${login_query()}">${_("Sign in")}</a>
+              % endif
+          % endif
+        </div>
+        % if not settings.FEATURES['DISABLE_LOGIN_BUTTON']:
+          % if course and settings.FEATURES.get('RESTRICT_ENROLL_BY_REG_METHOD') and course.enrollment_domain:
+          <div class="nav-courseware-02">
+            <a class="cta cta-register nav-courseware-button" href="${reverse('course-specific-register', args=[course.id.to_deprecated_string()])}">${_("Register")}</a>
+          </div>
+          % else:
+          <div class="nav-courseware-02">
+            <a class="cta cta-register nav-courseware-button" href="/register">${_("Register")}</a>
+          </div>
+          % endif
+        % endif
+      </div>
+    </nav>
+    % endif
+  </div>
+</header>
+% if course:
+<!--[if lte IE 9]>
+<div class="ie-banner" aria-hidden="true">${_('<strong>Warning:</strong> Your browser is not fully supported. We strongly recommend using {chrome_link} or {ff_link}.').format(chrome_link='<a href="https://www.google.com/chrome" target="_blank">Chrome</a>', ff_link='<a href="http://www.mozilla.org/firefox" target="_blank">Firefox</a>')}</div>
+<![endif]-->
+% endif
+
+<%include file="help_modal.html"/>