diff --git a/templates/html/assets/images/menu-flap.png b/templates/html/assets/images/menu-flap.png
new file mode 100644
index 0000000..4424406
Binary files /dev/null and b/templates/html/assets/images/menu-flap.png differ
diff --git a/templates/html/assets/images/search-background.png b/templates/html/assets/images/search-background.png
new file mode 100644
index 0000000..7629500
Binary files /dev/null and b/templates/html/assets/images/search-background.png differ
diff --git a/templates/html/assets/images/section-background.png b/templates/html/assets/images/section-background.png
new file mode 100644
index 0000000..d3cf11e
Binary files /dev/null and b/templates/html/assets/images/section-background.png differ
diff --git a/templates/html/assets/javascripts/tabs.js b/templates/html/assets/javascripts/tabs.js
new file mode 100644
index 0000000..7c97420
--- /dev/null
+++ b/templates/html/assets/javascripts/tabs.js
@@ -0,0 +1,506 @@
+/**
+ * @author Ryan Johnson
+ * @copyright 2008 PersonalGrid Corporation
+ * @package LivePipe UI
+ * @license MIT
+ * @url http://livepipe.net/core
+ * @require prototype.js
+ */
+
+if(typeof(Control) == 'undefined')
+ Control = {};
+
+var $proc = function(proc){
+ return typeof(proc) == 'function' ? proc : function(){return proc};
+};
+
+var $value = function(value){
+ return typeof(value) == 'function' ? value() : value;
+};
+
+Object.Event = {
+ extend: function(object){
+ object._objectEventSetup = function(event_name){
+ this._observers = this._observers || {};
+ this._observers[event_name] = this._observers[event_name] || [];
+ };
+ object.observe = function(event_name,observer){
+ if(typeof(event_name) == 'string' && typeof(observer) != 'undefined'){
+ this._objectEventSetup(event_name);
+ if(!this._observers[event_name].include(observer))
+ this._observers[event_name].push(observer);
+ }else
+ for(var e in event_name)
+ this.observe(e,event_name[e]);
+ };
+ object.stopObserving = function(event_name,observer){
+ this._objectEventSetup(event_name);
+ if(event_name && observer)
+ this._observers[event_name] = this._observers[event_name].without(observer);
+ else if(event_name)
+ this._observers[event_name] = [];
+ else
+ this._observers = {};
+ };
+ object.observeOnce = function(event_name,outer_observer){
+ var inner_observer = function(){
+ outer_observer.apply(this,arguments);
+ this.stopObserving(event_name,inner_observer);
+ }.bind(this);
+ this._objectEventSetup(event_name);
+ this._observers[event_name].push(inner_observer);
+ };
+ object.notify = function(event_name){
+ this._objectEventSetup(event_name);
+ var collected_return_values = [];
+ var args = $A(arguments).slice(1);
+ try{
+ for(var i = 0; i < this._observers[event_name].length; ++i)
+ collected_return_values.push(this._observers[event_name][i].apply(this._observers[event_name][i],args) || null);
+ }catch(e){
+ if(e == $break)
+ return false;
+ else
+ throw e;
+ }
+ return collected_return_values;
+ };
+ if(object.prototype){
+ object.prototype._objectEventSetup = object._objectEventSetup;
+ object.prototype.observe = object.observe;
+ object.prototype.stopObserving = object.stopObserving;
+ object.prototype.observeOnce = object.observeOnce;
+ object.prototype.notify = function(event_name){
+ if(object.notify){
+ var args = $A(arguments).slice(1);
+ args.unshift(this);
+ args.unshift(event_name);
+ object.notify.apply(object,args);
+ }
+ this._objectEventSetup(event_name);
+ var args = $A(arguments).slice(1);
+ var collected_return_values = [];
+ try{
+ if(this.options && this.options[event_name] && typeof(this.options[event_name]) == 'function')
+ collected_return_values.push(this.options[event_name].apply(this,args) || null);
+ for(var i = 0; i < this._observers[event_name].length; ++i)
+ collected_return_values.push(this._observers[event_name][i].apply(this._observers[event_name][i],args) || null);
+ }catch(e){
+ if(e == $break)
+ return false;
+ else
+ throw e;
+ }
+ return collected_return_values;
+ };
+ }
+ }
+};
+
+/* Begin Core Extensions */
+
+//Element.observeOnce
+Element.addMethods({
+ observeOnce: function(element,event_name,outer_callback){
+ var inner_callback = function(){
+ outer_callback.apply(this,arguments);
+ Element.stopObserving(element,event_name,inner_callback);
+ };
+ Element.observe(element,event_name,inner_callback);
+ }
+});
+
+//mouseenter, mouseleave
+//from http://dev.rubyonrails.org/attachment/ticket/8354/event_mouseenter_106rc1.patch
+Object.extend(Event, (function() {
+ var cache = Event.cache;
+
+ function getEventID(element) {
+ if (element._prototypeEventID) return element._prototypeEventID[0];
+ arguments.callee.id = arguments.callee.id || 1;
+ return element._prototypeEventID = [++arguments.callee.id];
+ }
+
+ function getDOMEventName(eventName) {
+ if (eventName && eventName.include(':')) return "dataavailable";
+ //begin extension
+ if(!Prototype.Browser.IE){
+ eventName = {
+ mouseenter: 'mouseover',
+ mouseleave: 'mouseout'
+ }[eventName] || eventName;
+ }
+ //end extension
+ return eventName;
+ }
+
+ function getCacheForID(id) {
+ return cache[id] = cache[id] || { };
+ }
+
+ function getWrappersForEventName(id, eventName) {
+ var c = getCacheForID(id);
+ return c[eventName] = c[eventName] || [];
+ }
+
+ function createWrapper(element, eventName, handler) {
+ var id = getEventID(element);
+ var c = getWrappersForEventName(id, eventName);
+ if (c.pluck("handler").include(handler)) return false;
+
+ var wrapper = function(event) {
+ if (!Event || !Event.extend ||
+ (event.eventName && event.eventName != eventName))
+ return false;
+
+ Event.extend(event);
+ handler.call(element, event);
+ };
+
+ //begin extension
+ if(!(Prototype.Browser.IE) && ['mouseenter','mouseleave'].include(eventName)){
+ wrapper = wrapper.wrap(function(proceed,event) {
+ var rel = event.relatedTarget;
+ var cur = event.currentTarget;
+ if(rel && rel.nodeType == Node.TEXT_NODE)
+ rel = rel.parentNode;
+ if(rel && rel != cur && !rel.descendantOf(cur))
+ return proceed(event);
+ });
+ }
+ //end extension
+
+ wrapper.handler = handler;
+ c.push(wrapper);
+ return wrapper;
+ }
+
+ function findWrapper(id, eventName, handler) {
+ var c = getWrappersForEventName(id, eventName);
+ return c.find(function(wrapper) { return wrapper.handler == handler });
+ }
+
+ function destroyWrapper(id, eventName, handler) {
+ var c = getCacheForID(id);
+ if (!c[eventName]) return false;
+ c[eventName] = c[eventName].without(findWrapper(id, eventName, handler));
+ }
+
+ function destroyCache() {
+ for (var id in cache)
+ for (var eventName in cache[id])
+ cache[id][eventName] = null;
+ }
+
+ if (window.attachEvent) {
+ window.attachEvent("onunload", destroyCache);
+ }
+
+ return {
+ observe: function(element, eventName, handler) {
+ element = $(element);
+ var name = getDOMEventName(eventName);
+
+ var wrapper = createWrapper(element, eventName, handler);
+ if (!wrapper) return element;
+
+ if (element.addEventListener) {
+ element.addEventListener(name, wrapper, false);
+ } else {
+ element.attachEvent("on" + name, wrapper);
+ }
+
+ return element;
+ },
+
+ stopObserving: function(element, eventName, handler) {
+ element = $(element);
+ var id = getEventID(element), name = getDOMEventName(eventName);
+
+ if (!handler && eventName) {
+ getWrappersForEventName(id, eventName).each(function(wrapper) {
+ element.stopObserving(eventName, wrapper.handler);
+ });
+ return element;
+
+ } else if (!eventName) {
+ Object.keys(getCacheForID(id)).each(function(eventName) {
+ element.stopObserving(eventName);
+ });
+ return element;
+ }
+
+ var wrapper = findWrapper(id, eventName, handler);
+ if (!wrapper) return element;
+
+ if (element.removeEventListener) {
+ element.removeEventListener(name, wrapper, false);
+ } else {
+ element.detachEvent("on" + name, wrapper);
+ }
+
+ destroyWrapper(id, eventName, handler);
+
+ return element;
+ },
+
+ fire: function(element, eventName, memo) {
+ element = $(element);
+ if (element == document && document.createEvent && !element.dispatchEvent)
+ element = document.documentElement;
+
+ var event;
+ if (document.createEvent) {
+ event = document.createEvent("HTMLEvents");
+ event.initEvent("dataavailable", true, true);
+ } else {
+ event = document.createEventObject();
+ event.eventType = "ondataavailable";
+ }
+
+ event.eventName = eventName;
+ event.memo = memo || { };
+
+ if (document.createEvent) {
+ element.dispatchEvent(event);
+ } else {
+ element.fireEvent(event.eventType, event);
+ }
+
+ return Event.extend(event);
+ }
+ };
+})());
+
+Object.extend(Event, Event.Methods);
+
+Element.addMethods({
+ fire: Event.fire,
+ observe: Event.observe,
+ stopObserving: Event.stopObserving
+});
+
+Object.extend(document, {
+ fire: Element.Methods.fire.methodize(),
+ observe: Element.Methods.observe.methodize(),
+ stopObserving: Element.Methods.stopObserving.methodize()
+});
+
+//mouse:wheel
+(function(){
+ function wheel(event){
+ var delta;
+ // normalize the delta
+ if(event.wheelDelta) // IE & Opera
+ delta = event.wheelDelta / 120;
+ else if (event.detail) // W3C
+ delta =- event.detail / 3;
+ if(!delta)
+ return;
+ var custom_event = Event.element(event).fire('mouse:wheel',{
+ delta: delta
+ });
+ if(custom_event.stopped){
+ Event.stop(event);
+ return false;
+ }
+ }
+ document.observe('mousewheel',wheel);
+ document.observe('DOMMouseScroll',wheel);
+})();
+
+/* End Core Extensions */
+
+//from PrototypeUI
+var IframeShim = Class.create({
+ initialize: function() {
+ this.element = new Element('iframe',{
+ style: 'position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);display:none',
+ src: 'javascript:void(0);',
+ frameborder: 0
+ });
+ $(document.body).insert(this.element);
+ },
+ hide: function() {
+ this.element.hide();
+ return this;
+ },
+ show: function() {
+ this.element.show();
+ return this;
+ },
+ positionUnder: function(element) {
+ var element = $(element);
+ var offset = element.cumulativeOffset();
+ var dimensions = element.getDimensions();
+ this.element.setStyle({
+ left: offset[0] + 'px',
+ top: offset[1] + 'px',
+ width: dimensions.width + 'px',
+ height: dimensions.height + 'px',
+ zIndex: element.getStyle('zIndex') - 1
+ }).show();
+ return this;
+ },
+ setBounds: function(bounds) {
+ for(prop in bounds)
+ bounds[prop] += 'px';
+ this.element.setStyle(bounds);
+ return this;
+ },
+ destroy: function() {
+ if(this.element)
+ this.element.remove();
+ return this;
+ }
+});
+
+/**
+ * @author Ryan Johnson
+ * @copyright 2008 PersonalGrid Corporation
+ * @package LivePipe UI
+ * @license MIT
+ * @url http://livepipe.net/control/tabs
+ * @require prototype.js, livepipe.js
+ */
+
+/*global window, document, Prototype, $, $A, $H, $break, Class, Element, Event, Control */
+
+if(typeof(Prototype) == "undefined") {
+ throw "Control.Tabs requires Prototype to be loaded."; }
+if(typeof(Object.Event) == "undefined") {
+ throw "Control.Tabs requires Object.Event to be loaded."; }
+
+Control.Tabs = Class.create({
+ initialize: function(tab_list_container,options){
+ if(!$(tab_list_container)) {
+ throw "Control.Tabs could not find the element: " + tab_list_container; }
+ this.activeContainer = false;
+ this.activeLink = false;
+ this.containers = $H({});
+ this.links = [];
+ Control.Tabs.instances.push(this);
+ this.options = {
+ beforeChange: Prototype.emptyFunction,
+ afterChange: Prototype.emptyFunction,
+ hover: false,
+ linkSelector: 'li a',
+ setClassOnContainer: false,
+ activeClassName: 'active',
+ defaultTab: 'first',
+ autoLinkExternal: true,
+ targetRegExp: /#(.+)$/,
+ showFunction: Element.show,
+ hideFunction: Element.hide
+ };
+ Object.extend(this.options,options || {});
+ (typeof(this.options.linkSelector == 'string') ?
+ $(tab_list_container).select(this.options.linkSelector) :
+ this.options.linkSelector($(tab_list_container))
+ ).findAll(function(link){
+ return (/^#/).exec((Prototype.Browser.WebKit ? decodeURIComponent(link.href) : link.href).replace(window.location.href.split('#')[0],''));
+ }).each(function(link){
+ this.addTab(link);
+ }.bind(this));
+ this.containers.values().each(Element.hide);
+ if(this.options.defaultTab == 'first') {
+ this.setActiveTab(this.links.first());
+ } else if(this.options.defaultTab == 'last') {
+ this.setActiveTab(this.links.last());
+ } else {
+ this.setActiveTab(this.options.defaultTab); }
+ var targets = this.options.targetRegExp.exec(window.location);
+ if(targets && targets[1]){
+ targets[1].split(',').each(function(target){
+ this.setActiveTab(this.links.find(function(link){
+ return link.key == target;
+ }));
+ }.bind(this));
+ }
+ if(this.options.autoLinkExternal){
+ $A(document.getElementsByTagName('a')).each(function(a){
+ if(!this.links.include(a)){
+ var clean_href = a.href.replace(window.location.href.split('#')[0],'');
+ if(clean_href.substring(0,1) == '#'){
+ if(this.containers.keys().include(clean_href.substring(1))){
+ $(a).observe('click',function(event,clean_href){
+ this.setActiveTab(clean_href.substring(1));
+ }.bindAsEventListener(this,clean_href));
+ }
+ }
+ }
+ }.bind(this));
+ }
+ },
+ addTab: function(link){
+ this.links.push(link);
+ link.key = link.getAttribute('href').replace(window.location.href.split('#')[0],'').split('#').last().replace(/#/,'');
+ var container = $(link.key);
+ if(!container) {
+ throw "Control.Tabs: #" + link.key + " was not found on the page."; }
+ this.containers.set(link.key,container);
+ link[this.options.hover ? 'onmouseover' : 'onclick'] = function(link){
+ if(window.event) {
+ Event.stop(window.event); }
+ this.setActiveTab(link);
+ return false;
+ }.bind(this,link);
+ },
+ setActiveTab: function(link){
+ if(!link && typeof(link) == 'undefined') {
+ return; }
+ if(typeof(link) == 'string'){
+ this.setActiveTab(this.links.find(function(_link){
+ return _link.key == link;
+ }));
+ }else if(typeof(link) == 'number'){
+ this.setActiveTab(this.links[link]);
+ }else{
+ if(this.notify('beforeChange',this.activeContainer,this.containers.get(link.key)) === false) {
+ return; }
+ if(this.activeContainer) {
+ this.options.hideFunction(this.activeContainer); }
+ this.links.each(function(item){
+ (this.options.setClassOnContainer ? $(item.parentNode) : item).removeClassName(this.options.activeClassName);
+ }.bind(this));
+ (this.options.setClassOnContainer ? $(link.parentNode) : link).addClassName(this.options.activeClassName);
+ this.activeContainer = this.containers.get(link.key);
+ this.activeLink = link;
+ this.options.showFunction(this.containers.get(link.key));
+ this.notify('afterChange',this.containers.get(link.key));
+ }
+ },
+ next: function(){
+ this.links.each(function(link,i){
+ if(this.activeLink == link && this.links[i + 1]){
+ this.setActiveTab(this.links[i + 1]);
+ throw $break;
+ }
+ }.bind(this));
+ },
+ previous: function(){
+ this.links.each(function(link,i){
+ if(this.activeLink == link && this.links[i - 1]){
+ this.setActiveTab(this.links[i - 1]);
+ throw $break;
+ }
+ }.bind(this));
+ },
+ first: function(){
+ this.setActiveTab(this.links.first());
+ },
+ last: function(){
+ this.setActiveTab(this.links.last());
+ }
+});
+Object.extend(Control.Tabs,{
+ instances: [],
+ findByTabId: function(id){
+ return Control.Tabs.instances.find(function(tab){
+ return tab.links.find(function(link){
+ return link.key == id;
+ });
+ });
+ }
+});
+Object.Event.extend(Control.Tabs);