    /**
     * @class Ext.util.CSS
     * Utility class for manipulating CSS rules
     * @singleton
     */
    Ext.define('Ext.util.CSS', function() {
        var rules = null;
        var doc = document;

        var camelRe = /(-[a-z])/gi;
        var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };

        return {

            singleton: true,

            constructor: function() {
                this.rules = {};
                this.initialized = false;
            },

            /**
             * Creates a stylesheet from a text blob of rules.
             * These rules will be wrapped in a STYLE tag and appended to the HEAD of the document.
             * @param {String} cssText The text containing the css rules
             * @param {String} id An id to add to the stylesheet for later removal
             * @return {StyleSheet}
             */
            createStyleSheet : function(cssText, id) {
                var ss,
                    head = doc.getElementsByTagName("head")[0],
                    styleEl = doc.createElement("style");

                styleEl.setAttribute("type", "text/css");
                if (id) {
                   styleEl.setAttribute("id", id);
                }

                if (Ext.isIE) {
                   head.appendChild(styleEl);
                   ss = styleEl.styleSheet;
                   ss.cssText = cssText;
                } else {
                    try{
                        styleEl.appendChild(doc.createTextNode(cssText));
                    } catch(e) {
                       styleEl.cssText = cssText;
                    }
                    head.appendChild(styleEl);
                    ss = styleEl.styleSheet ? styleEl.styleSheet : (styleEl.sheet || doc.styleSheets[doc.styleSheets.length-1]);
                }
                this.cacheStyleSheet(ss);
                return ss;
            },

            /**
             * Removes a style or link tag by id
             * @param {String} id The id of the tag
             */
            removeStyleSheet : function(id) {
                var existing = document.getElementById(id);
                if (existing) {
                    existing.parentNode.removeChild(existing);
                }
            },

            /**
             * Dynamically swaps an existing stylesheet reference for a new one
             * @param {String} id The id of an existing link tag to remove
             * @param {String} url The href of the new stylesheet to include
             */
            swapStyleSheet : function(id, url) {
                var doc = document;
                this.removeStyleSheet(id);
                var ss = doc.createElement("link");
                ss.setAttribute("rel", "stylesheet");
                ss.setAttribute("type", "text/css");
                ss.setAttribute("id", id);
                ss.setAttribute("href", url);
                doc.getElementsByTagName("head")[0].appendChild(ss);
            },

            /**
             * Refresh the rule cache if you have dynamically added stylesheets
             * @return {Object} An object (hash) of rules indexed by selector
             */
            refreshCache : function() {
                return this.getRules(true);
            },

            // private
            cacheStyleSheet : function(ss) {
                if(!rules){
                    rules = {};
                }
                try {// try catch for cross domain access issue
                    var ssRules = ss.cssRules || ss.rules,
                        selectorText,
                        i = ssRules.length - 1,
                        j,
                        selectors;

                    for (; i >= 0; --i) {
                        selectorText = ssRules[i].selectorText;
                        if (selectorText) {

                            // Split in case there are multiple, comma-delimited selectors
                            selectorText = selectorText.split(',');
                            selectors = selectorText.length;
                            for (j = 0; j < selectors; j++) {
                                rules[Ext.String.trim(selectorText[j]).toLowerCase()] = ssRules[i];
                            }
                        }
                    }
                } catch(e) {}
            },

            /**
            * Gets all css rules for the document
            * @param {Boolean} refreshCache true to refresh the internal cache
            * @return {Object} An object (hash) of rules indexed by selector
            */
            getRules : function(refreshCache) {
                if (rules === null || refreshCache) {
                    rules = {};
                    var ds = doc.styleSheets,
                        i = 0,
                        len = ds.length;

                    for (; i < len; i++) {
                        try {
                            if (!ds[i].disabled) {
                                this.cacheStyleSheet(ds[i]);
                            }
                        } catch(e) {}
                    }
                }
                return rules;
            },

            /**
             * Gets an an individual CSS rule by selector(s)
             * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
             * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
             * @return {CSSRule} The CSS rule or null if one is not found
             */
            getRule: function(selector, refreshCache) {
                var rs = this.getRules(refreshCache);
                if (!Ext.isArray(selector)) {
                    return rs[selector.toLowerCase()];
                }
                for (var i = 0; i < selector.length; i++) {
                    if (rs[selector[i]]) {
                        return rs[selector[i].toLowerCase()];
                    }
                }
                return null;
            },

            /**
             * Updates a rule property
             * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
             * @param {String} property The css property
             * @param {String} value The new value for the property
             * @return {Boolean} true If a rule was found and updated
             */
            updateRule : function(selector, property, value){
                if (!Ext.isArray(selector)) {
                    var rule = this.getRule(selector);
                    if (rule) {
                        rule.style[property.replace(camelRe, camelFn)] = value;
                        return true;
                    }
                } else {
                    for (var i = 0; i < selector.length; i++) {
                        if (this.updateRule(selector[i], property, value)) {
                            return true;
                        }
                    }
                }
                return false;
            }
        };
    }());