diff --git a/cdn.basic.css.inc b/cdn.basic.css.inc
new file mode 100644
index 0000000..66cc0a3
--- /dev/null
+++ b/cdn.basic.css.inc
@@ -0,0 +1,127 @@
+<?php
+
+/**
+ * @file
+ * Overrides of Drupal's CSS aggregation system. Ensures that files referenced
+ * by CSS files are also served from the CDN, according to the CDN module's
+ * CSS aggregation rules.
+ */
+
+
+/**
+ * Near-identical to @see drupal_aggregate_css().
+ *
+ * Changes: call _cdn_build_css_cache() instead of drupal_build_css_cache().
+ */
+function _cdn_aggregate_css(&$css_groups) {
+  $preprocess_css = (variable_get('preprocess_css', FALSE) && (!defined('MAINTENANCE_MODE') || MAINTENANCE_MODE != 'update'));
+
+  // For each group that needs aggregation, aggregate its items.
+  foreach ($css_groups as $key => $group) {
+    switch ($group['type']) {
+      // If a file group can be aggregated into a single file, do so, and set
+      // the group's data property to the file path of the aggregate file.
+      case 'file':
+        if ($group['preprocess'] && $preprocess_css) {
+          $css_groups[$key]['data'] = _cdn_build_css_cache($group['items']);
+        }
+        break;
+      // Aggregate all inline CSS content into the group's data property.
+      case 'inline':
+        $css_groups[$key]['data'] = '';
+        foreach ($group['items'] as $item) {
+          $css_groups[$key]['data'] .= drupal_load_stylesheet_content($item['data'], $item['preprocess']);
+        }
+        break;
+    }
+  }
+}
+
+/**
+ * Near-identical to @see drupal_build_css_cache().
+ *
+ * Changes:
+ * - the inner loop is modified
+ * - uses _cdn_build_css_path() instead of drupal_build_css_path().
+ */
+function _cdn_build_css_cache($css) {
+  $data = '';
+  $uri = '';
+  $map = variable_get('drupal_css_cache_files', array());
+  $key = hash('sha256', serialize($css));
+  if (isset($map[$key])) {
+    $uri = $map[$key];
+  }
+
+  if (empty($uri) || !file_exists($uri)) {
+    // Build aggregate CSS file.
+    foreach ($css as $stylesheet) {
+      // Only 'file' stylesheets can be aggregated.
+      if ($stylesheet['type'] == 'file') {
+        $contents = drupal_load_stylesheet($stylesheet['data'], TRUE);
+
+        // Get the parent directory of this file, relative to the Drupal root.
+        $css_base_url = substr($stylesheet['data'], 0, strrpos($stylesheet['data'], '/'));
+        _cdn_build_css_path(NULL, $css_base_url . '/');
+
+        // Anchor all paths in the CSS with its base URL, ignoring external and absolute paths.
+        $data .= preg_replace_callback('/url\(\s*[\'"]?(?![a-z]+:|\/+)([^\'")]+)[\'"]?\s*\)/i', '_cdn_build_css_path', $contents);
+      }
+    }
+
+    // Per the W3C specification at http://www.w3.org/TR/REC-CSS2/cascade.html#at-import,
+    // @import rules must proceed any other style, so we move those to the top.
+    $regexp = '/@import[^;]+;/i';
+    preg_match_all($regexp, $data, $matches);
+    $data = preg_replace($regexp, '', $data);
+    $data = implode('', $matches[0]) . $data;
+
+    // Prefix filename to prevent blocking by firewalls which reject files
+    // starting with "ad*".
+    $filename = 'css_' . drupal_hash_base64($data) . '.css';
+    // Create the css/ within the files folder.
+    $csspath = 'public://css';
+    $uri = $csspath . '/' . $filename;
+    // Create the CSS file.
+    file_prepare_directory($csspath, FILE_CREATE_DIRECTORY);
+    if (!file_exists($uri) && !file_unmanaged_save_data($data, $uri, FILE_EXISTS_REPLACE)) {
+      return FALSE;
+    }
+    // If CSS gzip compression is enabled, clean URLs are enabled (which means
+    // that rewrite rules are working) and the zlib extension is available then
+    // create a gzipped version of this file. This file is served conditionally
+    // to browsers that accept gzip using .htaccess rules.
+    if (variable_get('css_gzip_compression', TRUE) && variable_get('clean_url', 0) && extension_loaded('zlib')) {
+      if (!file_exists($uri . '.gz') && !file_unmanaged_save_data(gzencode($data, 9, FORCE_GZIP), $uri . '.gz', FILE_EXISTS_REPLACE)) {
+        return FALSE;
+      }
+    }
+    // Save the updated map.
+    $map[$key] = $uri;
+    variable_set('drupal_css_cache_files', $map);
+  }
+  return $uri;
+}
+
+/**
+ * Near-identical to @see drupal_build_css_path().
+ *
+ * Changes: apply file_create_url() to every file!
+ */
+function _cdn_build_css_path($matches, $base = NULL) {
+  $_base = &drupal_static(__FUNCTION__);
+  // Store base path for preg_replace_callback.
+  if (isset($base)) {
+    $_base = $base;
+  }
+
+  // Prefix with base and remove '../' segments where possible.
+  $path = $_base . $matches[1];
+  $last = '';
+  while ($path != $last) {
+    $last = $path;
+    $path = preg_replace('`(^|/)(?!\.\./)([^/]+)/\.\./`', '$1', $path);
+  }
+
+  return 'url(' . file_create_url($path) . ')';
+}
diff --git a/cdn.module b/cdn.module
index eb27f96..b602dd5 100644
--- a/cdn.module
+++ b/cdn.module
@@ -294,6 +294,18 @@ function cdn_cdn_unique_file_identifier_info() {
 }
 
 /**
+ * Implements hook_element_info_alter().
+ */
+function cdn_element_info_alter(&$type) {
+  $mode = variable_get(CDN_MODE_VARIABLE, CDN_MODE_BASIC);
+  if ($mode == CDN_MODE_BASIC) {
+    // Override Drupal's CSS aggregation system.
+    cdn_load_include('basic.css');
+    $type['styles']['#aggregate_callback'] = '_cdn_aggregate_css';
+  }
+}
+
+/**
  * Implements hook_menu().
  */
 function cdn_menu() {
