diff --git a/core/includes/form.inc b/core/includes/form.inc
index 2e8e9e1..10e7cfc 100644
--- a/core/includes/form.inc
+++ b/core/includes/form.inc
@@ -2248,13 +2248,13 @@ function form_pre_render_button($element) {
 
   $element['#attributes']['class'][] = 'button';
   if (!empty($element['#button_type'])) {
-    $element['#attributes']['class'][] = 'button-' . $element['#button_type'];
+    $element['#attributes']['class'][] = 'button--' . $element['#button_type'];
   }
   // @todo Various JavaScript depends on this button class.
   $element['#attributes']['class'][] = 'form-submit';
 
   if (!empty($element['#attributes']['disabled'])) {
-    $element['#attributes']['class'][] = 'form-button-disabled';
+    $element['#attributes']['class'][] = 'is-disabled';
   }
 
   return $element;
@@ -2285,13 +2285,13 @@ function form_pre_render_image_button($element) {
 
   $element['#attributes']['class'][] = 'image-button';
   if (!empty($element['#button_type'])) {
-    $element['#attributes']['class'][] = 'image-button-' . $element['#button_type'];
+    $element['#attributes']['class'][] = 'image-button--' . $element['#button_type'];
   }
   // @todo Various JavaScript depends on this button class.
   $element['#attributes']['class'][] = 'form-submit';
 
   if (!empty($element['#attributes']['disabled'])) {
-    $element['#attributes']['class'][] = 'image-button-disabled';
+    $element['#attributes']['class'][] = 'is-disabled';
   }
 
   return $element;
diff --git a/core/modules/system/lib/Drupal/system/Tests/Form/ElementTest.php b/core/modules/system/lib/Drupal/system/Tests/Form/ElementTest.php
index c491d0e..18c8770 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Form/ElementTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Form/ElementTest.php
@@ -99,12 +99,12 @@ function testOptions() {
   function testButtonClasses() {
     $this->drupalGet('form-test/button-class');
     // Just contains(@class, "button") won't do because then
-    // "button-foo" would contain "button". Instead, check
+    // "button--foo" would contain "button". Instead, check
     // " button ". Make sure it matches in the beginning and the end too
     // by adding a space before and after.
     $this->assertEqual(2, count($this->xpath('//*[contains(concat(" ", @class, " "), " button ")]')));
-    $this->assertEqual(1, count($this->xpath('//*[contains(concat(" ", @class, " "), " button-foo ")]')));
-    $this->assertEqual(1, count($this->xpath('//*[contains(concat(" ", @class, " "), " button-danger ")]')));
+    $this->assertEqual(1, count($this->xpath('//*[contains(concat(" ", @class, " "), " button--foo ")]')));
+    $this->assertEqual(1, count($this->xpath('//*[contains(concat(" ", @class, " "), " button--danger ")]')));
   }
 
   /**
diff --git a/core/modules/system/lib/Drupal/system/Tests/Form/FormTest.php b/core/modules/system/lib/Drupal/system/Tests/Form/FormTest.php
index 4aa8eb8..f29c662 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Form/FormTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Form/FormTest.php
@@ -582,11 +582,11 @@ function testDisabledMarkup() {
       // Setup XPath and CSS class depending on #type.
       if (in_array($item['#type'], array('button', 'submit'))) {
         $path = "//!type[contains(@class, :div-class) and @value=:value]";
-        $class = 'form-button-disabled';
+        $class = 'is-disabled';
       }
       elseif (in_array($item['#type'], array('image_button'))) {
         $path = "//!type[contains(@class, :div-class) and @value=:value]";
-        $class = 'image-button-disabled';
+        $class = 'is-disabled';
       }
       else {
         // starts-with() required for checkboxes.
diff --git a/core/modules/system/lib/Drupal/system/Tests/Form/SystemConfigFormTest.php b/core/modules/system/lib/Drupal/system/Tests/Form/SystemConfigFormTest.php
index a672360..211d1be 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Form/SystemConfigFormTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Form/SystemConfigFormTest.php
@@ -35,7 +35,7 @@ public static function getInfo() {
    */
   function testSystemConfigForm() {
     $this->drupalGet('form-test/system-config-form');
-    $element = $this->xpath('//div[@id = :id]/input[contains(@class, :class)]', array(':id' => 'edit-actions', ':class' => 'button-primary'));
+    $element = $this->xpath('//div[@id = :id]/input[contains(@class, :class)]', array(':id' => 'edit-actions', ':class' => 'button--primary'));
     $this->assertTrue($element, 'The primary action submit button was found.');
     $this->drupalPostForm(NULL, array(), t('Save configuration'));
     $this->assertText(t('The configuration options have been saved.'));
diff --git a/core/themes/seven/css/components/buttons.css b/core/themes/seven/css/components/buttons.css
new file mode 100644
index 0000000..a44ad36
--- /dev/null
+++ b/core/themes/seven/css/components/buttons.css
@@ -0,0 +1,47 @@
+/**
+ * @file
+ * Structural styles for Seven’s UI buttons
+ *
+ * Apply these classes to any element (<link>, <button>, <input>, etc.) that
+ * should appear as a button.
+ */
+
+/**
+ * Buttons.
+ *
+ * 1. Enable z-index on buttons.
+ * 2. Normalize 'line-height'; can’t be changed from 'normal' in Firefox 4+.
+ * 3. Allows full range of styling in Webkit and Gecko.
+ *
+ * @todo Consider moving box-sizing into base.css under a universal selector.
+ * See https://drupal.org/node/2124251
+ *
+ */
+.button {
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+  box-sizing: border-box;
+  display: inline-block;
+  position: relative;  /* 1 */
+  text-align: center;
+  line-height: normal;  /* 2 */
+  cursor: pointer;
+  -webkit-appearance: none;  /* 3 */
+     -moz-appearance: none;  /* " */
+}
+
+/* Prevent focus ring being covered by next siblings. */
+.button:focus {
+  z-index: 10;
+}
+
+/* Link actions. */
+.link {
+  display: inline;
+  cursor: pointer;
+  padding: 0;
+  border: 0;
+  background: none;
+  -webkit-appearance: none;
+     -moz-appearance: none;
+}
diff --git a/core/themes/seven/css/components/buttons.theme.css b/core/themes/seven/css/components/buttons.theme.css
new file mode 100644
index 0000000..4ff9fa5
--- /dev/null
+++ b/core/themes/seven/css/components/buttons.theme.css
@@ -0,0 +1,189 @@
+/**
+ * @file
+ * Stylistic treatment for Seven’s UI buttons
+ */
+
+/* Buttons. */
+
+/**
+ * 1. Use px units to ensure button text is centered vertically.
+ * 2. Use rems to avoid the font size cascade of ems, with a px fallback for
+ * older browsers.
+ * 3. Prevent fat text in WebKit.
+ */
+.button {
+  padding: 4px 1.5em;  /* 1 */
+  border: 1px solid #a6a6a6;
+  border-radius: 20em;
+  background-color: #f2f1eb;
+  background-image: -webkit-linear-gradient(top, #f6f6f3, #e7e7df);
+  background-image:    -moz-linear-gradient(top, #f6f6f3, #e7e7df);
+  background-image:      -o-linear-gradient(top, #f6f6f3, #e7e7df);
+  background-image:   linear-gradient(to bottom, #f6f6f3, #e7e7df);
+  color: #333333;
+  text-decoration: none;
+  text-shadow: 0 1px hsla(0, 0%, 100%, 0.6);
+  font-weight: 600;
+  font-size: 14px;
+  font-size: 0.875rem;  /* 2 */
+  -webkit-transition: all 0.1s;
+     -moz-transition: all 0.1s;
+       -o-transition: all 0.1s;
+          transition: all 0.1s;
+  -webkit-font-smoothing: antialiased;  /* 3 */
+}
+.button:focus,
+.button:hover {
+  background-color: #f9f8f6;
+  background-image: -webkit-linear-gradient(top, #fcfcfa, #e9e9dd);
+  background-image:    -moz-linear-gradient(top, #fcfcfa, #e9e9dd);
+  background-image:      -o-linear-gradient(top, #fcfcfa, #e9e9dd);
+  background-image:   linear-gradient(to bottom, #fcfcfa, #e9e9dd);
+  color: #1a1a1a;
+  text-decoration: none;
+  outline: none;
+}
+.button:hover {
+  box-shadow: 0 1px 2px hsla(0, 0%, 0%, 0.125);
+}
+.button:active {
+  background-color: #dfdfd9;
+  background-image: -webkit-linear-gradient(top, #f6f6f3, #e7e7df);
+  background-image:    -moz-linear-gradient(top, #f6f6f3, #e7e7df);
+  background-image:      -o-linear-gradient(top, #f6f6f3, #e7e7df);
+  background-image:   linear-gradient(to bottom, #f6f6f3, #e7e7df);
+  box-shadow: inset 0 1px 3px hsla(0, 0%, 0%, 0.2);
+  -webkit-transition: none;
+     -moz-transition: none;
+       -o-transition: none;
+          transition: none;
+}
+
+.button--primary {
+  border-color: #1e5c90;
+  background-image: -webkit-linear-gradient(top, #007bc6, #0071b8);
+  background-image:    -moz-linear-gradient(top, #007bc6, #0071b8);
+  background-image:      -o-linear-gradient(top, #007bc6, #0071b8);
+  background-image:   linear-gradient(to bottom, #007bc6, #0071b8);
+  color: #fff;
+  text-shadow: 0 1px hsla(0, 0%, 0%, 0.5);
+  font-weight: 700;
+  -webkit-font-smoothing: antialiased;
+}
+.button--primary:focus,
+.button--primary:hover {
+  background-color: #2369a6;
+  background-image: -webkit-linear-gradient(top, #0c97ed, #1f86c7);
+  background-image:    -moz-linear-gradient(top, #0c97ed, #1f86c7);
+  background-image:      -o-linear-gradient(top, #0c97ed, #1f86c7);
+  background-image:   linear-gradient(to bottom, #0c97ed, #1f86c7);
+  border-color: #1e5c90;
+  color: #fff;
+}
+.button--primary:focus {
+  border-color: #0087db;
+}
+.button--primary:hover {
+  box-shadow: 0 1px 2px hsla(203, 10%, 10%, 0.25);
+}
+.button--primary:active {
+  background-image: -webkit-linear-gradient(top, #08639b, #0071b8);
+  background-image:    -moz-linear-gradient(top, #08639b, #0071b8);
+  background-image:      -o-linear-gradient(top, #08639b, #0071b8);
+  background-image:   linear-gradient(to bottom, #08639b, #0071b8);
+  border-color: #144b78;
+  box-shadow: inset 0 1px 3px hsla(0, 0%, 0%, 0.2);
+}
+
+/**
+ * Overrides styling from system.theme.
+ */
+.button-action:before {
+  margin-left: -0.2em;
+  padding-right: 0.2em;
+  font-size: 14px;
+  font-size: 0.875rem;
+  line-height: 16px;
+  -webkit-font-smoothing: auto;
+}
+
+/**
+ * 1. Use px units to ensure button text is centered vertically.
+ */
+.no-touch .button--small {
+  font-size: 13px;
+  font-size: 0.813rem;
+  padding: 2px 1em;  /* 1 */
+}
+
+.button:disabled,
+.button:disabled:active,
+.button.is-disabled,
+.button.is-disabled:active {
+  border-color: #d4d4d4;
+  background: #ededed;
+  box-shadow: none;
+  color: #5c5c5c;
+  font-weight: normal;
+  cursor: default;
+  text-shadow: 0 1px hsla(0, 0%, 100%, 0.6);
+}
+
+/* Link actions. */
+
+/**
+ * Style a clickable/tappable element as a link. Duplicates the base style for
+ * the <a> tag, plus a reset for padding, borders and background.
+ */
+.link {
+  color: #0074bd;
+  text-decoration: none;
+}
+.link:focus,
+.link:hover {
+  color: #008ee6;
+  text-decoration: underline;
+}
+
+/**
+ * We've temporarily added the danger button here, bit of a harsh reset but we
+ * need it.
+ * @todo replace with link--danger.
+ * See https://drupal.org/node/2123731
+ */
+.button--danger {
+  display: inline;
+  cursor: pointer;
+  padding: 0;
+  border: 0;
+  border-radius: 0;
+  box-shadow: none;
+  background: none;
+  -webkit-appearance: none;
+     -moz-appearance: none;
+  color: #c72100;
+  font-weight: 400;
+  text-decoration: underline;
+}
+.button--danger:focus,
+.button--danger:hover,
+.button--danger:active {
+  color: #ff2a00;
+  text-decoration: underline;
+  text-shadow: none;
+  padding: 0;
+  border: 0;
+  box-shadow: none;
+  background: none;
+}
+.button--danger:disabled,
+.button--danger.is-disabled {
+ color: #737373;
+ cursor: default;
+ text-decoration: none;
+ -webkit-font-smoothing: antialiased;
+  padding: 0;
+  border: 0;
+  box-shadow: none;
+  background: none;
+}
diff --git a/core/themes/seven/seven.info.yml b/core/themes/seven/seven.info.yml
index c7f80bb..62beff8 100644
--- a/core/themes/seven/seven.info.yml
+++ b/core/themes/seven/seven.info.yml
@@ -7,6 +7,8 @@ core: 8.x
 stylesheets:
   screen:
     - style.css
+    - css/components/buttons.css
+    - css/components/buttons.theme.css
 stylesheets-override:
   - vertical-tabs.css
   - jquery.ui.theme.css
diff --git a/core/themes/seven/seven.theme b/core/themes/seven/seven.theme
index 67ebb0f..44fdabc 100644
--- a/core/themes/seven/seven.theme
+++ b/core/themes/seven/seven.theme
@@ -137,7 +137,7 @@ function seven_admin_block_content($variables) {
 function seven_tablesort_indicator($variables) {
   $theme_path = drupal_get_path('theme', 'seven');
 
-  if($variables['style'] == 'asc') {
+  if ($variables['style'] == 'asc') {
     $image_uri = $theme_path . '/images/arrow-asc.png';
     $text = t('Sort ascending');
   }
@@ -158,6 +158,59 @@ function seven_tablesort_indicator($variables) {
 }
 
 /**
+ * Overrides theme_menu_local_action().
+ */
+function seven_menu_local_action($variables) {
+  $link = $variables['element']['#link'];
+  $link += array(
+    'href' => '',
+    'localized_options' => array(),
+    'route_parameters' => array(),
+  );
+  $link['localized_options']['attributes']['class'][] = 'button';
+  $link['localized_options']['attributes']['class'][] = 'button--primary';
+  $link['localized_options']['attributes']['class'][] = 'button--small';
+
+  // @todo Replace with a generalized solution for icons.
+  // See http://drupal.org/node/1849712
+  $link['localized_options']['attributes']['class'][] = 'button-action';
+
+  // We require Modernizr's touch test for button styling.
+  $libraries = array(
+    '#attached' => array(
+      'library' => array(
+        array('system', 'modernizr'),
+      ),
+    ),
+  );
+  drupal_render($libraries);
+
+  $output = '<li>';
+  // @todo Remove this check and the call to l() when all pages are converted to
+  //   routes.
+  // @todo Figure out how to support local actions without a href properly.
+  if ($link['href'] === '' && !empty($link['route_name'])) {
+    $output .= \Drupal::l($link['title'], $link['route_name'], $link['route_parameters'], $link['localized_options']);
+  }
+  else {
+    $output .= \Drupal::l($link['title'], $link['href'], $link['localized_options']);
+  }
+  $output .= "</li>";
+
+  return $output;
+}
+
+/**
+ * Implements hook_element_info_alter().
+ */
+function seven_element_info_alter(&$type) {
+  // We require Modernizr for button styling.
+  if (isset($type['button'])) {
+    $type['button']['#attached']['library'][] = array('system', 'modernizr');
+  }
+}
+
+/**
  * Implements hook_preprocess_install_page().
  */
 function seven_preprocess_install_page(&$variables) {
diff --git a/core/themes/seven/style.css b/core/themes/seven/style.css
index 1bcb085..e1f8f5c 100644
--- a/core/themes/seven/style.css
+++ b/core/themes/seven/style.css
@@ -772,68 +772,6 @@ body div.form-type-checkbox div.description {
   margin-left: 0;
   margin-right: 1.5em;
 }
-.button {
-  cursor: pointer;
-  padding: 4px 17px;
-  color: #5a5a5a;
-  text-align: center;
-  font-weight: normal;
-  font-size: 1.077em;
-  font-family: "Lucida Grande", Verdana, sans-serif;
-  border: 1px solid #e4e4e4;
-  border-bottom: 1px solid #b4b4b4;
-  border-left-color: #d2d2d2;
-  border-right-color: #d2d2d2;
-  background-color: #e4e4e4;
-  border-radius: 20px;
-  text-decoration: none;
-}
-.button:focus,
-.button:hover {
-  background-color: #c0c0c0;
-  border: 1px solid #bebebe;
-  border-left-color: #afafaf;
-  border-right-color: #afafaf;
-  border-bottom-color: #9b9b9b;
-  color: #2e2e2e;
-  text-decoration: none;
-}
-.button:active {
-  background-color: #565656;
-  border: 1px solid #333;
-  border-left-color: #222;
-  border-right-color: #222;
-  border-bottom-color: #111;
-  color: #fff;
-  text-decoration: none;
-  text-shadow: #222 0 -1px 0;
-}
-.button-primary {
-  background-color: #9dcae7;
-  border: 1px solid #8eB7cd;
-  border-bottom-color: #7691a2;
-  color: #133B54;
-}
-.button-primary:focus,
-.button-primary:hover {
-  background-color: #73b3dd;
-  border: 1px solid #6ea3bf;
-  border-bottom-color: #4680a0;
-}
-.button-primary:active {
-  background-color: #3981b1;
-  border: 1px solid #36647c;
-  border-bottom-color: #284657;
-}
-.button-disabled,
-.button-disabled:active,
-.button[disabled],
-.button[disabled]:active {
-  background-color: #eee;
-  border-color: #eee;
-  text-shadow: none;
-  color: #999;
-}
 input.form-autocomplete,
 input.form-text,
 input.form-tel,
@@ -879,42 +817,6 @@ select.form-select:focus {
 .js input.throbbing {
   background-position: 100% -16px;
 }
-.button-action {
-  background: #1078d4;
-  background-image: -webkit-linear-gradient(top, #419ff1, #1076d5);
-  background-image: -moz-linear-gradient(top, #419ff1, #1076d5);
-  background-image: -o-linear-gradient(top, #419ff1, #1076d5);
-  background-image: linear-gradient(to bottom, #419ff1, #1076d5);
-  border: 1px solid #0048c8;
-  border-radius: .4em;
-  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .4);
-  color: #fff;
-  font-size: 1em;
-  line-height: normal;
-  margin: 0;
-  padding: 4px 1em;
-  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.5);
-}
-.button-action:focus,
-.button-action:hover {
-  background-color: #419cf1;
-  background-image: -webkit-linear-gradient(top, #59abf3, #2a90ef);
-  background-image: -moz-linear-gradient(top, #59abf3, #2a90ef);
-  background-image: -o-linear-gradient(top, #59abf3, #2a90ef);
-  background-image: linear-gradient(to bottom, #59abf3, #2a90ef);
-  border: 1px solid #0048c8;
-  color: #fff;
-}
-.button-action:active {
-  background-color: #0e69be;
-  background-image: -webkit-linear-gradient(top, #0e69be, #2a93ef);
-  background-image: -moz-linear-gradient(top, #0e69be, #2a93ef);
-  background-image: -o-linear-gradient(top, #0e69be, #2a93ef);
-  background-image: -ms-linear-gradient(top, #0e69be, #2a93ef);
-  background-image: linear-gradient(to bottom, #0e69be, #2a93ef);
-  border: 1px solid #0048c8;
-  box-shadow: inset 0 1px 2px rgba(0, 0, 0, .25);
-}
 
 /**
  * Improve spacing of cancel link.
