diff --git a/core/modules/breakpoints/README.txt b/core/modules/breakpoints/README.txt
new file mode 100644
index 0000000..5d6aed4
--- /dev/null
+++ b/core/modules/breakpoints/README.txt
@@ -0,0 +1,3 @@
+-- SUMMARY --
+
+Breakpoints
\ No newline at end of file
diff --git a/core/modules/breakpoints/breakpoints.info b/core/modules/breakpoints/breakpoints.info
new file mode 100644
index 0000000..12d8041
--- /dev/null
+++ b/core/modules/breakpoints/breakpoints.info
@@ -0,0 +1,7 @@
+name = Breakpoints
+description = General breakpoints functionality.
+core = 8.x
+files[] = breakpoints.module
+files[] = breakpoints.install
+
+dependencies[] = config
diff --git a/core/modules/breakpoints/breakpoints.install b/core/modules/breakpoints/breakpoints.install
new file mode 100644
index 0000000..a779975
--- /dev/null
+++ b/core/modules/breakpoints/breakpoints.install
@@ -0,0 +1,13 @@
+<?php
+/**
+ * @file
+ * Install, update and uninstall functions for the breakpoints module.
+ */
+
+/**
+ * Breakpoint module split in to two modules: Breakpoints and Breakpoints UI.
+ * Enable Breakpoints UI so that existing installations don't lose functionality.
+ */
+function breakpoints_update_8101() {
+  module_enable(array('breakpoints_ui'));
+}
\ No newline at end of file
diff --git a/core/modules/breakpoints/breakpoints.module b/core/modules/breakpoints/breakpoints.module
new file mode 100644
index 0000000..801e942
--- /dev/null
+++ b/core/modules/breakpoints/breakpoints.module
@@ -0,0 +1,246 @@
+<?php
+
+use \Drupal\breakpoints\Breakpoint;
+use \Drupal\breakpoints\BreakpointSet;
+
+/**
+ * @file
+ * Breakpoints
+ */
+
+define('BREAKPOINTS_SOURCE_TYPE_THEME', 'theme');
+define('BREAKPOINTS_SOURCE_TYPE_MODULE', 'module');
+define('BREAKPOINTS_SOURCE_TYPE_CUSTOM', 'custom');
+
+/**
+ * Implements hook_enable().
+ * Import breakpoints from all enabled themes.
+ */
+function breakpoints_enable() {
+  config_install_default_config('module', 'breakpoints');
+  $themes = list_themes();
+  breakpoints_themes_enabled(array_keys($themes));
+}
+
+/**
+ * Implements hook_themes_enabled();
+ * Import breakpoints from all new enabled themes.
+ */
+function breakpoints_themes_enabled($theme_list) {
+  $themes = list_themes();
+  foreach ($theme_list as $theme_key) {
+    if ($themes[$theme_key]->status) {
+      // Check theme_key.breakpoints.yml first
+      $theme_breakpoints = breakpoints_get_theme_breakpoint_list($theme_key);
+      // Fallback to theme_key.info
+      if (empty($theme_breakpoints) && isset($themes[$theme_key]->info['breakpoints'])) {
+        $theme_breakpoints = $themes[$theme_key]->info['breakpoints'];
+      }
+      if (!empty($theme_breakpoints)) {
+        $weight = 0;
+        // Build a breakpoint set for each theme
+        $breakpointset = new BreakpointSet();
+        $breakpointset->id = $theme_key;
+        $breakpointset->label = $themes[$theme_key]->info['name'];
+        $breakpointset->source_type = Breakpoint::BREAKPOINTS_SOURCE_TYPE_THEME;
+        foreach ($theme_breakpoints as $name => $media_query) {
+          $breakpoint = new Breakpoint;
+          $breakpoint->name = $name;
+          $breakpoint->label = ucfirst($name);
+          $breakpoint->media_query = $media_query;
+          $breakpoint->source = $theme_key;
+          $breakpoint->source_type = Breakpoint::BREAKPOINTS_SOURCE_TYPE_THEME;
+          $breakpoint->status = TRUE;
+          $breakpoint->weight = $weight++;
+          $breakpoint->save();
+          $breakpointset->breakpoints[$breakpoint->id()] = $breakpoint;
+        }
+        $breakpointset->save();
+        $uri = $breakpointset->uri();
+        if ($uri) {
+          $uri_options = $uri;
+          unset($uri_options['path']);
+          $uri = $uri['path'];
+        }
+        $message = t('The breakpoints from theme %theme are imported and !setlink.', array(
+          '%theme' => check_plain($themes[$theme_key]->info['name']),
+          '!setlink' => module_exists('breakpoints_ui') && $uri ? l(t('a new breakpoint set is created'), $uri, $uri_options) : t('a new breakpoint set is created'),
+        ));
+        drupal_set_message($message, 'status');
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_themes_disabled();
+ * Remove breakpoints from all disabled themes.
+ */
+function breakpoints_themes_disabled($theme_list) {
+  $breakpointsets = entity_load_multiple('breakpoints_breakpointset', $theme_list);
+  foreach ($breakpointsets as $breakpointset) {
+    $breakpointset->delete();
+    // delete all breakpoints defined by this theme.
+    $names = drupal_container()->get('config.storage')->listAll('breakpoints.breakpoint.' . BREAKPOINTS_SOURCE_TYPE_THEME . '.' . $breakpointset->id() . '.');
+    $entity_info = entity_get_info('breakpoints_breakpoint');
+
+    foreach ($names as &$name) {
+      $name = substr($name, strlen($entity_info['config prefix']) + 1);
+    }
+    $breakpoints = entity_load_multiple('breakpoints_breakpoint', $names);
+
+    foreach ($breakpoints as $breakpoint) {
+      $breakpoint->delete();
+    }
+  }
+}
+
+/**
+ * Load general settings.
+ */
+function breakpoints_settings() {
+  $config = config('breakpoints');
+  if ($config->isNew()) {
+    return FALSE;
+  }
+  return (object)$config->get();
+}
+
+/**
+ * Save general settings.
+ */
+function breakpoints_settings_save($multipliers) {
+  $config = config('breakpoints');
+  if ($config->isNew()) {
+    return FALSE;
+  }
+  $config->set('multipliers', $multipliers);
+  $config->save();
+}
+
+/**
+ * Reload breakpoint sets as they were defined in the theme.
+ * @param string $theme_key
+ * @return BreakpointSet
+ */
+function breakpoints_breakpoints_set_reload_from_theme($theme_key) {
+  // Clear caches so theme.info is fresh.
+  system_rebuild_theme_data();
+  drupal_theme_rebuild();
+
+  $themes = list_themes();
+  if ($themes[$theme_key]->status) {
+    // Check theme_key.breakpoints.yml first
+    $theme_breakpoints = breakpoints_get_theme_breakpoint_list($theme_key);
+    // Fallback to theme_key.info
+    if (empty($theme_breakpoints) && isset($themes[$theme_key]->info['breakpoints'])) {
+      $theme_breakpoints = $themes[$theme_key]->info['breakpoints'];
+    }
+    if (!empty($theme_breakpoints)) {
+      $weight = 0;
+      // Build a set for each theme
+      $breakpointset = new BreakpointSet();
+      $breakpointset->id = $theme_key;
+      $breakpointset->label = $themes[$theme_key]->info['name'];
+      $breakpointset->source_type = Breakpoint::BREAKPOINTS_SOURCE_TYPE_THEME;
+      foreach ($theme_breakpoints as $name => $media_query) {
+        $breakpoint = new Breakpoint;
+        $breakpoint->name = $name;
+        $breakpoint->label = ucfirst($name);
+        $breakpoint->media_query = $media_query;
+        $breakpoint->source = $theme_key;
+        $breakpoint->source_type = Breakpoint::BREAKPOINTS_SOURCE_TYPE_THEME;
+        $breakpoint->status = TRUE;
+        $breakpoint->weight = $weight++;
+        $breakpoint->save();
+        $breakpointset->breakpoints[$breakpoint->get_config_name()] = $breakpoint;
+      }
+    }
+    return $breakpointset;
+  }
+  return FALSE;
+}
+
+/**
+ * Get a list of available breakpoints from a specified theme.
+ *
+ * @param $theme_key
+ *   The name of a theme.
+ * @return
+ *   An array of breakpoints in the form $breakpoint['name'] = 'media query'.
+ */
+function breakpoints_get_theme_breakpoint_list($theme_key) {
+  $themes = list_themes();
+  if (!isset($themes[$theme_key])) {
+    return array();
+  }
+
+  $config = config($theme_key . '.breakpoints');
+  if ($config) {
+    return $config->get();
+  }
+  return array();
+}
+
+/**
+ * Implements hook_entity_info().
+ */
+function breakpoints_entity_info() {
+  // Breakpoint
+  $types['breakpoints_breakpoint'] = array(
+    'label' => 'Breakpoint',
+    'entity class' => 'Drupal\breakpoints\Breakpoint',
+    'controller class' => 'Drupal\Core\Config\Entity\ConfigStorageController',
+    'config prefix' => 'breakpoints.breakpoint',
+    'entity keys' => array(
+      'id' => 'id',
+      'label' => 'label',
+      'uuid' => 'uuid',
+    ),
+  );
+
+  // Breakpoint set
+  $types['breakpoints_breakpointset'] = array(
+    'label' => 'Breakpoint Set',
+    'entity class' => 'Drupal\breakpoints\BreakpointSet',
+    'controller class' => 'Drupal\breakpoints\BreakpointSetController',
+    'config prefix' => 'breakpoints.breakpointset',
+    'entity keys' => array(
+      'id' => 'id',
+      'label' => 'label',
+      'uuid' => 'uuid',
+    ),
+  );
+
+  return $types;
+}
+
+/**
+ * Load one breakpoint set by its identifier.
+ */
+function breakpoints_breakpointset_load($id) {
+  return entity_load('breakpoints_breakpointset', $id);
+}
+
+/**
+ * Load all breakpooint sets.
+ */
+function breakpoints_breakpointset_load_all() {
+  $breakpointsets = entity_load_multiple('breakpoints_breakpointset');
+  return $breakpointsets;
+}
+
+/**
+ * Load one breakpoint by its identifier.
+ */
+function breakpoints_breakpoint_load($id) {
+  return entity_load('breakpoints_breakpoint', $id);
+}
+
+/**
+ * Load all breakpoints.
+ */
+function breakpoints_breakpoint_load_all() {
+  $breakpoints = entity_load_multiple('breakpoints_breakpoint');
+  return $breakpoints;
+}
diff --git a/core/modules/breakpoints/config/breakpoints.yml b/core/modules/breakpoints/config/breakpoints.yml
new file mode 100644
index 0000000..0ba703d
--- /dev/null
+++ b/core/modules/breakpoints/config/breakpoints.yml
@@ -0,0 +1,2 @@
+multipliers: [1x, 1.5x, 2x]
+
diff --git a/core/modules/breakpoints/lib/Drupal/breakpoints/Breakpoint.php b/core/modules/breakpoints/lib/Drupal/breakpoints/Breakpoint.php
new file mode 100644
index 0000000..36b9a88
--- /dev/null
+++ b/core/modules/breakpoints/lib/Drupal/breakpoints/Breakpoint.php
@@ -0,0 +1,273 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\breakpoint\Breakpoint.
+ */
+
+namespace Drupal\breakpoints;
+
+use Drupal\Core\Config\Entity\ConfigEntityBase;
+use Exception;
+
+/**
+ * Defines the Breakpoint entity.
+ */
+class Breakpoint extends ConfigEntityBase {
+
+  /**
+   * The breakpoint ID (config name).
+   *
+   * @var string
+   */
+  public $id;
+
+  /**
+   * The breakpoint UUID.
+   *
+   * @var string
+   */
+  public $uuid;
+
+  /**
+   * The breakpoint name (machine name).
+   *
+   * @var string
+   */
+  public $name;
+
+ /**
+   * The breakpoint label.
+   *
+   * @var string
+   */
+  public $label;
+
+  /**
+   * The breakpoint media query.
+   *
+   * @var string
+   */
+  public $media_query = '';
+
+  /**
+   * The breakpoint source.
+   *
+   * @var string
+   */
+  public $source = 'user';
+
+  /**
+   * The breakpoint source type.
+   *
+   * @var string
+   */
+  public $source_type = BREAKPOINTS_SOURCE_TYPE_CUSTOM;
+
+  /**
+   * The breakpoint status.
+   *
+   * @var string
+   */
+  public $status = TRUE;
+
+  /**
+   * The breakpoint weight.
+   *
+   * @var weight
+   */
+  public $weight = 0;
+
+  /**
+   * The breakpoint multipliers.
+   *
+   * @var multipliers
+   */
+  public $multipliers = array();
+
+  /**
+   * The possible values for source type.
+   *
+   */
+  const BREAKPOINTS_SOURCE_TYPE_THEME = 'theme';
+  const BREAKPOINTS_SOURCE_TYPE_MODULE = 'module';
+  const BREAKPOINTS_SOURCE_TYPE_CUSTOM = 'custom';
+  /**
+   * Overrides Drupal\config\ConfigEntityBase::__construct()
+   */
+  public function __construct(array $values = array(), $entity_type = 'breakpoints_breakpoint') {
+    parent::__construct($values, $entity_type);
+  }
+  public function save() {
+    if (empty($this->id)) {
+      $this->id = $this->build_config_name();
+    }
+    if (empty($this->label)) {
+      $this->label = ucfirst($this->name);
+    }
+    if (!$this->isValid()) {
+      throw new Exception(t('Invalid media query detected.'));
+    }
+    return parent::save();
+  }
+
+  /**
+   * Get config name.
+   */
+  public function get_config_name() {
+    return $this->source_type
+      . '.' . $this->source
+      . '.' . $this->name;
+  }
+
+  /**
+   * Construct config name.
+   */
+  private function build_config_name() {
+    // Check for illegal values in breakpoint source type.
+    if (!in_array($this->source_type, array(BREAKPOINTS_SOURCE_TYPE_CUSTOM, BREAKPOINTS_SOURCE_TYPE_MODULE, BREAKPOINTS_SOURCE_TYPE_THEME))) {
+      throw new Exception(
+          t(
+            'Expected one of \'@custom\', \'@module\' or \'@theme\' for breakpoint source_type property but got \'@sourcetype\'.',
+            array(
+              '@custom' => \BREAKPOINTS_SOURCE_TYPE_CUSTOM,
+              '@module' => \BREAKPOINTS_SOURCE_TYPE_MODULE,
+              '@theme' => \BREAKPOINTS_SOURCE_TYPE_THEME,
+              '@sourcetype' => $this->source_type,
+            )
+          )
+      );
+    }
+    // Check for illegal characters in breakpoint source.
+    if (preg_match('/[^a-z_]+/', $this->source)) {
+      throw new Exception(t('Invalid value \'@source\' for breakpoint source property. Breakpoint source property can only contain lowercase letters and underscores.', array('@source' => $this->source)));
+    }
+    // Check for illegal characters in breakpoint names.
+    if (preg_match('/[^0-9a-z_\-]/', $this->name)) {
+      throw new Exception(t('Invalid value \'@name\' for breakpoint name property. Breakpoint name property can only contain lowercase alphanumeric characters, underscores (_), and hyphens (-).', array('@name' => $this->name)));
+    }
+    return $this->source_type
+      . '.' . $this->source
+      . '.' . $this->name;
+  }
+
+  /**
+   * Shortcut function to enable a breakpoint and save it.
+   * @see breakpoints_breakpoint_action_confirm_submit().
+   */
+  public function enable() {
+    if (!$this->status) {
+      $this->status = 1;
+      $this->save();
+    }
+  }
+
+  /**
+   * Shortcut function to disable a breakpoint and save it.
+   * @see breakpoints_breakpoint_action_confirm_submit().
+   */
+  public function disable() {
+    if ($this->status) {
+      $this->status = 0;
+      $this->save();
+    }
+  }
+
+  /**
+   * Check if the media__query is valid.
+   * @see isValidMediaQuery().
+   */
+  public function isValid() {
+    return $this::isValidMediaQuery($this->media_query);
+  }
+
+  /**
+   * Check if a media_query is valid.
+   * @see http://www.w3.org/TR/css3-mediaqueries/.
+   * @see http://www.w3.org/Style/CSS/Test/MediaQueries/20120229/reports/implement-report.html.
+   */
+  static function isValidMediaQuery($media_query) {
+    $media_features = array(
+      'width' => 'length', 'min-width' => 'length', 'max-width' => 'length',
+      'height' => 'length', 'min-height' => 'length', 'max-height' => 'length',
+      'device-width' => 'length', 'min-device-width' => 'length', 'max-device-width' => 'length',
+      'device-height' => 'length', 'min-device-height' => 'length', 'max-device-height' => 'length',
+      'orientation' => array('portrait', 'landscape'),
+      'aspect-ratio' => 'ratio', 'min-aspect-ratio' => 'ratio', 'max-aspect-ratio' => 'ratio',
+      'device-aspect-ratio' => 'ratio', 'min-device-aspect-ratio' => 'ratio', 'max-device-aspect-ratio' => 'ratio',
+      'color' => 'integer', 'min-color' => 'integer', 'max-color' => 'integer',
+      'color-index' => 'integer', 'min-color-index' => 'integer', 'max-color-index' => 'integer',
+      'monochrome' => 'integer', 'min-monochrome' => 'integer', 'max-monochrome' => 'integer',
+      'resolution' => 'resolution', 'min-resolution' => 'resolution', 'max-resolution' => 'resolution',
+      'scan' => array('progressive', 'interlace'),
+      'grid' => 'integer',
+    );
+    if ($media_query) {
+      // @todo: strip comments, new lines, ....
+      // Check media_query_list: S* [media_query [ ',' S* media_query ]* ]?
+      $parts = explode(',', trim($media_query));
+      foreach ($parts as $part) {
+        // Split on ' and '
+        $query_parts = explode(' and ', trim($part));
+        $media_type_found = FALSE;
+        foreach ($query_parts as $query_part) {
+          $matches = array();
+          // Check expression: '(' S* media_feature S* [ ':' S* expr ]? ')' S*
+          if (preg_match('/^\(([\w\-]+)(:\s?([\w\-]+))?\)/', trim($query_part), $matches)) {
+            // Single expression.
+            if (isset($matches[1]) && !isset($matches[2])) {
+              if (!array_key_exists($matches[1], $media_features)) {
+                return FALSE;
+              }
+            }
+            // Full expression.
+            elseif (isset($matches[3]) && !isset($matches[4])) {
+              $value = trim($matches[3]);
+              if (!array_key_exists($matches[1], $media_features)) {
+                return FALSE;
+              }
+              if (is_array($media_features[$matches[1]])) {
+                // Check if value is allowed.
+                if (!array_key_exists($value, $media_features[$matches[1]])) {
+                  return FALSE;
+                }
+              }
+              else {
+                switch ($media_features[$matches[1]]) {
+                  case 'length':
+                    $length_matches = array();
+                    if (preg_match('/^(\-)?(\d+)?((?:|em|ex|px|cm|mm|in|pt|pc|deg|rad|grad|ms|s|hz|khz|dpi|dpcm))$/i', trim($value), $length_matches)) {
+                      // Only -0 is allowed.
+                      if ($length_matches[1] === '-' && $length_matches[2] !== '0') {
+                        return FALSE;
+                      }
+                      // If there's a unit, a number is needed as well.
+                      if ($length_matches[2] === '' && $length_matches[3] !== '') {
+                        return FALSE;
+                      }
+                    }
+                    else {
+                      return FALSE;
+                    }
+                    break;
+                }
+              }
+            }
+          }
+          // Check [ONLY | NOT]? S* media_type
+          elseif (preg_match('/((?:only|not)?\s?)([\w\-]+)$/i', trim($query_part), $matches)) {
+            if ($media_type_found) {
+              throw new Exception(t('Only when media type allowed.'));
+            }
+            $media_type_found = TRUE;
+          }
+          else {
+            throw new Exception(t('Invalid value \'@query_part\' for breakpoint media query property.', array('@query_part' => $query_part)));
+          }
+        }
+      }
+      return TRUE;
+    }
+    return FALSE;
+  }
+}
diff --git a/core/modules/breakpoints/lib/Drupal/breakpoints/BreakpointSet.php b/core/modules/breakpoints/lib/Drupal/breakpoints/BreakpointSet.php
new file mode 100644
index 0000000..cc7bab6
--- /dev/null
+++ b/core/modules/breakpoints/lib/Drupal/breakpoints/BreakpointSet.php
@@ -0,0 +1,115 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\breakpoint\BreakpointSet.
+ */
+
+namespace Drupal\breakpoints;
+
+use Drupal\Core\Config\Entity\ConfigEntityBase;
+
+/**
+ * Defines the BreakpointSet entity.
+ */
+class BreakpointSet extends ConfigEntityBase {
+
+  /**
+   * The BreakpointSet ID (machine name).
+   *
+   * @var string
+   */
+  public $id;
+
+  /**
+   * The BreakpointSet UUID.
+   *
+   * @var string
+   */
+  public $uuid;
+
+  /**
+   * The BreakpointSet label.
+   *
+   * @var string
+   */
+  public $label;
+
+  /**
+   * The BreakpointSet breakpoints.
+   *
+   * @var array
+   */
+  public $breakpoints = array();
+
+  /**
+   * The BreakpointSet source type.
+   *
+   * @var string
+   */
+  public $source_type = Breakpoint::BREAKPOINTS_SOURCE_TYPE_CUSTOM;
+
+  /**
+   * The BreakpointSet overridden status.
+   *
+   * @var string
+   */
+  public $overridden = FALSE;
+
+  /**
+   * Overrides Drupal\config\ConfigEntityBase::__construct()
+   */
+  public function __construct(array $values = array(), $entity_type = 'breakpoints_breakpointset') {
+    parent::__construct($values, $entity_type);
+    $this->_load_all_breakpoints();
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity::save().
+   */
+  public function save() {
+    // Only save the keys, but return the full objects.
+    $this->breakpoints = array_keys($this->breakpoints);
+    parent::save();
+    $this->_load_all_breakpoints();
+  }
+
+  /**
+   * Override and save a breakpoint set.
+   */
+  public function override() {
+    return entity_get_controller($this->entityType)->override($this);
+  }
+
+  /**
+   * Revert a breakpoint set after it has been overridden.
+   */
+  public function revert() {
+    return entity_get_controller($this->entityType)->revert($this);
+  }
+
+  /**
+   * Implements EntityInterface::createDuplicate().
+   */
+  public function createDuplicate() {
+    $duplicate = new BreakpointSet();
+    $duplicate->id = '';
+    $duplicate->label = t('Clone of') . ' ' . $this->label();
+    $duplicate->breakpoints = $this->breakpoints;
+    return $duplicate;
+  }
+
+  /**
+   * Load all breakpoints, remove non-existing ones.
+   */
+  private function _load_all_breakpoints() {
+    $breakpoints = $this->breakpoints;
+    $this->breakpoints = array();
+    foreach($breakpoints as $breakpoint_id) {
+      $breakpoint = breakpoints_breakpoint_load($breakpoint_id);
+      if ($breakpoint) {
+        $this->breakpoints[$breakpoint_id] = $breakpoint;
+      }
+    }
+  }
+}
diff --git a/core/modules/breakpoints/lib/Drupal/breakpoints/BreakpointSetController.php b/core/modules/breakpoints/lib/Drupal/breakpoints/BreakpointSetController.php
new file mode 100644
index 0000000..861f459
--- /dev/null
+++ b/core/modules/breakpoints/lib/Drupal/breakpoints/BreakpointSetController.php
@@ -0,0 +1,58 @@
+<?php
+/**
+ * @file
+ * Definition of Drupal\breakpoint\BreakpointSetController.
+ */
+namespace Drupal\breakpoints;
+
+use Drupal\Core\Config\Entity\ConfigStorageController;
+use Drupal\breakpoints\BreakpointSet;
+use Drupal\breakpoints\Breakpoint;
+
+/**
+ * Defines the BreakpointSet entity's controller.
+ */
+class BreakpointSetController extends ConfigStorageController{
+
+  /**
+   * Override and save a breakpoint set.
+   */
+  public function override(BreakpointSet $breakpointset) {
+    if (!$breakpointset->source_type == Breakpoint::BREAKPOINTS_SOURCE_TYPE_THEME) {
+      return FALSE;
+    }
+    foreach ($breakpointset->breakpoints as $key => $breakpoint) {
+      if ($breakpoint->source_type == Breakpoint::BREAKPOINTS_SOURCE_TYPE_THEME && $breakpoint->source == $breakpointset->id()) {
+        $new_breakpoint = $breakpoint->createDuplicate();
+        $new_breakpoint->id = '';
+        $new_breakpoint->source_type = Breakpoint::BREAKPOINTS_SOURCE_TYPE_CUSTOM;
+        $new_breakpoint->save();
+
+        // Remove old one, add new one.
+        unset($breakpointset->breakpoints[$key]);
+        $breakpointset->breakpoints[$new_breakpoint->id] = $new_breakpoint;
+      }
+    }
+    $breakpointset->overridden = TRUE;
+    $breakpointset->save();
+    return $breakpointset;
+  }
+
+  /**
+   * Revert a breakpoint set after it has been overridden.
+   */
+  public function revert(BreakpointSet $breakpointset) {
+    if (!$breakpointset->overridden || !$breakpointset->source_type == Breakpoint::BREAKPOINTS_SOURCE_TYPE_THEME) {
+      return FALSE;
+    }
+
+    // reload all breakpoints from theme.info.
+    $reloaded_set = breakpoints_breakpoints_set_reload_from_theme($breakpointset->id());
+    if ($reloaded_set) {
+      $breakpointset->breakpoints = $reloaded_set->breakpoints;
+      $breakpointset->overridden = FALSE;
+      $breakpointset->save();
+    }
+    return $breakpointset;
+  }
+}
diff --git a/core/modules/breakpoints/lib/Drupal/breakpoints/Tests/BreakpointSetCrudTest.php b/core/modules/breakpoints/lib/Drupal/breakpoints/Tests/BreakpointSetCrudTest.php
new file mode 100644
index 0000000..9702e4d
--- /dev/null
+++ b/core/modules/breakpoints/lib/Drupal/breakpoints/Tests/BreakpointSetCrudTest.php
@@ -0,0 +1,71 @@
+<?php
+/**
+ * @file
+ * Definition of Drupal\breakpoints\Tests\BreakpointSetCrudTest.
+ */
+namespace Drupal\breakpoints\Tests;
+
+use Drupal\breakpoints\Tests\BreakpointSetTestBase;
+use Drupal\breakpoints\BreakpointSet;
+use Drupal\breakpoints\Breakpoint;
+
+/**
+ * Tests for breakpoint set CRUD operations.
+ */
+class BreakpointSetCrudTest extends BreakpointSetTestBase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Breakpoint Set CRUD operations',
+      'description' => 'Test creation, loading, updating, deleting of breakpoint sets.',
+      'group' => 'Breakpoints',
+    );
+  }
+
+  /**
+   * Test CRUD operations for breakpoint sets.
+   */
+  function testBreakpointSetCrud() {
+    // Add breakpoints.
+    $breakpoints = array();
+    for ($i = 0; $i <= 3; $i++) {
+      $width = ($i + 1) * 200;
+      $values = array(
+        'name' => drupal_strtolower($this->randomName()),
+        'weight' => $i,
+        'media_query' => "(min-width: {$width}px)",
+      );
+      $breakpoint = new Breakpoint($values);
+      $breakpoint->save();
+      $breakpoints[$breakpoint->id()] = $breakpoint;
+    }
+    // Add a breakpoint set with minimum data only.
+    $label = $this->randomName();
+    $values = array(
+      'label' => $label,
+      'id' => drupal_strtolower($label),
+    );
+
+    $set = new BreakpointSet($values);
+    $set->save();
+    $this->verifyBreakpointSet($set);
+
+    // Update the breakpoint set.
+    $set->breakpoints = array_keys($breakpoints);
+    $set->save();
+    $this->verifyBreakpointSet($set);
+
+    // Duplicate the breakpoint set.
+    $new_set = new BreakpointSet();
+    $new_set->label = t('Clone of') . ' ' . $set->label();
+    $new_set->id = '';
+    $new_set->source_type = Breakpoint::BREAKPOINTS_SOURCE_TYPE_CUSTOM;
+    $new_set->breakpoints = $set->breakpoints;
+    $duplicated_set = $set->createDuplicate();
+    $this->verifyBreakpointSet($duplicated_set, $new_set);
+
+    // Delete the breakpoint set.
+    $set->delete();
+    $this->assertFalse(breakpoints_breakpointset_load($set->id), t('breakpoints_breakpointset_load: Loading a deleted breakpoint set returns false.'), t('Breakpoints API'));
+  }
+}
diff --git a/core/modules/breakpoints/lib/Drupal/breakpoints/Tests/BreakpointSetTestBase.php b/core/modules/breakpoints/lib/Drupal/breakpoints/Tests/BreakpointSetTestBase.php
new file mode 100644
index 0000000..ebabe56
--- /dev/null
+++ b/core/modules/breakpoints/lib/Drupal/breakpoints/Tests/BreakpointSetTestBase.php
@@ -0,0 +1,47 @@
+<?php
+/**
+ * @file
+ * Definition of Drupal\breakpoints\Tests\BreakpointSetTestBase.
+ */
+
+namespace Drupal\breakpoints\Tests;
+
+use Drupal\simpletest\WebTestBase;
+use Drupal\breakpoints\BreakpointSet;
+/**
+ * Base class for Breakpoint Set tests.
+ */
+abstract class BreakpointSetTestBase extends WebTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('breakpoints');
+
+  function  setUp() {
+    parent::setUp();
+  }
+
+  /**
+   * Verify that a breakpoint is properly stored.
+   */
+  function verifyBreakpointSet(BreakpointSet $set, BreakpointSet $compare_set = NULL) {
+    $t_args = array('%set' => $set->label());
+    $properties = array('label', 'id', 'breakpoints', 'overridden', 'source_type');
+    $assert_set = t('Breakpoints API');
+
+    // Verify breakpoints_breakpoint_set_load().
+    $compare_set = is_null($compare_set) ? breakpoints_breakpointset_load($set->id) : $compare_set;
+
+    foreach ($properties as $property) {
+      if (is_array($compare_set->{$property})) {
+        $this->assertEqual(array_keys($compare_set->{$property}), array_keys($set->{$property}), t('breakpoints_breakpoint_set_load: Proper ' . $property . ' for breakpoint set %set.', $t_args), $assert_set);
+      }
+      else {
+        $this->assertEqual($compare_set->{$property}, $set->{$property}, t('breakpoints_breakpoint_set_load: Proper ' . $property . ' for breakpoint set %set.', $t_args), $assert_set);
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/core/modules/breakpoints/lib/Drupal/breakpoints/Tests/BreakpointsApiTest.php b/core/modules/breakpoints/lib/Drupal/breakpoints/Tests/BreakpointsApiTest.php
new file mode 100644
index 0000000..38edbe3
--- /dev/null
+++ b/core/modules/breakpoints/lib/Drupal/breakpoints/Tests/BreakpointsApiTest.php
@@ -0,0 +1,86 @@
+<?php
+/**
+ * @file
+ * Definition of Drupal\breakpoints\Tests\BreakpointsApiTest.
+ */
+namespace Drupal\breakpoints\Tests;
+
+use Drupal\breakpoints\Tests\BreakpointsTestBase;
+use Drupal\breakpoints\Breakpoint;
+use Exception;
+
+/**
+ * Tests for general breakpoints api functions.
+ */
+class BreakpointsApiTest extends BreakpointsTestBase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Breakpoints general API functions',
+      'description' => 'Test general API functions of the breakpoints module.',
+      'group' => 'Breakpoints',
+    );
+  }
+
+  /**
+   * Test breakpoints_breakpoint_config_name
+   */
+  public function testConfigName() {
+    $breakpoint = new Breakpoint(
+      array(
+        'label' => drupal_strtolower($this->randomName()),
+        'source' => 'custom_module',
+        // Try an invalid source_type.
+        'source_type' => 'oops',
+      )
+    );
+
+    try {
+      $breakpoint->save();
+    }
+    catch (Exception $e) {
+      $exception = TRUE;
+    }
+    $this->assertTrue($exception, t('breakpoints_breakpoint_config_name: An exception is thrown when an invalid source_type is entered.'), t('Breakpoints API'));
+    $this->assertEqual((string)$breakpoint->id(), '', t('breakpoints_breakpoint_config_name: No id is set when an invalid source_type is entered.'), t('Breakpoints API'));
+
+    // Try an invalid source.
+    $breakpoint->source_type = BREAKPOINTS_SOURCE_TYPE_CUSTOM;
+    $breakpoint->source = 'custom*_module source';
+    $exception = FALSE;
+    try {
+      $breakpoint->save();
+    }
+    catch (Exception $e) {
+      $exception = TRUE;
+    }
+    $this->assertTrue($exception, t('breakpoints_breakpoint_config_name: An exception is thrown when an invalid source is entered.'), t('Breakpoints API'));
+    $this->assertEqual((string)$breakpoint->id(), '', t('breakpoints_breakpoint_config_name: No id is set when an invalid source_type is entered.'), t('Breakpoints API'));
+
+    // Try an invalid name (make sure there is at least once capital letter).
+    $breakpoint->source = 'custom_module';
+    $breakpoint->name = drupal_ucfirst($this->randomName());
+    $exception = FALSE;
+    try {
+      $breakpoint->save();
+    }
+    catch (Exception $e) {
+      $exception = TRUE;
+    }
+    $this->assertTrue($exception, t('breakpoints_breakpoint_config_name: An exception is thrown when an invalid name is entered.'), t('Breakpoints API'));
+    $this->assertEqual((string)$breakpoint->id(), '', t('breakpoints_breakpoint_config_name: No id is set when an invalid source_type is entered.'), t('Breakpoints API'));
+
+    // Try a valid breakpoint.
+    $breakpoint->name = drupal_strtolower($this->randomName());
+    $breakpoint->media_query = 'all';
+    $exception = FALSE;
+    try {
+      $breakpoint->save();
+    }
+    catch (Exception $e) {
+      $exception = TRUE;
+    }
+    $this->assertFalse($exception, t('breakpoints_breakpoint_config_name: No exception is thrown when a valid breakpoint is passed.'), t('Breakpoints API'));
+    $this->assertEqual($breakpoint->id(), Breakpoint::BREAKPOINTS_SOURCE_TYPE_CUSTOM . '.custom_module.' . $breakpoint->name, t('breakpoints_breakpoint_config_name: A id is set when a valid breakpoint is passed.'), t('Breakpoints API'));
+  }
+}
diff --git a/core/modules/breakpoints/lib/Drupal/breakpoints/Tests/BreakpointsCrudTest.php b/core/modules/breakpoints/lib/Drupal/breakpoints/Tests/BreakpointsCrudTest.php
new file mode 100644
index 0000000..1f9fbd4
--- /dev/null
+++ b/core/modules/breakpoints/lib/Drupal/breakpoints/Tests/BreakpointsCrudTest.php
@@ -0,0 +1,59 @@
+<?php
+/**
+ * @file
+ * Definition of Drupal\breakpoints\Tests\BreakpointsCrudTest.
+ */
+namespace Drupal\breakpoints\Tests;
+
+use Drupal\breakpoints\Tests\BreakpointsTestBase;
+use Drupal\breakpoints\Breakpoint;
+
+/**
+ * Tests for breakpoints CRUD operations.
+ */
+class BreakpointsCrudTest extends BreakpointsTestBase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Breakpoints CRUD operations',
+      'description' => 'Test creation, loading, updating, deleting of breakpoints.',
+      'group' => 'Breakpoints',
+    );
+  }
+
+  /**
+   * Test CRUD operations for breakpoints.
+   */
+  function testBreakpointsCrud() {
+    // Add a breakpoint with minimum data only.
+    $values = array(
+      'label' => drupal_strtolower($this->randomName()),
+      'media_query' => '(min-width: 600px)',
+    );
+
+    $breakpoint = new Breakpoint($values);
+    $breakpoint->save();
+
+    $this->verifyBreakpoint($breakpoint);
+
+    // Test breakpoints_breakpoint_load_all
+    $all_breakpoints = breakpoints_breakpoint_load_all();
+    $config_name = $breakpoint->get_config_name();
+    $this->assertTrue(isset($all_breakpoints[$config_name]), t('breakpoints_breakpoint_load_all: New breakpoint is present when loading all breakpoints.'));
+    $this->verifyBreakpoint($breakpoint, $all_breakpoints[$config_name]);
+
+    // Update the breakpoint.
+    $breakpoint->weight = 1;
+    $breakpoint->multipliers['2x'] = '2x';
+    $breakpoint->save();
+    $this->verifyBreakpoint($breakpoint);
+
+    // Disable the breakpoint.
+    $breakpoint->disable();
+    $this->verifyBreakpoint($breakpoint);
+
+    // Delete the breakpoint.
+    $breakpoint->delete();
+    $this->assertFalse(breakpoints_breakpoint_load($config_name), t('breakpoints_breakpoint_load: Loading a deleted breakpoint returns false.'), t('Breakpoints API'));
+  }
+}
diff --git a/core/modules/breakpoints/lib/Drupal/breakpoints/Tests/BreakpointsMediaqueryTest.php b/core/modules/breakpoints/lib/Drupal/breakpoints/Tests/BreakpointsMediaqueryTest.php
new file mode 100644
index 0000000..0df1b70
--- /dev/null
+++ b/core/modules/breakpoints/lib/Drupal/breakpoints/Tests/BreakpointsMediaqueryTest.php
@@ -0,0 +1,117 @@
+<?php
+/**
+ * @file
+ * Definition of Drupal\breakpoints\Tests\BreakpointsCrudTest.
+ */
+namespace Drupal\breakpoints\Tests;
+
+use Drupal\simpletest\UnitTestBase;
+use Drupal\breakpoints\Breakpoint;
+use Exception;
+
+/**
+ * Tests for media queries in breakpoints.
+ */
+class BreakpointsMediaqueryTest extends UnitTestBase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Breakpoints media query tests',
+      'description' => 'Test validation of media queries.',
+      'group' => 'Breakpoints',
+    );
+  }
+
+  /**
+   * Test valid media queries.
+   */
+  function testValidMediaQueries() {
+    $media_queries = array(
+      // Bartik
+      '(min-width: 0px)',
+      'all and (min-width: 560px) and (max-width:850px)',
+      'all and (min-width: 851px)',
+      // Seven
+      '(min-width: 0em)',
+      'screen and (min-width: 40em)',
+      // Stark
+      '(min-width: 0px)',
+      'all and (min-width: 480px) and (max-width: 959px)',
+      'all and (min-width: 960px)',
+      '(orientation)',
+      'all and (orientation)',
+      'not all and (orientation)',
+      'only all and (orientation)',
+      'screen and (width)',
+      'screen and (width: 0)',
+      'screen and (width: 0px)',
+      'screen and (width: 0em)',
+      'screen and (min-width: -0)',
+      'screen and (max-width: 0)',
+      'screen and (min-width)',
+    );
+
+    foreach($media_queries as $media_query) {
+      try {
+        $this->assertTrue(Breakpoint::isValidMediaQuery($media_query), $media_query . ' is valid.');
+      }
+      catch (Exception $e) {
+        $this->assertTrue(FALSE, $media_query . ' is valid.');
+      }
+    }
+  }
+
+  /**
+   * Test invalid media queries.
+   */
+  function testInvalidMediaQueries() {
+    $media_queries = array(
+      'not (orientation)',
+      'only (orientation)',
+      'all and not all',
+      'screen and (width: 0xx)',
+      'screen and (width: -8xx)',
+      'screen and (width: -xx)',
+      'screen and (width: xx)',
+      'screen and (width: px)',
+      'screen and (width: -8px)',
+      'screen and (width: -0.8px)',
+      'screen and (height: 0xx)',
+      'screen and (height: -8xx)',
+      'screen and (height: -xx)',
+      'screen and (height: xx)',
+      'screen and (height: px)',
+      'screen and (height: -8px)',
+      'screen and (height: -0.8px)',
+      'screen and (device-width: 0xx)',
+      'screen and (device-width: -8xx)',
+      'screen and (device-width: -xx)',
+      'screen and (device-width: xx)',
+      'screen and (device-width: px)',
+      'screen and (device-width: -8px)',
+      'screen and (device-width: -0.8px)',
+      'screen and (device-height: 0xx)',
+      'screen and (device-height: -8xx)',
+      'screen and (device-height: -xx)',
+      'screen and (device-height: xx)',
+      'screen and (device-height: px)',
+      'screen and (device-height: -8px)',
+      'screen and (device-height: -0.8px)',
+      'screen and (min-orientation)',
+      'screen and (max-orientation)',
+      'screen and (min-orientation: landscape)',
+      'screen and (max-orientation: landscape)',
+      'screen and (orientation: bogus)',
+      '(orientation: bogus)',
+    );
+
+    foreach($media_queries as $media_query) {
+      try {
+        $this->assertFalse(Breakpoint::isValidMediaQuery($media_query), $media_query . ' is not valid.');
+      }
+      catch (Exception $e) {
+        $this->assertTrue(TRUE, $media_query . ' is not valid.');
+      }
+    }
+  }
+}
diff --git a/core/modules/breakpoints/lib/Drupal/breakpoints/Tests/BreakpointsTestBase.php b/core/modules/breakpoints/lib/Drupal/breakpoints/Tests/BreakpointsTestBase.php
new file mode 100644
index 0000000..400e31d
--- /dev/null
+++ b/core/modules/breakpoints/lib/Drupal/breakpoints/Tests/BreakpointsTestBase.php
@@ -0,0 +1,42 @@
+<?php
+/**
+ * @file
+ * Definition of Drupal\breakpoints\Tests\BreakpointsTestBase.
+ */
+
+namespace Drupal\breakpoints\Tests;
+
+use Drupal\simpletest\WebTestBase;
+use Drupal\breakpoints\Breakpoint;
+
+/**
+ * Base class for Breakpoint tests.
+ */
+abstract class BreakpointsTestBase extends WebTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('breakpoints');
+
+  function  setUp() {
+    parent::setUp();
+  }
+
+  /**
+   * Verify that a breakpoint is properly stored.
+   */
+  function verifyBreakpoint(Breakpoint $breakpoint, Breakpoint $compare_breakpoint = NULL) {
+    $t_args = array('%breakpoint' => $breakpoint->label());
+    $properties = array('label', 'media_query', 'source', 'source_type', 'status', 'weight', 'multipliers');
+    $assert_group = t('Breakpoints API');
+
+    // Verify breakpoints_breakpoint_load_by_fullkey().
+    $compare_breakpoint = is_null($compare_breakpoint) ? breakpoints_breakpoint_load($breakpoint->get_config_name()) : $compare_breakpoint;
+    foreach ($properties as $property) {
+      $this->assertEqual($compare_breakpoint->{$property}, $breakpoint->{$property}, t('breakpoints_breakpoint_load: Proper ' . $property . ' for breakpoint %breakpoint.', $t_args), $assert_group);
+    }
+  }
+}
\ No newline at end of file
diff --git a/core/modules/breakpoints/lib/Drupal/breakpoints/Tests/BreakpointsThemeTest.php b/core/modules/breakpoints/lib/Drupal/breakpoints/Tests/BreakpointsThemeTest.php
new file mode 100644
index 0000000..e093599
--- /dev/null
+++ b/core/modules/breakpoints/lib/Drupal/breakpoints/Tests/BreakpointsThemeTest.php
@@ -0,0 +1,83 @@
+<?php
+/**
+ * @file
+ * Definition of Drupal\breakpoints\Tests\BreakpointsThemeTest.
+ */
+namespace Drupal\breakpoints\Tests;
+
+use Drupal\breakpoints\Tests\BreakpointSetTestBase;
+use Drupal\breakpoints\BreakpointSet;
+use Drupal\breakpoints\Breakpoint;
+
+/**
+ * Test breakpoints provided by themes.
+ */
+class BreakpointsThemeTest extends BreakpointSetTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('breakpoints_theme_test');
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Breakpoint Theme functionality',
+      'description' => 'Thoroughly test the breakpoints provided by a theme.',
+      'group' => 'Breakpoints',
+    );
+  }
+
+  public function  setUp() {
+    parent::setUp();
+    theme_enable(array('breakpoints_test_theme'));
+  }
+
+  /**
+   * Test the breakpoints provided by a theme.
+   */
+  public function testThemeBreakpoints() {
+    // Verify the breakpoint group for breakpoints_test_theme was created.
+    $breakpoint_set_obj = new BreakpointSet();
+    $breakpoint_set_obj->label = 'Breakpoints test theme';
+    $breakpoint_set_obj->id = 'breakpoints_test_theme';
+    $breakpoint_set_obj->source_type = Breakpoint::BREAKPOINTS_SOURCE_TYPE_THEME;
+    $breakpoint_set_obj->breakpoints = array(
+      'theme.breakpoints_test_theme.mobile' => array(),
+      'theme.breakpoints_test_theme.narrow' => array(),
+      'theme.breakpoints_test_theme.wide' => array(),
+      'theme.breakpoints_test_theme.tv' => array(),
+    );
+    $breakpoint_set_obj->overridden = 0;
+
+    // Verify we can load this breakpoint defined by the theme.
+    $this->verifyBreakpointSet($breakpoint_set_obj);
+
+    // Override the breakpoints.
+    $overridden_set = clone $breakpoint_set_obj;
+    $breakpoint_set = breakpoints_breakpointset_load('breakpoints_test_theme');
+    $breakpoint_set = $breakpoint_set->override();
+
+    // Verify the group is overridden.
+    $overridden_set->breakpoints = array(
+      'custom.breakpoints_test_theme.mobile' => array(),
+      'custom.breakpoints_test_theme.narrow' => array(),
+      'custom.breakpoints_test_theme.wide' => array(),
+      'custom.breakpoints_test_theme.tv' => array(),
+    );
+    $overridden_set->overridden = 1;
+    $this->verifyBreakpointSet($overridden_set);
+
+    // Revert the breakpoint set.
+    $breakpoint_set = breakpoints_breakpointset_load('breakpoints_test_theme');
+    $breakpoint_set = $breakpoint_set->revert();
+
+    // Verify the breakpointset has its original values again when loaded.
+    $this->verifyBreakpointSet($breakpoint_set_obj);
+
+    // Disable the test theme and verify the breakpoint group is deleted.
+    theme_disable(array('breakpoints_test_theme'));
+    $this->assertFalse(breakpoints_breakpointset_load('breakpoints_test_theme'), t('breakpoints_breakpoint_group_load: Loading a deleted breakpoint group returns false.'), t('Breakpoints API'));
+  }
+}
diff --git a/core/modules/breakpoints/tests/breakpoints_theme_test.info b/core/modules/breakpoints/tests/breakpoints_theme_test.info
new file mode 100644
index 0000000..4aa97c7
--- /dev/null
+++ b/core/modules/breakpoints/tests/breakpoints_theme_test.info
@@ -0,0 +1,5 @@
+name = Breakpoints Theme Test
+description = Test breakpoints provided by themes
+package = Other
+core = 8.x
+hidden = TRUE
diff --git a/core/modules/breakpoints/tests/breakpoints_theme_test.module b/core/modules/breakpoints/tests/breakpoints_theme_test.module
new file mode 100644
index 0000000..34088da
--- /dev/null
+++ b/core/modules/breakpoints/tests/breakpoints_theme_test.module
@@ -0,0 +1,13 @@
+<?php
+/**
+ * @file
+ * Test breakpoint functionality for breakpoints provided by themes
+ */
+
+/**
+ * Implements hook_system_theme_info().
+ */
+function breakpoints_theme_test_system_theme_info() {
+  $themes['breakpoints_test_theme'] = drupal_get_path('module', 'breakpoints_theme_test') . '/themes/breakpoints_test_theme/breakpoints_test_theme.info';
+  return $themes;
+}
diff --git a/core/modules/breakpoints/tests/themes/breakpoints_test_theme/breakpoints_test_theme.info b/core/modules/breakpoints/tests/themes/breakpoints_test_theme/breakpoints_test_theme.info
new file mode 100644
index 0000000..8d2d360
--- /dev/null
+++ b/core/modules/breakpoints/tests/themes/breakpoints_test_theme/breakpoints_test_theme.info
@@ -0,0 +1,10 @@
+name = Breakpoints test theme
+description = Test theme for breakpoints.
+core = 8.x
+base theme = bartik
+hidden = TRUE
+
+breakpoints[mobile] = (min-width: 0px)
+breakpoints[narrow] = (min-width: 560px)
+breakpoints[wide] = (min-width: 851px)
+breakpoints[tv] = only screen and (min-width: 3456px)
