diff --git a/core/modules/grid/config/grid.fluid_12.yml b/core/modules/grid/config/grid.fluid_12.yml
new file mode 100644
index 0000000..774b630
--- /dev/null
+++ b/core/modules/grid/config/grid.fluid_12.yml
@@ -0,0 +1,9 @@
+id: fluid_12
+label: Twelve column fluid
+type: equal_column
+options:
+  units: '%'
+  width: 100
+  columns: 12
+  padding_width: 1.5
+  gutter_width: 2
diff --git a/core/modules/grid/config/grid.fluid_3.yml b/core/modules/grid/config/grid.fluid_3.yml
new file mode 100644
index 0000000..7e6a9a6
--- /dev/null
+++ b/core/modules/grid/config/grid.fluid_3.yml
@@ -0,0 +1,9 @@
+id: fluid_3
+label: Three column fluid
+type: equal_column
+options:
+  units: '%'
+  width: 100
+  columns: 3
+  padding_width: 1.5
+  gutter_width: 2
diff --git a/core/modules/grid/config/grid.fluid_6.yml b/core/modules/grid/config/grid.fluid_6.yml
new file mode 100644
index 0000000..1d7fbcb
--- /dev/null
+++ b/core/modules/grid/config/grid.fluid_6.yml
@@ -0,0 +1,9 @@
+id: fluid_6
+label: Six column fluid
+type: equal_column
+options:
+  units: '%'
+  width: 100
+  columns: 6
+  padding_width: 1.5
+  gutter_width: 2
diff --git a/core/modules/grid/config/grid.ninesixty_12.yml b/core/modules/grid/config/grid.ninesixty_12.yml
new file mode 100644
index 0000000..5409789
--- /dev/null
+++ b/core/modules/grid/config/grid.ninesixty_12.yml
@@ -0,0 +1,9 @@
+id: ninesixty_12
+label: '960px wide, 12 column grid'
+type: equal_column
+options:
+  units: 'px'
+  width: 960
+  columns: 12
+  padding_width: 20
+  gutter_width: 10
diff --git a/core/modules/grid/config/grid.ninesixty_16.yml b/core/modules/grid/config/grid.ninesixty_16.yml
new file mode 100644
index 0000000..2cd9c65
--- /dev/null
+++ b/core/modules/grid/config/grid.ninesixty_16.yml
@@ -0,0 +1,9 @@
+id: ninesixty_16
+label: '960px wide, 16 column grid'
+type: equal_column
+options:
+  units: 'px'
+  width: 960
+  columns: 16
+  padding_width: 20
+  gutter_width: 10
diff --git a/core/modules/grid/grid.admin.inc b/core/modules/grid/grid.admin.inc
new file mode 100644
index 0000000..22d87d8
--- /dev/null
+++ b/core/modules/grid/grid.admin.inc
@@ -0,0 +1,67 @@
+<?php
+
+/**
+ * @file
+ * Administration functions to maintain a common set of grids.
+ */
+
+use Drupal\grid\Grid;
+
+/**
+ * Page callback: Presents list of grids.
+ *
+ * @see grid_menu()
+ */
+function grid_page_list() {
+  $controller = entity_list_controller('grid');
+  return $controller->render();
+}
+
+/**
+ * Page callback: Presents the grid editing form.
+ *
+ * @see grid_menu()
+ */
+function grid_page_edit(Grid $grid) {
+  drupal_set_title(t('<em>Edit grid</em> @label', array('@label' => $grid->label())), PASS_THROUGH);
+  return entity_get_form($grid);
+}
+
+/**
+ * Page callback: Provides the new grid addition form.
+ *
+ * @see grid_menu()
+ */
+function grid_page_add() {
+  $grid = entity_create('grid', array());
+  return entity_get_form($grid);
+}
+
+/**
+ * Page callback: Form constructor for grid deletion confirmation form.
+ *
+ * @see grid_menu()
+ */
+function grid_delete_confirm($form, &$form_state, Grid $grid) {
+  // Always provide entity id in the same form key as in the entity edit form.
+  $form['id'] = array('#type' => 'value', '#value' => $grid->id());
+  $form_state['grid'] = $grid;
+  return confirm_form($form,
+    t('Are you sure you want to remove the grid %title?', array('%title' => $grid->label())),
+    'admin/structure/grids',
+    t('This action cannot be undone.'),
+    t('Delete'),
+    t('Cancel')
+  );
+}
+
+/**
+ * Form submission handler for grid_delete_confirm().
+ */
+function grid_delete_confirm_submit($form, &$form_state) {
+  $grid = $form_state['grid'];
+  $grid->delete();
+  drupal_set_message(t('Grid %label has been deleted.', array('%label' => $grid->label())));
+  watchdog('grid', 'Grid %label has been deleted.', array('%label' => $grid->label()), WATCHDOG_NOTICE);
+  $form_state['redirect'] = 'admin/structure/grids';
+}
diff --git a/core/modules/grid/grid.info b/core/modules/grid/grid.info
new file mode 100644
index 0000000..9dd6db4
--- /dev/null
+++ b/core/modules/grid/grid.info
@@ -0,0 +1,8 @@
+name = Grid
+description = Pluggable grid system manager.
+package = Core
+version = VERSION
+core = 8.x
+dependencies[] = config
+configure = admin/structure/grids
+
diff --git a/core/modules/grid/grid.module b/core/modules/grid/grid.module
new file mode 100644
index 0000000..6063c7f
--- /dev/null
+++ b/core/modules/grid/grid.module
@@ -0,0 +1,116 @@
+<?php
+
+/**
+ * @file
+ * Pluggable grid system manager module.
+ */
+
+use Drupal\grid\Grid;
+
+/**
+ * Implements hook_menu().
+ */
+function grid_menu() {
+  $items = array();
+  $items['admin/structure/grids'] = array(
+    'title' => 'Grids',
+    'description' => 'Manage list of grids which can be used with layouts.',
+    'page callback' => 'grid_page_list',
+    'access callback' => 'user_access',
+    'access arguments' => array('administer grids'),
+    'file' => 'grid.admin.inc',
+  );
+  $items['admin/structure/grids/add'] = array(
+    'title' => 'Add grid',
+    'page callback' => 'grid_page_add',
+    'access callback' => 'user_access',
+    'access arguments' => array('administer grids'),
+    'type' => MENU_LOCAL_ACTION,
+    'file' => 'grid.admin.inc',
+  );
+  $items['admin/structure/grids/manage/%grid'] = array(
+    'title' => 'Edit grid',
+    'page callback' => 'grid_page_edit',
+    'page arguments' => array(4),
+    'access callback' => 'user_access',
+    'access arguments' => array('administer grids'),
+    'type' => MENU_CALLBACK,
+    'file' => 'grid.admin.inc',
+  );
+  $items['admin/structure/grids/manage/%grid/edit'] = array(
+    'title' => 'Edit',
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+    'weight' => -10,
+  );
+  $items['admin/structure/grids/grid/%grid/delete'] = array(
+    'title' => 'Delete',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('grid_delete_confirm', 4),
+    'access callback' => 'user_access',
+    'access arguments' => array('administer grids'),
+    'type' => MENU_LOCAL_TASK,
+    'file' => 'grid.admin.inc',
+  );
+  return $items;
+}
+
+/**
+ * Implements hook_permission().
+ */
+function grid_permission() {
+  return array(
+    'administer grids' => array(
+      'title' => t('Administer grids'),
+      'description' => t('Administer grids created with the grid module.'),
+    ),
+  );
+}
+
+/**
+ * Implements hook_entity_info().
+ */
+function grid_entity_info() {
+  $types['grid'] = array(
+    'label' => t('Grid'),
+    'entity class' => 'Drupal\grid\Grid',
+    'controller class' => 'Drupal\Core\Config\Entity\ConfigStorageController',
+    'form controller class' => array(
+      'default' => 'Drupal\grid\GridFormController',
+    ),
+    'list controller class' => 'Drupal\Core\Config\Entity\ConfigEntityListController',
+    'list path' => 'admin/structure/grids',
+    'uri callback' => 'grid_uri',
+    'config prefix' => 'grid',
+    'entity keys' => array(
+      'id' => 'id',
+      'label' => 'label',
+      'uuid' => 'uuid',
+    ),
+  );
+  return $types;
+}
+
+/**
+ * Entity URI callback.
+ *
+ * @param Drupal\grid\Grid $grid
+ *   Grid configuration entity instance.
+ *
+ * @return array
+ *   Entity URI information.
+ */
+function grid_uri(Grid $grid) {
+  return array(
+    'path' => 'admin/structure/grids/manage/' . $grid->id(),
+  );
+}
+
+/**
+ * Look up one grid setup based on machine name.
+ *
+ * @return Drupal\grid\Grid
+ *   Grid configuration entity instance.
+ */
+function grid_load($id) {
+  return entity_load('grid', $id);
+}
diff --git a/core/modules/grid/lib/Drupal/grid/Grid.php b/core/modules/grid/lib/Drupal/grid/Grid.php
new file mode 100644
index 0000000..af122e5
--- /dev/null
+++ b/core/modules/grid/lib/Drupal/grid/Grid.php
@@ -0,0 +1,81 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\grid\Grid.
+ */
+
+namespace Drupal\grid;
+
+use Drupal\Core\Config\Entity\ConfigEntityBase;
+use Drupal\grid\Plugin\GridInterface;
+
+/**
+ * Defines the grid entity.
+ */
+class Grid extends ConfigEntityBase implements GridInterface {
+
+  /**
+   * The grid ID (machine name).
+   *
+   * @var string
+   */
+  public $id;
+
+  /**
+   * The grid UUID.
+   *
+   * @var string
+   */
+  public $uuid;
+
+  /**
+   * The grid label.
+   *
+   * @var string
+   */
+  public $label;
+
+  /**
+   * Plugin identifier for this grid.
+   *
+   * @var string
+   */
+  public $type;
+
+  /**
+   * Plugin configuration to instantiate the plugin instance.
+   *
+   * @var array
+   */
+  public $options;
+
+  /**
+   * Instantiated plugin to handle the grid.
+   *
+   * @see Drupal\grid\Grid::GetPlugin().
+   *
+   * @var Drupal\grid\Plugin\GridInterface
+   */
+  protected $plugin;
+
+  /**
+   * Get a plugin instance for this grid.
+   */
+  public function getPlugin() {
+    if (!isset($this->plugin)) {
+      // Pass on Grid ID as part of the configuration array.
+      $this->options['id'] = $this->id;
+      $this->plugin = drupal_container()->get('plugin.manager.grid')->createInstance($this->type, $this->options);
+    }
+    return $this->plugin;
+  }
+
+  /**
+   * Implements Drupal\grid\Plugin\GridInterface::getGridCss().
+   */
+  public function getGridCss($wrapper_selector = NULL, $col_selector_prefix = NULL, $skip_spacing = FALSE) {
+    return $this->getPlugin()->getGridCss($wrapper_selector, $col_selector_prefix, $skip_spacing);
+  }
+
+}
diff --git a/core/modules/grid/lib/Drupal/grid/GridBundle.php b/core/modules/grid/lib/Drupal/grid/GridBundle.php
new file mode 100644
index 0000000..eb5b927
--- /dev/null
+++ b/core/modules/grid/lib/Drupal/grid/GridBundle.php
@@ -0,0 +1,25 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\grid\GridBundle.
+ */
+
+namespace Drupal\grid;
+
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\HttpKernel\Bundle\Bundle;
+
+/**
+ * Grid dependency injection container.
+ */
+class GridBundle extends Bundle {
+
+  /**
+   * Overrides Symfony\Component\HttpKernel\Bundle\Bundle::build().
+   */
+  public function build(ContainerBuilder $container) {
+    // Register the GridManager class with the dependency injection container.
+    $container->register('plugin.manager.grid', 'Drupal\grid\Plugin\GridManager');
+  }
+}
diff --git a/core/modules/grid/lib/Drupal/grid/GridFormController.php b/core/modules/grid/lib/Drupal/grid/GridFormController.php
new file mode 100644
index 0000000..96763d7
--- /dev/null
+++ b/core/modules/grid/lib/Drupal/grid/GridFormController.php
@@ -0,0 +1,100 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\grid\GridFormController.
+ */
+
+namespace Drupal\grid;
+
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityFormController;
+
+/**
+ * Form controller for the grid edit/add forms.
+ */
+class GridFormController extends EntityFormController {
+
+  /**
+   * Overrides Drupal\Core\Entity\EntityFormController::prepareEntity().
+   *
+   * Prepares the grid object filling in a few default values.
+   */
+  protected function prepareEntity(EntityInterface $grid) {
+    // If no grid type was specified yet, default to equal_column.
+    if (empty($grid->type)) {
+      $grid->type = 'equal_column';
+      $grid->options = array();
+    }
+    $grid->options = $this->getPlugin()->prepareOptions($grid->options);
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity\EntityFormController::form().
+   */
+  public function form(array $form, array &$form_state, EntityInterface $grid) {
+    $form['label'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Label'),
+      '#maxlength' => 255,
+      '#default_value' => $grid->label(),
+      '#required' => TRUE,
+    );
+    $form['id'] = array(
+      '#type' => 'machine_name',
+      '#default_value' => $grid->id(),
+      '#machine_name' => array(
+        'exists' => 'grid_load',
+        'source' => array('label'),
+      ),
+      '#disabled' => !$grid->isNew(),
+    );
+    $form['type'] = array(
+      '#type' => 'value',
+      '#value' => $grid->type,
+    );
+    $form['options'] = $this->getPlugin()->form($form, $form_state, $grid->options);
+
+    return parent::form($form, $form_state, $grid);
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity\EntityFormController::validate().
+   */
+  public function validate(array $form, array &$form_state) {
+    $this->getPlugin()->validate($form, $form_state['values']['options']);
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity\EntityFormController::actions().
+   */
+  protected function actions(array $form, array &$form_state) {
+    // Only includes a Save action for the entity, no direct Delete button.
+    return array(
+      'submit' => array(
+        '#value' => t('Save'),
+        '#validate' => array(
+          array($this, 'validate'),
+        ),
+        '#submit' => array(
+          array($this, 'submit'),
+          array($this, 'save'),
+        ),
+      ),
+    );
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity\EntityFormController::save().
+   */
+  public function save(array $form, array &$form_state) {
+    $grid = $this->getEntity($form_state);
+    $grid->save();
+
+    watchdog('grid', 'Grid @label saved.', array('@label' => $grid->label()), WATCHDOG_NOTICE);
+    drupal_set_message(t('Grid %label saved.', array('%label' => $grid->label())));
+
+    $form_state['redirect'] = 'admin/structure/grids';
+  }
+
+}
diff --git a/core/modules/grid/lib/Drupal/grid/Plugin/GridInterface.php b/core/modules/grid/lib/Drupal/grid/Plugin/GridInterface.php
new file mode 100644
index 0000000..ca73fd8
--- /dev/null
+++ b/core/modules/grid/lib/Drupal/grid/Plugin/GridInterface.php
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\grid\Plugin\GridInterface.
+ */
+
+namespace Drupal\grid\Plugin;
+
+/**
+ * Defines the shared interface for all grid plugins.
+ */
+interface GridInterface {
+
+  /**
+   * Generates grid CSS for this grid system.
+   *
+   * @param (string) $wrapper_selector
+   *   (optional) Wrapper CSS selector to use to scope the CSS.
+   * @param (string) $col_selector_prefix
+   *   (optional) Column selector prefix to scope the CSS.
+   * @param (boolean) $skip_spacing
+   *    Whether we should skip including spacing in the output. Useful for tight
+   *    layout demonstration presentation.
+   *
+   * @return string
+   *   Grid CSS for this grid system.
+   */
+  public function getGridCss($wrapper_selector = NULL, $col_selector_prefix = NULL, $skip_spacing = FALSE);
+}
diff --git a/core/modules/grid/lib/Drupal/grid/Plugin/GridManager.php b/core/modules/grid/lib/Drupal/grid/Plugin/GridManager.php
new file mode 100644
index 0000000..78516f1
--- /dev/null
+++ b/core/modules/grid/lib/Drupal/grid/Plugin/GridManager.php
@@ -0,0 +1,26 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\grid\Plugin\GridManager.
+ */
+
+namespace Drupal\grid\Plugin;
+
+use Drupal\Component\Plugin\PluginManagerBase;
+use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
+use Drupal\Component\Plugin\Factory\ReflectionFactory;
+
+/**
+ * Grid plugin manager.
+ */
+class GridManager extends PluginManagerBase {
+
+  /**
+   * Overrides Drupal\Component\Plugin\PluginManagerBase::__construct().
+   */
+  public function __construct() {
+    $this->discovery = new AnnotatedClassDiscovery('grid', 'grid');
+    $this->factory = new ReflectionFactory($this);
+  }
+}
diff --git a/core/modules/grid/lib/Drupal/grid/Plugin/grid/grid/EqualColumn.php b/core/modules/grid/lib/Drupal/grid/Plugin/grid/grid/EqualColumn.php
new file mode 100644
index 0000000..881723c
--- /dev/null
+++ b/core/modules/grid/lib/Drupal/grid/Plugin/grid/grid/EqualColumn.php
@@ -0,0 +1,250 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\grid\Plugin\grid\grid\EqualColumn.
+ */
+
+namespace Drupal\grid\Plugin\grid\grid;
+
+use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
+use Drupal\grid\Plugin\GridInterface;
+use Drupal\Component\Plugin\PluginBase;
+use Drupal\Core\Annotation\Plugin;
+
+/**
+ * @Plugin(
+ *  id = "equal_column"
+ * )
+ */
+class EqualColumn implements GridInterface {
+
+  /**
+   * The grid ID (machine name).
+   *
+   * @var string
+   */
+  protected $id;
+
+  /**
+   * The total numeric width of the grid without units.
+   *
+   * For example, '960' for a 960px grid or '100' for a fluid (100%) grid.
+   *
+   * @var string
+   */
+  protected $width;
+
+  /**
+   * The size units that width, gutter, and padding are in.
+   *
+   * For example, 'px', 'em', or '%'.
+   *
+   * @var string
+   */
+  protected $units;
+
+  /**
+   * The number of columns.
+   *
+   * @var string
+   */
+  protected $columns;
+
+  /**
+   * The gutter width.
+   *
+   * @var string
+   */
+  protected $gutter;
+
+  /**
+   * The padding width.
+   *
+   * @var string
+   */
+  protected $padding;
+
+  /**
+   * Constructor.
+   */
+  public function __construct($id, $units, $width, $columns, $padding_width, $gutter_width) {
+    $this->id = $id;
+    $this->columns = $columns;
+    $this->padding = $padding_width;
+    $this->gutter = $gutter_width;
+    $this->width = $width;
+    $this->units = $units;
+  }
+
+  /**
+   * Prepare grid entity.
+   */
+  public function prepareOptions(array $options) {
+    if (empty($options['width'])) {
+      // Set some defaults for the user if this is a new grid.
+      $options['units'] = '%';
+      $options['width'] = 100;
+      $options['columns'] = 12;
+      $options['padding_width'] = 1.5;
+      $options['gutter_width'] = 2;
+    }
+    return $options;
+  }
+
+  /**
+   * Form elements for grid editing.
+   */
+  public function form(array $form, array &$form_state, array $options) {
+    // Master grid configuration.
+    $form['unit'] = array(
+      '#type' => 'radios',
+      '#title' => t('Grid units'),
+      '#options' => array('%' => t('Percentages'), 'em' => t('Em-based'), 'px' => t('Pixel based')),
+      '#default_value' => $options['unit'],
+    );
+    $form['width'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Grid width'),
+      '#description' => t('Width of the grid in unit set above. For example 960 (pixels) or 100 (percent).'),
+      '#default_value' => $options['width'],
+    );
+
+    // Grid detail configuration.
+    $form['columns'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Number of grid columns'),
+      '#default_value' => $options['columns'],
+    );
+    $form['padding_width'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Column padding'),
+      '#description' => t('Column padding in unit set above. For example 10 (pixels) or 1.5 (percent). Enter 0 for no padding.'),
+      '#default_value' => $options['padding_width'],
+    );
+
+    $form['gutter_width'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Gutter width'),
+      '#description' => t('Gutter width in unit set above. For example 20 (pixels) or 1.5 (percent). Enter 0 for no padding.'),
+      '#default_value' => $options['gutter_width'],
+    );
+    return $form;
+  }
+
+  /**
+   * Form validation callback.
+   */
+  public function validate(array $form, array &$options_state) {
+    if ((intval($options_state['width']) != $options_state['width']) || $options_state['width'] == 0) {
+      // Width should be a positive integer.
+      form_set_error('columns', t('The width should be a positive number.'));
+    }
+    if ((intval($options_state['columns']) != $options_state['columns']) || $options_state['columns'] == 0) {
+      // Columns should be a positive integer.
+      form_set_error('columns', t('The number of columns should be a positive number.'));
+    }
+    if (!is_numeric($options_state['padding_width'])) {
+      // Padding can be float as well (eg. 1.5 for 1.5% for fluid grids).
+      form_set_error('padding_width', t('The column padding should be a number. Enter 0 (zero) for no padding.' . $options_state['padding_width']));
+    }
+    if (!is_numeric($options_state['gutter_width'])) {
+      // Gutter can be float too (eg. 1.5 for 1.5% for fluid grids).
+      form_set_error('gutter_width', t('The gutter width should be a number. Enter 0 (zero) for no gutter.'));
+    }
+  }
+
+  /**
+   * Implements Drupal\grid\Plugin\GridInterface::getGridCss().
+   */
+  public function getGridCss($wrapper_selector = NULL, $col_selector_prefix = NULL, $skip_spacing = FALSE) {
+
+    // If the wrapper selector was not provided, generate one. This is useful for
+    // specific administration use cases when we scope the classes by grids.
+    if (empty($wrapper_selector)) {
+      $wrapper_selector = '.grid-' . $this->id;
+    }
+
+    // If the col span selector was not provided, generate one. This is useful
+    // for the front end to apply varying span widths under different names.
+    if (empty($col_selector_prefix)) {
+      $col_selector_prefix = '.grid-col-';
+    }
+
+    // If spacing is to be skipped, use 0 instead of the configured values.
+    if ($skip_spacing) {
+      $padding = 0;
+      $gutter = 0;
+    }
+    else {
+      $padding = $this->padding;
+      $gutter = $this->gutter;
+    }
+
+    // Because we use the border-box box model, we only need to substract the
+    // size of margins from the full width and divide the rest by number of
+    // columns to get a value for column size.
+    $colwidth = ($this->width - (($this->columns - 1) * $gutter)) / $this->columns;
+
+    $css = array();
+    $css[$wrapper_selector . ' .grid-col'] = array(
+      'border' => '0px solid rgba(0,0,0,0)',
+      'float' => 'left',
+      '-webkit-box-sizing' => 'border-box',
+      '-moz-box-sizing' => 'border-box',
+      'box-sizing' => 'border-box',
+      '-moz-background-clip' => 'padding-box',
+      '-webkit-background-clip' => 'padding-box',
+      'background-clip' => 'padding-box',
+      'margin-left' => $gutter . $this->units,
+      'padding' => '0 ' . $padding  . $this->units,
+    );
+    $css[$wrapper_selector . ' .grid-col' . $col_selector_prefix . 'first'] = array(
+      'margin-left' => '0',
+      'clear' => 'both',
+    );
+    for ($i = 1; $i <= $this->columns; $i++) {
+      $selector = $wrapper_selector . ' .grid-col' . $col_selector_prefix . $i;
+      if ($i == 1) {
+        // The first column does not yet have any margins.
+        $css[$selector] = array(
+          'width' => ($colwidth * $i) . $this->units,
+        );
+      }
+      elseif ($i == $this->columns) {
+        // The last column always spans 100%.
+        $css[$selector] = array(
+          'width' => $this->width . $this->units,
+          'margin-left' => 0,
+        );
+      }
+      else {
+        // Other columns absorb all columns that they need to include and one
+        // less margin before them.
+        $css[$selector] = array(
+          'width' => (($colwidth * $i) + ($gutter * ($i - 1))) . $this->units,
+        );
+      }
+    }
+
+    return $this->formatCss($css);
+  }
+
+  /**
+   * Returns a CSS string.
+   *
+   * @param (array) $css
+   *   A two dimensional array, keyed first on selector, then on property name.
+   */
+  protected function formatCss($css) {
+    $output = '';
+    foreach ($css as $selector => $rules) {
+      $output .= $selector . "{\n";
+      foreach ($rules as $property => $value) {
+        $output .= '  ' . $property . ': ' . $value . ";\n";
+      }
+      $output .= "}\n";
+    }
+    return $output;
+  }
+}
