summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorelijah <elijah@riseup.net>2012-08-24 21:12:36 -0700
committerelijah <elijah@riseup.net>2012-08-24 21:12:36 -0700
commit627f0488e5bd3c31359fc9e78acffbfea4a86a8b (patch)
treef7b14733e314cf82d5fa3e18cbe9d98c2ffe5c7c /app
parentb774dea07f97b078fa17e5dcbf901d1c83fed0d6 (diff)
committed website v. 0.1.0
Diffstat (limited to 'app')
-rw-r--r--app/assets/images/rails.pngbin0 -> 6646 bytes
-rw-r--r--app/assets/javascripts/application.js15
-rw-r--r--app/assets/stylesheets/README23
-rw-r--r--app/assets/stylesheets/application.scss33
-rw-r--r--app/assets/stylesheets/bootstrap.scss58
-rw-r--r--app/assets/stylesheets/bootstrap/README11
-rw-r--r--app/assets/stylesheets/bootstrap/_accordion.scss28
-rw-r--r--app/assets/stylesheets/bootstrap/_alerts.scss70
-rw-r--r--app/assets/stylesheets/bootstrap/_breadcrumbs.scss22
-rw-r--r--app/assets/stylesheets/bootstrap/_button-groups.scss147
-rw-r--r--app/assets/stylesheets/bootstrap/_buttons.scss183
-rw-r--r--app/assets/stylesheets/bootstrap/_carousel.scss121
-rw-r--r--app/assets/stylesheets/bootstrap/_close.scss18
-rw-r--r--app/assets/stylesheets/bootstrap/_code.scss57
-rw-r--r--app/assets/stylesheets/bootstrap/_component-animations.scss18
-rw-r--r--app/assets/stylesheets/bootstrap/_dropdowns.scss130
-rw-r--r--app/assets/stylesheets/bootstrap/_forms.scss522
-rw-r--r--app/assets/stylesheets/bootstrap/_grid.scss8
-rw-r--r--app/assets/stylesheets/bootstrap/_hero-unit.scss20
-rw-r--r--app/assets/stylesheets/bootstrap/_labels.scss32
-rw-r--r--app/assets/stylesheets/bootstrap/_layouts.scss17
-rw-r--r--app/assets/stylesheets/bootstrap/_mixins.scss578
-rw-r--r--app/assets/stylesheets/bootstrap/_modals.scss84
-rw-r--r--app/assets/stylesheets/bootstrap/_navbar.scss299
-rw-r--r--app/assets/stylesheets/bootstrap/_navs.scss353
-rw-r--r--app/assets/stylesheets/bootstrap/_pager.scss30
-rw-r--r--app/assets/stylesheets/bootstrap/_pagination.scss55
-rw-r--r--app/assets/stylesheets/bootstrap/_popovers.scss49
-rw-r--r--app/assets/stylesheets/bootstrap/_progress-bars.scss95
-rw-r--r--app/assets/stylesheets/bootstrap/_reset.scss126
-rw-r--r--app/assets/stylesheets/bootstrap/_scaffolding.scss33
-rw-r--r--app/assets/stylesheets/bootstrap/_sprites.scss158
-rw-r--r--app/assets/stylesheets/bootstrap/_tables.scss150
-rw-r--r--app/assets/stylesheets/bootstrap/_thumbnails.scss35
-rw-r--r--app/assets/stylesheets/bootstrap/_tooltip.scss35
-rw-r--r--app/assets/stylesheets/bootstrap/_type.scss218
-rw-r--r--app/assets/stylesheets/bootstrap/_utilities.scss23
-rw-r--r--app/assets/stylesheets/bootstrap/_variables.scss107
-rw-r--r--app/assets/stylesheets/bootstrap/_wells.scss17
-rw-r--r--app/assets/stylesheets/bootstrap/bootstrap.scss66
-rw-r--r--app/assets/stylesheets/bootstrap/responsive.scss337
-rw-r--r--app/assets/stylesheets/leap.scss176
-rw-r--r--app/assets/stylesheets/mixins.scss172
-rw-r--r--app/assets/stylesheets/superfluid.scss113
-rw-r--r--app/assets/stylesheets/typography.scss33
-rw-r--r--app/controllers/application_controller.rb88
-rw-r--r--app/controllers/pages_controller.rb29
-rw-r--r--app/controllers/root_controller.rb11
-rw-r--r--app/helpers/application_helper.rb91
-rw-r--r--app/helpers/blog_helper.rb15
-rw-r--r--app/helpers/haml_helper.rb54
-rw-r--r--app/helpers/navigation_helper.rb84
-rw-r--r--app/mailers/.gitkeep0
-rw-r--r--app/models/.gitkeep0
-rw-r--r--app/views/errors/error.html.haml3
-rw-r--r--app/views/errors/not_found.html.haml3
-rw-r--r--app/views/layouts/_footer.haml7
-rw-r--r--app/views/layouts/_masthead.html.haml7
-rw-r--r--app/views/layouts/_topnav.html.haml8
-rw-r--r--app/views/layouts/application.html.haml29
-rw-r--r--app/views/layouts/blog.html.haml6
-rw-r--r--app/views/layouts/blog/_summary.html.haml17
-rw-r--r--app/views/layouts/blog/show.html.haml20
-rw-r--r--app/views/pages/about-us/contact/en.haml32
-rw-r--r--app/views/pages/about-us/en.haml1
-rw-r--r--app/views/pages/about-us/news/2012/en.haml1
-rw-r--r--app/views/pages/about-us/news/2012/first-post/en.haml10
-rw-r--r--app/views/pages/about-us/news/en.haml2
-rw-r--r--app/views/pages/about-us/partners/en.haml9
-rw-r--r--app/views/pages/about-us/vision/en.haml26
-rw-r--r--app/views/pages/development/en.haml68
-rw-r--r--app/views/pages/home/en.haml61
-rw-r--r--app/views/pages/menu.txt24
-rw-r--r--app/views/pages/services/chat/en.haml27
-rw-r--r--app/views/pages/services/eip/en.haml62
-rw-r--r--app/views/pages/services/email/en.haml22
-rw-r--r--app/views/pages/services/en.haml17
-rw-r--r--app/views/pages/technology/client/en.haml107
-rw-r--r--app/views/pages/technology/critiques/en.haml57
-rw-r--r--app/views/pages/technology/en.haml30
-rw-r--r--app/views/pages/technology/identity/en.haml45
-rw-r--r--app/views/pages/technology/infosec/en.haml101
-rw-r--r--app/views/pages/technology/infosec/table-style.haml59
-rw-r--r--app/views/pages/technology/infosec/table.haml233
-rw-r--r--app/views/pages/technology/platform/en.haml16
-rw-r--r--app/views/pages/technology/routing/en.haml52
86 files changed, 6409 insertions, 0 deletions
diff --git a/app/assets/images/rails.png b/app/assets/images/rails.png
new file mode 100644
index 0000000..d5edc04
--- /dev/null
+++ b/app/assets/images/rails.png
Binary files differ
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
new file mode 100644
index 0000000..9097d83
--- /dev/null
+++ b/app/assets/javascripts/application.js
@@ -0,0 +1,15 @@
+// This is a manifest file that'll be compiled into application.js, which will include all the files
+// listed below.
+//
+// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
+// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
+//
+// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
+// the compiled file.
+//
+// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
+// GO AFTER THE REQUIRES BELOW.
+//
+//= require jquery
+//= require jquery_ujs
+//= require_tree .
diff --git a/app/assets/stylesheets/README b/app/assets/stylesheets/README
new file mode 100644
index 0000000..2865272
--- /dev/null
+++ b/app/assets/stylesheets/README
@@ -0,0 +1,23 @@
+The stylesheets we use are based on bootstrap, with some significant changes:
+
+(1) We do not use bootstrap layout. Instead, see superfluid.scss
+
+(2) We do use the fluid grid system of bootstrap, but not the fixed grid system.
+
+ For example, this is valid:
+
+ <div class="row-fluid">
+ <div class="span12">
+ Level 1 of column
+ <div class="row-fluid">
+ <div class="span6">Level 2</div>
+ <div class="span6">Level 2</div>
+ </div>
+ </div>
+ </div>
+
+ but <div class="row"> is not supported
+
+ we keep the default of twelve columns.
+
+(3) see app/assets/stylesheets/bootstrap.scss for the custom ways we partially include bootstrap. \ No newline at end of file
diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss
new file mode 100644
index 0000000..144bcf2
--- /dev/null
+++ b/app/assets/stylesheets/application.scss
@@ -0,0 +1,33 @@
+//
+// VARIABLES
+//
+
+$baseFontSize: 14px;
+$baseFontFamily: "Helvetica Neue", Helvetica, Arial, sans-serif !default;
+$baseLineHeight: 22px;
+
+// Default 940px grid
+$gridColumns: 12 !default;
+$gridColumnWidth: 60px !default;
+$gridGutterWidth: 20px !default;
+$gridRowWidth: ($gridColumns * $gridColumnWidth) + ($gridGutterWidth * ($gridColumns - 1));
+
+// Fluid grid
+$fluidGridColumnWidth: 6.382978723% !default;
+$fluidGridGutterWidth: 2.127659574% !default;
+
+//
+// IMPORT LIBRARIES
+//
+
+@import "bootstrap";
+@import "superfluid";
+
+//
+// IMPORT LOCAL SCSS
+//
+
+@import "mixins";
+@import "typography";
+@import "leap";
+
diff --git a/app/assets/stylesheets/bootstrap.scss b/app/assets/stylesheets/bootstrap.scss
new file mode 100644
index 0000000..0ba3b62
--- /dev/null
+++ b/app/assets/stylesheets/bootstrap.scss
@@ -0,0 +1,58 @@
+//
+// this is a modified bootstrap.scss that only includes some parts of bootstrap.
+// see bootstrap/bootstrap.scss for the full deal.
+//
+
+// Core variables and mixins
+@import "bootstrap/variables"; // Modify this for custom colors, font-sizes, etc
+@import "bootstrap/mixins";
+
+// CSS Reset
+@import "bootstrap/reset";
+
+// Grid system and page structure
+@import "bootstrap/scaffolding";
+@import "bootstrap/grid";
+@import "bootstrap/responsive";
+//@import "bootstrap/layouts";
+
+// Base CSS
+@import "bootstrap/type";
+@import "bootstrap/code";
+@import "bootstrap/forms";
+@import "bootstrap/tables";
+
+// Components: common
+@import "bootstrap/sprites";
+@import "bootstrap/dropdowns";
+//@import "bootstrap/wells";
+@import "bootstrap/component-animations";
+@import "bootstrap/close";
+
+// Components: Buttons & Alerts
+@import "bootstrap/buttons";
+@import "bootstrap/button-groups";
+@import "bootstrap/alerts"; // Note: alerts share common CSS with buttons and thus have styles in buttons.scss
+
+// Components: Nav
+@import "bootstrap/navs";
+//@import "bootstrap/navbar";
+//@import "bootstrap/breadcrumbs";
+//@import "bootstrap/pagination";
+//@import "bootstrap/pager";
+
+// Components: Popovers
+@import "bootstrap/modals";
+@import "bootstrap/tooltip";
+@import "bootstrap/popovers";
+
+// Components: Misc
+@import "bootstrap/thumbnails";
+@import "bootstrap/labels";
+@import "bootstrap/progress-bars";
+@import "bootstrap/accordion";
+@import "bootstrap/carousel";
+@import "bootstrap/hero-unit";
+
+// Utility classes
+@import "bootstrap/utilities"; // Has to be last to override when necessary
diff --git a/app/assets/stylesheets/bootstrap/README b/app/assets/stylesheets/bootstrap/README
new file mode 100644
index 0000000..521c306
--- /dev/null
+++ b/app/assets/stylesheets/bootstrap/README
@@ -0,0 +1,11 @@
+Eventually, we want to migrate more of the CSS over to using "Bootstrap"
+
+ http://twitter.github.com/bootstrap
+
+In this directories is a copy of bootstrap converted to SCSS:
+
+ https://github.com/jlong/sass-twitter-bootstrap
+
+To update the files in this directory, run this command (in this directory!)
+
+ curl https://nodeload.github.com/jlong/sass-twitter-bootstrap/tarball/master | tar -vxz --transform 's/.*lib\///' --overwrite --wildcards '*/lib/*.scss' \ No newline at end of file
diff --git a/app/assets/stylesheets/bootstrap/_accordion.scss b/app/assets/stylesheets/bootstrap/_accordion.scss
new file mode 100644
index 0000000..311fa85
--- /dev/null
+++ b/app/assets/stylesheets/bootstrap/_accordion.scss
@@ -0,0 +1,28 @@
+// ACCORDION
+// ---------
+
+
+// Parent container
+.accordion {
+ margin-bottom: $baseLineHeight;
+}
+
+// Group == heading + body
+.accordion-group {
+ margin-bottom: 2px;
+ border: 1px solid #e5e5e5;
+ @include border-radius(4px);
+}
+.accordion-heading {
+ border-bottom: 0;
+}
+.accordion-heading .accordion-toggle {
+ display: block;
+ padding: 8px 15px;
+}
+
+// Inner needs the styles because you can't animate properly with any styles on the element
+.accordion-inner {
+ padding: 9px 15px;
+ border-top: 1px solid #e5e5e5;
+}
diff --git a/app/assets/stylesheets/bootstrap/_alerts.scss b/app/assets/stylesheets/bootstrap/_alerts.scss
new file mode 100644
index 0000000..4c4b9e7
--- /dev/null
+++ b/app/assets/stylesheets/bootstrap/_alerts.scss
@@ -0,0 +1,70 @@
+// ALERT STYLES
+// ------------
+
+// Base alert styles
+.alert {
+ padding: 8px 35px 8px 14px;
+ margin-bottom: $baseLineHeight;
+ text-shadow: 0 1px 0 rgba(255,255,255,.5);
+ background-color: $warningBackground;
+ border: 1px solid $warningBorder;
+ @include border-radius(4px);
+}
+.alert,
+.alert-heading {
+ color: $warningText;
+}
+
+// Adjust close link position
+.alert .close {
+ position: relative;
+ top: -2px;
+ right: -21px;
+ line-height: 18px;
+}
+
+// Alternate styles
+// ----------------
+
+.alert-success {
+ background-color: $successBackground;
+ border-color: $successBorder;
+}
+.alert-success,
+.alert-success .alert-heading {
+ color: $successText;
+}
+.alert-danger,
+.alert-error {
+ background-color: $errorBackground;
+ border-color: $errorBorder;
+}
+.alert-danger,
+.alert-error,
+.alert-danger .alert-heading,
+.alert-error .alert-heading {
+ color: $errorText;
+}
+.alert-info {
+ background-color: $infoBackground;
+ border-color: $infoBorder;
+}
+.alert-info,
+.alert-info .alert-heading {
+ color: $infoText;
+}
+
+
+// Block alerts
+// ------------------------
+.alert-block {
+ padding-top: 14px;
+ padding-bottom: 14px;
+}
+.alert-block > p,
+.alert-block > ul {
+ margin-bottom: 0;
+}
+.alert-block p + p {
+ margin-top: 5px;
+}
diff --git a/app/assets/stylesheets/bootstrap/_breadcrumbs.scss b/app/assets/stylesheets/bootstrap/_breadcrumbs.scss
new file mode 100644
index 0000000..3d47d25
--- /dev/null
+++ b/app/assets/stylesheets/bootstrap/_breadcrumbs.scss
@@ -0,0 +1,22 @@
+// BREADCRUMBS
+// -----------
+
+.breadcrumb {
+ padding: 7px 14px;
+ margin: 0 0 $baseLineHeight;
+ @include gradient-vertical($white, #f5f5f5);
+ border: 1px solid #ddd;
+ @include border-radius(3px);
+ @include box-shadow(inset 0 1px 0 $white);
+ li {
+ display: inline-block;
+ text-shadow: 0 1px 0 $white;
+ }
+ .divider {
+ padding: 0 5px;
+ color: $grayLight;
+ }
+ .active a {
+ color: $grayDark;
+ }
+}
diff --git a/app/assets/stylesheets/bootstrap/_button-groups.scss b/app/assets/stylesheets/bootstrap/_button-groups.scss
new file mode 100644
index 0000000..7b573eb
--- /dev/null
+++ b/app/assets/stylesheets/bootstrap/_button-groups.scss
@@ -0,0 +1,147 @@
+// BUTTON GROUPS
+// -------------
+
+
+// Make the div behave like a button
+.btn-group {
+ position: relative;
+ @include clearfix(); // clears the floated buttons
+ @include ie7-restore-left-whitespace();
+}
+
+// Space out series of button groups
+.btn-group + .btn-group {
+ margin-left: 5px;
+}
+
+// Optional: Group multiple button groups together for a toolbar
+.btn-toolbar {
+ margin-top: $baseLineHeight / 2;
+ margin-bottom: $baseLineHeight / 2;
+ .btn-group {
+ display: inline-block;
+ @include ie7-inline-block();
+ }
+}
+
+// Float them, remove border radius, then re-add to first and last elements
+.btn-group .btn {
+ position: relative;
+ float: left;
+ margin-left: -1px;
+ @include border-radius(0);
+}
+// Set corners individual because sometimes a single button can be in a .btn-group and we need :first-child and :last-child to both match
+.btn-group .btn:first-child {
+ margin-left: 0;
+ -webkit-border-top-left-radius: 4px;
+ -moz-border-radius-topleft: 4px;
+ border-top-left-radius: 4px;
+ -webkit-border-bottom-left-radius: 4px;
+ -moz-border-radius-bottomleft: 4px;
+ border-bottom-left-radius: 4px;
+}
+.btn-group .btn:last-child,
+.btn-group .dropdown-toggle {
+ -webkit-border-top-right-radius: 4px;
+ -moz-border-radius-topright: 4px;
+ border-top-right-radius: 4px;
+ -webkit-border-bottom-right-radius: 4px;
+ -moz-border-radius-bottomright: 4px;
+ border-bottom-right-radius: 4px;
+}
+// Reset corners for large buttons
+.btn-group .btn.large:first-child {
+ margin-left: 0;
+ -webkit-border-top-left-radius: 6px;
+ -moz-border-radius-topleft: 6px;
+ border-top-left-radius: 6px;
+ -webkit-border-bottom-left-radius: 6px;
+ -moz-border-radius-bottomleft: 6px;
+ border-bottom-left-radius: 6px;
+}
+.btn-group .btn.large:last-child,
+.btn-group .large.dropdown-toggle {
+ -webkit-border-top-right-radius: 6px;
+ -moz-border-radius-topright: 6px;
+ border-top-right-radius: 6px;
+ -webkit-border-bottom-right-radius: 6px;
+ -moz-border-radius-bottomright: 6px;
+ border-bottom-right-radius: 6px;
+}
+
+// On hover/focus/active, bring the proper btn to front
+.btn-group .btn:hover,
+.btn-group .btn:focus,
+.btn-group .btn:active,
+.btn-group .btn.active {
+ z-index: 2;
+}
+
+// On active and open, don't show outline
+.btn-group .dropdown-toggle:active,
+.btn-group.open .dropdown-toggle {
+ outline: 0;
+}
+
+
+
+// Split button dropdowns
+// ----------------------
+
+// Give the line between buttons some depth
+.btn-group .dropdown-toggle {
+ padding-left: 8px;
+ padding-right: 8px;
+ $shadow: inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);
+ @include box-shadow($shadow);
+ *padding-top: 5px;
+ *padding-bottom: 5px;
+}
+
+.btn-group.open {
+ // IE7's z-index only goes to the nearest positioned ancestor, which would
+ // make the menu appear below buttons that appeared later on the page
+ *z-index: $zindexDropdown;
+
+ // Reposition menu on open and round all corners
+ .dropdown-menu {
+ display: block;
+ margin-top: 1px;
+ @include border-radius(5px);
+ }
+
+ .dropdown-toggle {
+ background-image: none;
+ $shadow: inset 0 1px 6px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);
+ @include box-shadow($shadow);
+ }
+}
+
+// Reposition the caret
+.btn .caret {
+ margin-top: 7px;
+ margin-left: 0;
+}
+.btn:hover .caret,
+.open.btn-group .caret {
+ @include opacity(100);
+}
+
+
+// Account for other colors
+.btn-primary,
+.btn-danger,
+.btn-info,
+.btn-success,
+.btn-inverse {
+ .caret {
+ border-top-color: $white;
+ @include opacity(75);
+ }
+}
+
+// Small button dropdowns
+.btn-small .caret {
+ margin-top: 4px;
+}
diff --git a/app/assets/stylesheets/bootstrap/_buttons.scss b/app/assets/stylesheets/bootstrap/_buttons.scss
new file mode 100644
index 0000000..d0c4ee6
--- /dev/null
+++ b/app/assets/stylesheets/bootstrap/_buttons.scss
@@ -0,0 +1,183 @@
+// BUTTON STYLES
+// -------------
+
+
+// Base styles
+// --------------------------------------------------
+
+// Core
+.btn {
+ display: inline-block;
+ padding: 4px 10px 4px;
+ margin-bottom: 0; // For input.btn
+ font-size: $baseFontSize;
+ line-height: $baseLineHeight;
+ color: $grayDark;
+ text-align: center;
+ text-shadow: 0 1px 1px rgba(255,255,255,.75);
+ vertical-align: middle;
+ @include buttonBackground($white, darken($white, 10%));
+ border: 1px solid #ccc;
+ border-bottom-color: #bbb;
+ @include border-radius(4px);
+ $shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);
+ @include box-shadow($shadow);
+ cursor: pointer;
+
+ // Give IE7 some love
+ @include reset-filter();
+ @include ie7-restore-left-whitespace();
+}
+
+// Hover state
+.btn:hover {
+ color: $grayDark;
+ text-decoration: none;
+ background-color: darken($white, 10%);
+ background-position: 0 -15px;
+
+ // transition is only when going to hover, otherwise the background
+ // behind the gradient (there for IE<=9 fallback) gets mismatched
+ @include transition(background-position .1s linear);
+}
+
+// Focus state for keyboard and accessibility
+.btn:focus {
+ @include tab-focus();
+}
+
+// Active state
+.btn.active,
+.btn:active {
+ background-image: none;
+ $shadow: inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);
+ @include box-shadow($shadow);
+ background-color: darken($white, 10%);
+ background-color: darken($white, 15%) #{"\9"};
+ outline: 0;
+}
+
+// Disabled state
+.btn.disabled,
+.btn[disabled] {
+ cursor: default;
+ background-image: none;
+ background-color: darken($white, 10%);
+ @include opacity(65);
+ @include box-shadow(none);
+}
+
+
+// Button Sizes
+// --------------------------------------------------
+
+// Large
+.btn-large {
+ padding: 9px 14px;
+ font-size: $baseFontSize + 2px;
+ line-height: normal;
+ @include border-radius(5px);
+}
+.btn-large [class^="icon-"] {
+ margin-top: 1px;
+}
+
+// Small
+.btn-small {
+ padding: 5px 9px;
+ font-size: $baseFontSize - 2px;
+ line-height: $baseLineHeight - 2px;
+}
+.btn-small [class^="icon-"] {
+ margin-top: -1px;
+}
+
+// Mini
+.btn-mini {
+ padding: 2px 6px;
+ font-size: $baseFontSize - 2px;
+ line-height: $baseLineHeight - 4px;
+}
+
+
+// Alternate buttons
+// --------------------------------------------------
+
+// Set text color
+// -------------------------
+.btn-primary,
+.btn-primary:hover,
+.btn-warning,
+.btn-warning:hover,
+.btn-danger,
+.btn-danger:hover,
+.btn-success,
+.btn-success:hover,
+.btn-info,
+.btn-info:hover,
+.btn-inverse,
+.btn-inverse:hover {
+ text-shadow: 0 -1px 0 rgba(0,0,0,.25);
+ color: $white;
+}
+// Provide *some* extra contrast for those who can get it
+.btn-primary.active,
+.btn-warning.active,
+.btn-danger.active,
+.btn-success.active,
+.btn-info.active,
+.btn-dark.active {
+ color: rgba(255,255,255,.75);
+}
+
+// Set the backgrounds
+// -------------------------
+.btn-primary {
+ @include buttonBackground($primaryButtonBackground, adjust-hue($primaryButtonBackground, 20));
+}
+// Warning appears are orange
+.btn-warning {
+ @include buttonBackground(lighten($orange, 15%), $orange);
+}
+// Danger and error appear as red
+.btn-danger {
+ @include buttonBackground(#ee5f5b, #bd362f);
+}
+// Success appears as green
+.btn-success {
+ @include buttonBackground(#62c462, #51a351);
+}
+// Info appears as a neutral blue
+.btn-info {
+ @include buttonBackground(#5bc0de, #2f96b4);
+}
+// Inverse appears as dark gray
+.btn-inverse {
+ @include buttonBackground(#454545, #262626);
+}
+
+
+// Cross-browser Jank
+// --------------------------------------------------
+
+button.btn,
+input[type="submit"].btn {
+
+ // Firefox 3.6 only I believe
+ &::-moz-focus-inner {
+ padding: 0;
+ border: 0;
+ }
+
+ // IE7 has some default padding on button controls
+ *padding-top: 2px;
+ *padding-bottom: 2px;
+ &.large {
+ *padding-top: 7px;
+ *padding-bottom: 7px;
+ }
+ &.small {
+ *padding-top: 3px;
+ *padding-bottom: 3px;
+ }
+}
diff --git a/app/assets/stylesheets/bootstrap/_carousel.scss b/app/assets/stylesheets/bootstrap/_carousel.scss
new file mode 100644
index 0000000..ffba3d0
--- /dev/null
+++ b/app/assets/stylesheets/bootstrap/_carousel.scss
@@ -0,0 +1,121 @@
+// CAROUSEL
+// --------
+
+.carousel {
+ position: relative;
+ margin-bottom: $baseLineHeight;
+ line-height: 1;
+}
+
+.carousel-inner {
+ overflow: hidden;
+ width: 100%;
+ position: relative;
+}
+
+.carousel {
+
+ .item {
+ display: none;
+ position: relative;
+ @include transition(.6s ease-in-out left);
+ }
+
+ // Account for jankitude on images
+ .item > img {
+ display: block;
+ line-height: 1;
+ }
+
+ .active,
+ .next,
+ .prev { display: block; }
+
+ .active {
+ left: 0;
+ }
+
+ .next,
+ .prev {
+ position: absolute;
+ top: 0;
+ width: 100%;
+ }
+
+ .next {
+ left: 100%;
+ }
+ .prev {
+ left: -100%;
+ }
+ .next.left,
+ .prev.right {
+ left: 0;
+ }
+
+ .active.left {
+ left: -100%;
+ }
+ .active.right {
+ left: 100%;
+ }
+
+}
+
+// Left/right controls for nav
+// ---------------------------
+
+.carousel-control {
+ position: absolute;
+ top: 40%;
+ left: 15px;
+ width: 40px;
+ height: 40px;
+ margin-top: -20px;
+ font-size: 60px;
+ font-weight: 100;
+ line-height: 30px;
+ color: $white;
+ text-align: center;
+ background: $grayDarker;
+ border: 3px solid $white;
+ @include border-radius(23px);
+ @include opacity(50);
+
+ // we can't have this transition here
+ // because webkit cancels the carousel
+ // animation if you trip this while
+ // in the middle of another animation
+ // ;_;
+ // .transition(opacity .2s linear);
+
+ // Reposition the right one
+ &.right {
+ left: auto;
+ right: 15px;
+ }
+
+ // Hover state
+ &:hover {
+ color: $white;
+ text-decoration: none;
+ @include opacity(90);
+ }
+}
+
+// Caption for text below images
+// -----------------------------
+
+.carousel-caption {
+ position: absolute;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ padding: 10px 15px 5px;
+ background: $grayDark;
+ background: rgba(0,0,0,.75);
+}
+.carousel-caption h4,
+.carousel-caption p {
+ color: $white;
+}
diff --git a/app/assets/stylesheets/bootstrap/_close.scss b/app/assets/stylesheets/bootstrap/_close.scss
new file mode 100644
index 0000000..5d31836
--- /dev/null
+++ b/app/assets/stylesheets/bootstrap/_close.scss
@@ -0,0 +1,18 @@
+// CLOSE ICONS
+// -----------
+
+.close {
+ float: right;
+ font-size: 20px;
+ font-weight: bold;
+ line-height: $baseLineHeight;
+ color: $black;
+ text-shadow: 0 1px 0 rgba(255,255,255,1);
+ @include opacity(20);
+ &:hover {
+ color: $black;
+ text-decoration: none;
+ @include opacity(40);
+ cursor: pointer;
+ }
+}
diff --git a/app/assets/stylesheets/bootstrap/_code.scss b/app/assets/stylesheets/bootstrap/_code.scss
new file mode 100644
index 0000000..546a0b9
--- /dev/null
+++ b/app/assets/stylesheets/bootstrap/_code.scss
@@ -0,0 +1,57 @@
+// Code.scss
+// Code typography styles for the <code> and <pre> elements
+// --------------------------------------------------------
+
+// Inline and block code styles
+code,
+pre {
+ padding: 0 3px 2px;
+ @include font-family-monospace;
+ font-size: $baseFontSize - 1;
+ color: $grayDark;
+ @include border-radius(3px);
+}
+
+// Inline code
+code {
+ padding: 3px 4px;
+ color: #d14;
+ background-color: #f7f7f9;
+ border: 1px solid #e1e1e8;
+}
+
+// Blocks of code
+pre {
+ display: block;
+ padding: ($baseLineHeight - 1) / 2;
+ margin: 0 0 $baseLineHeight / 2;
+ font-size: 12px;
+ line-height: $baseLineHeight;
+ background-color: #f5f5f5;
+ border: 1px solid #ccc; // fallback for IE7-8
+ border: 1px solid rgba(0,0,0,.15);
+ @include border-radius(4px);
+ white-space: pre;
+ white-space: pre-wrap;
+ word-break: break-all;
+ word-wrap: break-word;
+
+ // Make prettyprint styles more spaced out for readability
+ &.prettyprint {
+ margin-bottom: $baseLineHeight;
+ }
+
+ // Account for some code outputs that place code tags in pre tags
+ code {
+ padding: 0;
+ color: inherit;
+ background-color: transparent;
+ border: 0;
+ }
+}
+
+// Enable scrollable blocks of code
+.pre-scrollable {
+ max-height: 340px;
+ overflow-y: scroll;
+}
diff --git a/app/assets/stylesheets/bootstrap/_component-animations.scss b/app/assets/stylesheets/bootstrap/_component-animations.scss
new file mode 100644
index 0000000..d985b6a
--- /dev/null
+++ b/app/assets/stylesheets/bootstrap/_component-animations.scss
@@ -0,0 +1,18 @@
+// COMPONENT ANIMATIONS
+// --------------------
+
+.fade {
+ @include transition(opacity .15s linear);
+ opacity: 0;
+ &.in {
+ opacity: 1;
+ }
+}
+
+.collapse {
+ @include transition(height .35s ease);
+ position:relative;
+ overflow:hidden;
+ height: 0;
+ &.in { height: auto; }
+}
diff --git a/app/assets/stylesheets/bootstrap/_dropdowns.scss b/app/assets/stylesheets/bootstrap/_dropdowns.scss
new file mode 100644
index 0000000..87b9efe
--- /dev/null
+++ b/app/assets/stylesheets/bootstrap/_dropdowns.scss
@@ -0,0 +1,130 @@
+// DROPDOWN MENUS
+// --------------
+
+// Use the .menu class on any <li> element within the topbar or ul.tabs and you'll get some superfancy dropdowns
+.dropdown {
+ position: relative;
+}
+.dropdown-toggle {
+ // The caret makes the toggle a bit too tall in IE7
+ *margin-bottom: -3px;
+}
+.dropdown-toggle:active,
+.open .dropdown-toggle {
+ outline: 0;
+}
+// Dropdown arrow/caret
+.caret {
+ display: inline-block;
+ width: 0;
+ height: 0;
+ text-indent: -99999px;
+ // IE7 won't do the border trick if there's a text indent, but it doesn't
+ // do the content that text-indent is hiding, either, so we're ok.
+ *text-indent: 0;
+ vertical-align: top;
+ border-left: 4px solid transparent;
+ border-right: 4px solid transparent;
+ border-top: 4px solid $black;
+ @include opacity(30);
+ content: "\2193";
+}
+.dropdown .caret {
+ margin-top: 8px;
+ margin-left: 2px;
+}
+.dropdown:hover .caret,
+.open.dropdown .caret {
+ @include opacity(100);
+}
+// The dropdown menu (ul)
+.dropdown-menu {
+ position: absolute;
+ top: 100%;
+ left: 0;
+ z-index: $zindexDropdown;
+ float: left;
+ display: none; // none by default, but block on "open" of the menu
+ min-width: 160px;
+ _width: 160px;
+ padding: 4px 0;
+ margin: 0; // override default ul
+ list-style: none;
+ background-color: $white;
+ border-color: #ccc;
+ border-color: rgba(0,0,0,.2);
+ border-style: solid;
+ border-width: 1px;
+ @include border-radius(0 0 5px 5px);
+ @include box-shadow(0 5px 10px rgba(0,0,0,.2));
+ -webkit-background-clip: padding-box;
+ -moz-background-clip: padding;
+ background-clip: padding-box;
+ *border-right-width: 2px;
+ *border-bottom-width: 2px;
+
+ // Allow for dropdowns to go bottom up (aka, dropup-menu)
+ &.bottom-up {
+ top: auto;
+ bottom: 100%;
+ margin-bottom: 2px;
+ }
+
+ // Dividers (basically an hr) within the dropdown
+ .divider {
+ height: 1px;
+ margin: 5px 1px;
+ overflow: hidden;
+ background-color: #e5e5e5;
+ border-bottom: 1px solid $white;
+
+ // IE7 needs a set width since we gave a height. Restricting just
+ // to IE7 to keep the 1px left/right space in other browsers.
+ // It is unclear where IE is getting the extra space that we need
+ // to negative-margin away, but so it goes.
+ *width: 100%;
+ *margin: -5px 0 5px;
+ }
+
+ // Links within the dropdown menu
+ a {
+ display: block;
+ padding: 3px 15px;
+ clear: both;
+ font-weight: normal;
+ line-height: $baseLineHeight;
+ color: $gray;
+ white-space: nowrap;
+ }
+}
+
+// Hover state
+.dropdown-menu li > a:hover,
+.dropdown-menu .active > a,
+.dropdown-menu .active > a:hover {
+ color: $white;
+ text-decoration: none;
+ background-color: $linkColor;
+}
+
+// Open state for the dropdown
+.dropdown.open {
+ // IE7's z-index only goes to the nearest positioned ancestor, which would
+ // make the menu appear below buttons that appeared later on the page
+ *z-index: $zindexDropdown;
+
+ .dropdown-toggle {
+ color: $white;
+ background: #ccc;
+ background: rgba(0,0,0,.3);
+ }
+ .dropdown-menu {
+ display: block;
+ }
+}
+
+// Typeahead
+.typeahead {
+ margin-top: 2px; // give it some space to breathe
+ @include border-radius(4px);
+}
diff --git a/app/assets/stylesheets/bootstrap/_forms.scss b/app/assets/stylesheets/bootstrap/_forms.scss
new file mode 100644
index 0000000..b2033f7
--- /dev/null
+++ b/app/assets/stylesheets/bootstrap/_forms.scss
@@ -0,0 +1,522 @@
+// Forms.scss
+// Base styles for various input types, form layouts, and states
+// -------------------------------------------------------------
+
+
+// GENERAL STYLES
+// --------------
+
+// Make all forms have space below them
+form {
+ margin: 0 0 $baseLineHeight;
+}
+
+fieldset {
+ padding: 0;
+ margin: 0;
+ border: 0;
+}
+
+// Groups of fields with labels on top (legends)
+legend {
+ display: block;
+ width: 100%;
+ padding: 0;
+ margin-bottom: $baseLineHeight * 1.5;
+ font-size: $baseFontSize * 1.5;
+ line-height: $baseLineHeight * 2;
+ color: $grayDark;
+ border: 0;
+ border-bottom: 1px solid #eee;
+
+ // Small
+ small {
+ font-size: $baseLineHeight * .75;
+ color: $grayLight;
+ }
+}
+
+// Set font for forms
+label,
+input,
+button,
+select,
+textarea {
+ @include font-shorthand(); // Set size, weight, line-height here
+}
+input,
+button,
+select,
+textarea {
+ @include font-family-sans-serif(); // And only set font-family here for those that need it (note the missing label element)
+}
+
+// Identify controls by their labels
+label {
+ display: block;
+ margin-bottom: 5px;
+ color: $grayDark;
+}
+
+// Inputs, Textareas, Selects
+input,
+textarea,
+select,
+.uneditable-input {
+ display: inline-block;
+ width: 210px;
+ height: $baseLineHeight;
+ padding: 4px;
+ margin-bottom: 9px;
+ font-size: $baseFontSize;
+ line-height: $baseLineHeight;
+ color: $gray;
+ border: 1px solid #ccc;
+ @include border-radius(3px);
+}
+.uneditable-textarea {
+ width: auto;
+ height: auto;
+}
+
+// Inputs within a label
+label input,
+label textarea,
+label select {
+ display: block;
+}
+
+// Mini reset for unique input types
+input[type="image"],
+input[type="checkbox"],
+input[type="radio"] {
+ width: auto;
+ height: auto;
+ padding: 0;
+ margin: 3px 0;
+ *margin-top: 0; /* IE7 */
+ line-height: normal;
+ cursor: pointer;
+ @include border-radius(0);
+ border: 0 \9; /* IE9 and down */
+}
+input[type="image"] {
+ border: 0;
+}
+
+// Reset the file input to browser defaults
+input[type="file"] {
+ width: auto;
+ padding: initial;
+ line-height: initial;
+ border: initial;
+ background-color: $white;
+ background-color: initial;
+ @include box-shadow(none);
+}
+
+// Help out input buttons
+input[type="button"],
+input[type="reset"],
+input[type="submit"] {
+ width: auto;
+ height: auto;
+}
+
+// Set the height of select and file controls to match text inputs
+select,
+input[type="file"] {
+ height: 28px; /* In IE7, the height of the select element cannot be changed by height, only font-size */
+ *margin-top: 4px; /* For IE7, add top margin to align select with labels */
+ line-height: 28px;
+}
+
+// Reset line-height for IE
+input[type="file"] {
+ line-height: 18px \9;
+}
+
+// Chrome on Linux and Mobile Safari need background-color
+select {
+ width: 220px; // default input width + 10px of padding that doesn't get applied
+ background-color: $white;
+}
+
+// Make multiple select elements height not fixed
+select[multiple],
+select[size] {
+ height: auto;
+}
+
+// Remove shadow from image inputs
+input[type="image"] {
+ @include box-shadow(none);
+}
+
+// Make textarea height behave
+textarea {
+ height: auto;
+}
+
+// Hidden inputs
+input[type="hidden"] {
+ display: none;
+}
+
+
+
+// CHECKBOXES & RADIOS
+// -------------------
+
+// Indent the labels to position radios/checkboxes as hanging
+.radio,
+.checkbox {
+ padding-left: 18px;
+}
+.radio input[type="radio"],
+.checkbox input[type="checkbox"] {
+ float: left;
+ margin-left: -18px;
+}
+
+// Move the options list down to align with labels
+.controls > .radio:first-child,
+.controls > .checkbox:first-child {
+ padding-top: 5px; // has to be padding because margin collaspes
+}
+
+// Radios and checkboxes on same line
+// TODO v3: Convert .inline to .control-inline
+.radio.inline,
+.checkbox.inline {
+ display: inline-block;
+ padding-top: 5px;
+ margin-bottom: 0;
+ vertical-align: middle;
+}
+.radio.inline + .radio.inline,
+.checkbox.inline + .checkbox.inline {
+ margin-left: 10px; // space out consecutive inline controls
+}
+
+
+
+// FOCUS STATE
+// -----------
+
+input,
+textarea {
+ @include box-shadow(inset 0 1px 1px rgba(0,0,0,.075));
+ $transition: border linear .2s, box-shadow linear .2s;
+ @include transition($transition);
+}
+input:focus,
+textarea:focus {
+ border-color: rgba(82,168,236,.8);
+ $shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);
+ @include box-shadow($shadow);
+ outline: 0;
+ outline: thin dotted \9; /* IE6-9 */
+}
+input[type="file"]:focus,
+input[type="radio"]:focus,
+input[type="checkbox"]:focus,
+select:focus {
+ @include box-shadow(none); // override for file inputs
+ @include tab-focus();
+}
+
+
+
+// INPUT SIZES
+// -----------
+
+// General classes for quick sizes
+.input-mini { width: 60px; }
+.input-small { width: 90px; }
+.input-medium { width: 150px; }
+.input-large { width: 210px; }
+.input-xlarge { width: 270px; }
+.input-xxlarge { width: 530px; }
+
+// Grid style input sizes
+input[class*="span"],
+select[class*="span"],
+textarea[class*="span"],
+.uneditable-input {
+ float: none;
+ margin-left: 0;
+}
+
+
+
+// GRID SIZING FOR INPUTS
+// ----------------------
+
+@include inputGridSystem-generate($gridColumns, $gridColumnWidth, $gridGutterWidth);
+
+
+
+
+// DISABLED STATE
+// --------------
+
+// Disabled and read-only inputs
+input[disabled],
+select[disabled],
+textarea[disabled],
+input[readonly],
+select[readonly],
+textarea[readonly] {
+ background-color: #f5f5f5;
+ border-color: #ddd;
+ cursor: not-allowed;
+}
+
+
+
+
+// FORM FIELD FEEDBACK STATES
+// --------------------------
+
+// Warning
+.control-group.warning {
+ @include formFieldState($warningText, $warningText, $warningBackground);
+}
+// Error
+.control-group.error {
+ @include formFieldState($errorText, $errorText, $errorBackground);
+}
+// Success
+.control-group.success {
+ @include formFieldState($successText, $successText, $successBackground);
+}
+
+// HTML5 invalid states
+// Shares styles with the .control-group.error above
+input:focus:required:invalid,
+textarea:focus:required:invalid,
+select:focus:required:invalid {
+ color: #b94a48;
+ border-color: #ee5f5b;
+ &:focus {
+ border-color: darken(#ee5f5b, 10%);
+ @include box-shadow(0 0 6px lighten(#ee5f5b, 20%));
+ }
+}
+
+
+
+// FORM ACTIONS
+// ------------
+
+.form-actions {
+ padding: ($baseLineHeight - 1) 20px $baseLineHeight;
+ margin-top: $baseLineHeight;
+ margin-bottom: $baseLineHeight;
+ background-color: #f5f5f5;
+ border-top: 1px solid #ddd;
+}
+
+// For text that needs to appear as an input but should not be an input
+.uneditable-input {
+ display: block;
+ background-color: $white;
+ border-color: #eee;
+ @include box-shadow(inset 0 1px 2px rgba(0,0,0,.025));
+ cursor: not-allowed;
+}
+
+// Placeholder text gets special styles; can't be bundled together though for some reason
+@include placeholder($grayLight);
+
+
+
+// HELP TEXT
+// ---------
+
+.help-block {
+ display: block; // account for any element using help-block
+ margin-top: 5px;
+ margin-bottom: 0;
+ color: $grayLight;
+}
+
+.help-inline {
+ display: inline-block;
+ @include ie7-inline-block();
+ margin-bottom: 9px;
+ vertical-align: middle;
+ padding-left: 5px;
+}
+
+
+
+// INPUT GROUPS
+// ------------
+
+// Allow us to put symbols and text within the input field for a cleaner look
+.input-prepend,
+.input-append {
+ margin-bottom: 5px;
+ @include clearfix(); // Clear the float to prevent wrapping
+ input,
+ .uneditable-input {
+ @include border-radius(0 3px 3px 0);
+ &:focus {
+ position: relative;
+ z-index: 2;
+ }
+ }
+ .uneditable-input {
+ border-left-color: #ccc;
+ }
+ .add-on {
+ float: left;
+ display: block;
+ width: auto;
+ min-width: 16px;
+ height: $baseLineHeight;
+ margin-right: -1px;
+ padding: 4px 5px;
+ font-weight: normal;
+ line-height: $baseLineHeight;
+ color: $grayLight;
+ text-align: center;
+ text-shadow: 0 1px 0 $white;
+ background-color: #f5f5f5;
+ border: 1px solid #ccc;
+ @include border-radius(3px 0 0 3px);
+ }
+ .active {
+ background-color: lighten($green, 30);
+ border-color: $green;
+ }
+}
+.input-prepend {
+ .add-on {
+ *margin-top: 1px; /* IE6-7 */
+ }
+}
+.input-append {
+ input,
+ .uneditable-input {
+ float: left;
+ @include border-radius(3px 0 0 3px);
+ }
+ .uneditable-input {
+ border-left-color: #eee;
+ border-right-color: #ccc;
+ }
+ .add-on {
+ margin-right: 0;
+ margin-left: -1px;
+ @include border-radius(0 3px 3px 0);
+ }
+ input:first-child {
+ // In IE7, having a hasLayout container (from clearfix's zoom:1) can make the first input
+ // inherit the sum of its ancestors' margins.
+ *margin-left: -160px;
+
+ &+.add-on {
+ *margin-left: -21px;
+ }
+ }
+}
+
+
+
+// SEARCH FORM
+// -----------
+
+.search-query {
+ padding-left: 14px;
+ padding-right: 14px;
+ margin-bottom: 0; // remove the default margin on all inputs
+ @include border-radius(14px);
+}
+
+
+
+// HORIZONTAL & VERTICAL FORMS
+// ---------------------------
+
+// Common properties
+// -----------------
+
+.form-search,
+.form-inline,
+.form-horizontal {
+ input,
+ textarea,
+ select,
+ .help-inline,
+ .uneditable-input {
+ display: inline-block;
+ margin-bottom: 0;
+ }
+ // Re-hide hidden elements due to specifity
+ .hide {
+ display: none;
+ }
+}
+.form-search label,
+.form-inline label,
+.form-search .input-append,
+.form-inline .input-append,
+.form-search .input-prepend,
+.form-inline .input-prepend {
+ display: inline-block;
+}
+// Make the prepend and append add-on vertical-align: middle;
+.form-search .input-append .add-on,
+.form-inline .input-prepend .add-on,
+.form-search .input-append .add-on,
+.form-inline .input-prepend .add-on {
+ vertical-align: middle;
+}
+// Inline checkbox/radio labels
+.form-search .radio,
+.form-inline .radio,
+.form-search .checkbox,
+.form-inline .checkbox {
+ margin-bottom: 0;
+ vertical-align: middle;
+}
+
+// Margin to space out fieldsets
+.control-group {
+ margin-bottom: $baseLineHeight / 2;
+}
+
+// Legend collapses margin, so next element is responsible for spacing
+legend + .control-group {
+ margin-top: $baseLineHeight;
+ -webkit-margin-top-collapse: separate;
+}
+
+// Horizontal-specific styles
+// --------------------------
+
+.form-horizontal {
+ // Increase spacing between groups
+ .control-group {
+ margin-bottom: $baseLineHeight;
+ @include clearfix();
+ }
+ // Float the labels left
+ .control-label {
+ float: left;
+ width: 140px;
+ padding-top: 5px;
+ text-align: right;
+ }
+ // Move over all input controls and content
+ .controls {
+ margin-left: 160px;
+ }
+ // Move over buttons in .form-actions to align with .controls
+ .form-actions {
+ padding-left: 160px;
+ }
+}
diff --git a/app/assets/stylesheets/bootstrap/_grid.scss b/app/assets/stylesheets/bootstrap/_grid.scss
new file mode 100644
index 0000000..11cc819
--- /dev/null
+++ b/app/assets/stylesheets/bootstrap/_grid.scss
@@ -0,0 +1,8 @@
+// GRID SYSTEM
+// -----------
+
+// Fixed (940px)
+//@include gridSystem-generate($gridColumns, $gridColumnWidth, $gridGutterWidth);
+
+// Fluid (940px)
+@include fluidGridSystem-generate($gridColumns, $fluidGridColumnWidth, $fluidGridGutterWidth);
diff --git a/app/assets/stylesheets/bootstrap/_hero-unit.scss b/app/assets/stylesheets/bootstrap/_hero-unit.scss
new file mode 100644
index 0000000..ef219b2
--- /dev/null
+++ b/app/assets/stylesheets/bootstrap/_hero-unit.scss
@@ -0,0 +1,20 @@
+// HERO UNIT
+// ---------
+
+.hero-unit {
+ padding: 60px;
+ margin-bottom: 30px;
+ background-color: #f5f5f5;
+ @include border-radius(6px);
+ h1 {
+ margin-bottom: 0;
+ font-size: 60px;
+ line-height: 1;
+ letter-spacing: -1px;
+ }
+ p {
+ font-size: 18px;
+ font-weight: 200;
+ line-height: $baseLineHeight * 1.5;
+ }
+}
diff --git a/app/assets/stylesheets/bootstrap/_labels.scss b/app/assets/stylesheets/bootstrap/_labels.scss
new file mode 100644
index 0000000..6a2ed80
--- /dev/null
+++ b/app/assets/stylesheets/bootstrap/_labels.scss
@@ -0,0 +1,32 @@
+// LABELS
+// ------
+
+// Base
+.label {
+ padding: 2px 4px 3px;
+ font-size: $baseFontSize * .85;
+ font-weight: bold;
+ color: $white;
+ text-shadow: 0 -1px 0 rgba(0,0,0,.25);
+ background-color: $grayLight;
+ @include border-radius(3px);
+}
+
+// Hover state
+.label:hover {
+ color: $white;
+ text-decoration: none;
+}
+
+// Colors
+.label-important { background-color: $errorText; }
+.label-important:hover { background-color: darken($errorText, 10%); }
+
+.label-warning { background-color: $orange; }
+.label-warning:hover { background-color: darken($orange, 10%); }
+
+.label-success { background-color: $successText; }
+.label-success:hover { background-color: darken($successText, 10%); }
+
+.label-info { background-color: $infoText; }
+.label-info:hover { background-color: darken($infoText, 10%); }
diff --git a/app/assets/stylesheets/bootstrap/_layouts.scss b/app/assets/stylesheets/bootstrap/_layouts.scss
new file mode 100644
index 0000000..b9bae1d
--- /dev/null
+++ b/app/assets/stylesheets/bootstrap/_layouts.scss
@@ -0,0 +1,17 @@
+//
+// Layouts
+// Fixed-width and fluid (with sidebar) layouts
+// --------------------------------------------
+
+
+// Container (centered, fixed-width layouts)
+.container {
+ @include container-fixed();
+}
+
+// Fluid layouts (left aligned, with sidebar, min- & max-width content)
+.container-fluid {
+ padding-left: $gridGutterWidth;
+ padding-right: $gridGutterWidth;
+ @include clearfix();
+}
diff --git a/app/assets/stylesheets/bootstrap/_mixins.scss b/app/assets/stylesheets/bootstrap/_mixins.scss
new file mode 100644
index 0000000..e437ce3
--- /dev/null
+++ b/app/assets/stylesheets/bootstrap/_mixins.scss
@@ -0,0 +1,578 @@
+// Mixins.scss
+// Snippets of reusable CSS to develop faster and keep code readable
+// -----------------------------------------------------------------
+
+
+// UTILITY MIXINS
+// --------------------------------------------------
+
+// Clearfix
+// --------
+// For clearing floats like a boss h5bp.com/q
+@mixin clearfix() {
+ *zoom: 1;
+ &:before,
+ &:after {
+ display: table;
+ content: "";
+ }
+ &:after {
+ clear: both;
+ }
+}
+
+// Webkit-style focus
+// ------------------
+@mixin tab-focus() {
+ // Default
+ outline: thin dotted #333;
+ // Webkit
+ outline: 5px auto -webkit-focus-ring-color;
+ outline-offset: -2px;
+}
+
+// Center-align a block level element
+// ----------------------------------
+@mixin center-block() {
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+// IE7 inline-block
+// ----------------
+@mixin ie7-inline-block() {
+ *display: inline; /* IE7 inline-block hack */
+ *zoom: 1;
+}
+
+// IE7 likes to collapse whitespace on either side of the inline-block elements.
+// Ems because we're attempting to match the width of a space character. Left
+// version is for form buttons, which typically come after other elements, and
+// right version is for icons, which come before. Applying both is ok, but it will
+// mean that space between those elements will be .6em (~2 space characters) in IE7,
+// instead of the 1 space in other browsers.
+@mixin ie7-restore-left-whitespace() {
+ *margin-left: .3em;
+
+ &:first-child {
+ *margin-left: 0;
+ }
+}
+
+@mixin ie7-restore-right-whitespace() {
+ *margin-right: .3em;
+
+ &:last-child {
+ *margin-left: 0;
+ }
+}
+
+// Sizing shortcuts
+// -------------------------
+@mixin size($height: 5px, $width: 5px) {
+ width: $width;
+ height: $height;
+}
+@mixin square($size: 5px) {
+ @include size($size, $size);
+}
+
+// Placeholder text
+// -------------------------
+@mixin placeholder($color: $placeholderText) {
+ :-moz-placeholder {
+ color: $color;
+ }
+ ::-webkit-input-placeholder {
+ color: $color;
+ }
+}
+
+// Text overflow
+// -------------------------
+// Requires inline-block or block for proper styling
+@mixin text-overflow() {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+
+
+// FONTS
+// --------------------------------------------------
+
+// Font Stacks
+@mixin font-family-serif {
+ font-family: Georgia, "Times New Roman", Times, serif;
+}
+@mixin font-family-sans-serif {
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+}
+@mixin font-family-monospace {
+ font-family: Menlo, Monaco, "Courier New", monospace;
+}
+@mixin font-shorthand($size: $baseFontSize, $weight: normal, $lineHeight: $baseLineHeight) {
+ font-size: $size;
+ font-weight: $weight;
+ line-height: $lineHeight;
+}
+@mixin font-serif($size: $baseFontSize, $weight: normal, $lineHeight: $baseLineHeight) {
+ @include font-family-serif;
+ @include font-shorthand($size, $weight, $lineHeight);
+}
+@mixin font-sans-serif($size: $baseFontSize, $weight: normal, $lineHeight: $baseLineHeight) {
+ @include font-family-sans-serif;
+ @include font-shorthand($size, $weight, $lineHeight);
+}
+@mixin font-monospace($size: $baseFontSize, $weight: normal, $lineHeight: $baseLineHeight) {
+ @include font-family-monospace;
+ @include font-shorthand($size, $weight, $lineHeight);
+}
+
+
+
+// GRID SYSTEM
+// --------------------------------------------------
+
+// Site container
+// -------------------------
+@mixin container-fixed() {
+ width: $gridRowWidth;
+ margin-left: auto;
+ margin-right: auto;
+ @include clearfix();
+}
+
+// Le grid system
+// -------------------------
+@mixin gridSystem-columns ($gridGutterWidth, $gridColumnWidth, $gridRowWidth, $columns) {
+ width: ($gridColumnWidth * $columns) + ($gridGutterWidth * ($columns - 1));
+}
+@mixin gridSystem-offset($gridColumnWidth, $gridGutterWidth, $columns) {
+ margin-left: ($gridColumnWidth * $columns) + ($gridGutterWidth * ($columns - 1)) + ($gridGutterWidth * 2);
+}
+@mixin gridSystem-gridColumn($gridGutterWidth) {
+ float: left;
+ margin-left: $gridGutterWidth;
+}
+
+// Take these values and mixins, and make 'em do their thang
+@mixin gridSystem-generate($gridColumns, $gridColumnWidth, $gridGutterWidth) {
+ // Row surrounds the columns
+ .row {
+ margin-left: $gridGutterWidth * -1;
+ @include clearfix();
+ }
+ // Find all .span# classes within .row and give them the necessary properties for grid columns (supported by all browsers back to IE7, thanks $dhg)
+ [class*="span"] {
+ @include gridSystem-gridColumn($gridGutterWidth);
+ }
+ // Default columns
+ .span1 { @include gridSystem-columns($gridGutterWidth, $gridColumnWidth, $gridRowWidth, 1); }
+ .span2 { @include gridSystem-columns($gridGutterWidth, $gridColumnWidth, $gridRowWidth, 2); }
+ .span3 { @include gridSystem-columns($gridGutterWidth, $gridColumnWidth, $gridRowWidth, 3); }
+ .span4 { @include gridSystem-columns($gridGutterWidth, $gridColumnWidth, $gridRowWidth, 4); }
+ .span5 { @include gridSystem-columns($gridGutterWidth, $gridColumnWidth, $gridRowWidth, 5); }
+ .span6 { @include gridSystem-columns($gridGutterWidth, $gridColumnWidth, $gridRowWidth, 6); }
+ .span7 { @include gridSystem-columns($gridGutterWidth, $gridColumnWidth, $gridRowWidth, 7); }
+ .span8 { @include gridSystem-columns($gridGutterWidth, $gridColumnWidth, $gridRowWidth, 8); }
+ .span9 { @include gridSystem-columns($gridGutterWidth, $gridColumnWidth, $gridRowWidth, 9); }
+ .span10 { @include gridSystem-columns($gridGutterWidth, $gridColumnWidth, $gridRowWidth, 10); }
+ .span11 { @include gridSystem-columns($gridGutterWidth, $gridColumnWidth, $gridRowWidth, 11); }
+ .span12,
+ .container { @include gridSystem-columns($gridGutterWidth, $gridColumnWidth, $gridRowWidth, 12); }
+ // Offset column options
+ .offset1 { @include gridSystem-offset($gridColumnWidth, $gridGutterWidth, 1); }
+ .offset2 { @include gridSystem-offset($gridColumnWidth, $gridGutterWidth, 2); }
+ .offset3 { @include gridSystem-offset($gridColumnWidth, $gridGutterWidth, 3); }
+ .offset4 { @include gridSystem-offset($gridColumnWidth, $gridGutterWidth, 4); }
+ .offset5 { @include gridSystem-offset($gridColumnWidth, $gridGutterWidth, 5); }
+ .offset6 { @include gridSystem-offset($gridColumnWidth, $gridGutterWidth, 6); }
+ .offset7 { @include gridSystem-offset($gridColumnWidth, $gridGutterWidth, 7); }
+ .offset8 { @include gridSystem-offset($gridColumnWidth, $gridGutterWidth, 8); }
+ .offset9 { @include gridSystem-offset($gridColumnWidth, $gridGutterWidth, 9); }
+ .offset10 { @include gridSystem-offset($gridColumnWidth, $gridGutterWidth, 10); }
+ .offset11 { @include gridSystem-offset($gridColumnWidth, $gridGutterWidth, 11); }
+}
+
+// Fluid grid system
+// -------------------------
+@mixin fluidGridSystem-columns($fluidGridGutterWidth, $fluidGridColumnWidth, $columns) {
+ width: ($fluidGridColumnWidth * $columns) + ($fluidGridGutterWidth * ($columns - 1));
+}
+@mixin fluidGridSystem-gridColumn($fluidGridGutterWidth) {
+ float: left;
+ margin-left: $fluidGridGutterWidth;
+}
+// Take these values and mixins, and make 'em do their thang
+@mixin fluidGridSystem-generate($gridColumns, $fluidGridColumnWidth, $fluidGridGutterWidth) {
+ // Row surrounds the columns
+ .row-fluid {
+ width: 100%;
+ @include clearfix();
+
+ // Find all .span# classes within .row and give them the necessary properties for grid columns (supported by all browsers back to IE7, thanks $dhg)
+ > [class*="span"] {
+ @include fluidGridSystem-gridColumn($fluidGridGutterWidth);
+ }
+ > [class*="span"]:first-child {
+ margin-left: 0;
+ }
+ // Default columns
+ > .span1 { @include fluidGridSystem-columns($fluidGridGutterWidth, $fluidGridColumnWidth, 1); }
+ > .span2 { @include fluidGridSystem-columns($fluidGridGutterWidth, $fluidGridColumnWidth, 2); }
+ > .span3 { @include fluidGridSystem-columns($fluidGridGutterWidth, $fluidGridColumnWidth, 3); }
+ > .span4 { @include fluidGridSystem-columns($fluidGridGutterWidth, $fluidGridColumnWidth, 4); }
+ > .span5 { @include fluidGridSystem-columns($fluidGridGutterWidth, $fluidGridColumnWidth, 5); }
+ > .span6 { @include fluidGridSystem-columns($fluidGridGutterWidth, $fluidGridColumnWidth, 6); }
+ > .span7 { @include fluidGridSystem-columns($fluidGridGutterWidth, $fluidGridColumnWidth, 7); }
+ > .span8 { @include fluidGridSystem-columns($fluidGridGutterWidth, $fluidGridColumnWidth, 8); }
+ > .span9 { @include fluidGridSystem-columns($fluidGridGutterWidth, $fluidGridColumnWidth, 9); }
+ > .span10 { @include fluidGridSystem-columns($fluidGridGutterWidth, $fluidGridColumnWidth, 10); }
+ > .span11 { @include fluidGridSystem-columns($fluidGridGutterWidth, $fluidGridColumnWidth, 11); }
+ > .span12 { @include fluidGridSystem-columns($fluidGridGutterWidth, $fluidGridColumnWidth, 12); }
+ }
+}
+
+
+
+// Input grid system
+// -------------------------
+@mixin inputGridSystem-inputColumns($gridGutterWidth, $gridColumnWidth, $gridRowWidth, $columns) {
+ width: (($gridColumnWidth) * $columns) + ($gridGutterWidth * ($columns - 1)) - 10;
+}
+@mixin inputGridSystem-generate($gridColumns, $gridColumnWidth, $gridGutterWidth) {
+ input,
+ textarea,
+ .uneditable-input {
+ &.span1 { @include inputGridSystem-inputColumns($gridGutterWidth, $gridColumnWidth, $gridRowWidth, 1); }
+ &.span2 { @include inputGridSystem-inputColumns($gridGutterWidth, $gridColumnWidth, $gridRowWidth, 2); }
+ &.span3 { @include inputGridSystem-inputColumns($gridGutterWidth, $gridColumnWidth, $gridRowWidth, 3); }
+ &.span4 { @include inputGridSystem-inputColumns($gridGutterWidth, $gridColumnWidth, $gridRowWidth, 4); }
+ &.span5 { @include inputGridSystem-inputColumns($gridGutterWidth, $gridColumnWidth, $gridRowWidth, 5); }
+ &.span6 { @include inputGridSystem-inputColumns($gridGutterWidth, $gridColumnWidth, $gridRowWidth, 6); }
+ &.span7 { @include inputGridSystem-inputColumns($gridGutterWidth, $gridColumnWidth, $gridRowWidth, 7); }
+ &.span8 { @include inputGridSystem-inputColumns($gridGutterWidth, $gridColumnWidth, $gridRowWidth, 8); }
+ &.span9 { @include inputGridSystem-inputColumns($gridGutterWidth, $gridColumnWidth, $gridRowWidth, 9); }
+ &.span10 { @include inputGridSystem-inputColumns($gridGutterWidth, $gridColumnWidth, $gridRowWidth, 10); }
+ &.span11 { @include inputGridSystem-inputColumns($gridGutterWidth, $gridColumnWidth, $gridRowWidth, 11); }
+ &.span12 { @include inputGridSystem-inputColumns($gridGutterWidth, $gridColumnWidth, $gridRowWidth, 12); }
+ }
+}
+
+// Make a Grid
+// -------------------------
+// Use .makeRow and .makeColumn to assign semantic layouts grid system behavior
+@mixin makeRow() {
+ margin-left: $gridGutterWidth * -1;
+ @include clearfix();
+}
+@mixin makeColumn($columns: 1) {
+ float: left;
+ margin-left: $gridGutterWidth;
+ width: ($gridColumnWidth * $columns) + ($gridGutterWidth * ($columns - 1));
+}
+
+
+
+// Form field states (used in forms.scss)
+// --------------------------------------------------
+
+// Mixin for form field states
+@mixin formFieldState($textColor: #555, $borderColor: #ccc, $backgroundColor: #f5f5f5) {
+ // Set the text color
+ > label,
+ .help-block,
+ .help-inline {
+ color: $textColor;
+ }
+ // Style inputs accordingly
+ input,
+ select,
+ textarea {
+ color: $textColor;
+ border-color: $borderColor;
+ &:focus {
+ border-color: darken($borderColor, 10%);
+ @include box-shadow(0 0 6px lighten($borderColor, 20%));
+ }
+ }
+ // Give a small background color for input-prepend/-append
+ .input-prepend .add-on,
+ .input-append .add-on {
+ color: $textColor;
+ background-color: $backgroundColor;
+ border-color: $textColor;
+ }
+}
+
+
+
+// CSS3 PROPERTIES
+// --------------------------------------------------
+
+// Border Radius
+@mixin border-radius($radius: 5px) {
+ -webkit-border-radius: $radius;
+ -moz-border-radius: $radius;
+ border-radius: $radius;
+}
+
+// Drop shadows
+@mixin box-shadow($shadow: 0 1px 3px rgba(0,0,0,.25)) {
+ -webkit-box-shadow: $shadow;
+ -moz-box-shadow: $shadow;
+ box-shadow: $shadow;
+}
+
+// Transitions
+@mixin transition($transition) {
+ -webkit-transition: $transition;
+ -moz-transition: $transition;
+ -ms-transition: $transition;
+ -o-transition: $transition;
+ transition: $transition;
+}
+
+// Transformations
+@mixin rotate($degrees) {
+ -webkit-transform: rotate($degrees);
+ -moz-transform: rotate($degrees);
+ -ms-transform: rotate($degrees);
+ -o-transform: rotate($degrees);
+ transform: rotate($degrees);
+}
+@mixin scale($ratio) {
+ -webkit-transform: scale($ratio);
+ -moz-transform: scale($ratio);
+ -ms-transform: scale($ratio);
+ -o-transform: scale($ratio);
+ transform: scale($ratio);
+}
+@mixin translate($x: 0, $y: 0) {
+ -webkit-transform: translate($x, $y);
+ -moz-transform: translate($x, $y);
+ -ms-transform: translate($x, $y);
+ -o-transform: translate($x, $y);
+ transform: translate($x, $y);
+}
+@mixin skew($x: 0, $y: 0) {
+ -webkit-transform: skew($x, $y);
+ -moz-transform: skew($x, $y);
+ -ms-transform: skew($x, $y);
+ -o-transform: skew($x, $y);
+ transform: skew($x, $y);
+}
+@mixin translate3d($x: 0, $y: 0, $z: 0) {
+ -webkit-transform: translate($x, $y, $z);
+ -moz-transform: translate($x, $y, $z);
+ -ms-transform: translate($x, $y, $z);
+ -o-transform: translate($x, $y, $z);
+ transform: translate($x, $y, $z);
+}
+
+// Background clipping
+// Heads up: FF 3.6 and under need "padding" instead of "padding-box"
+@mixin background-clip($clip) {
+ -webkit-background-clip: $clip;
+ -moz-background-clip: $clip;
+ background-clip: $clip;
+}
+
+// Background sizing
+@mixin background-size($size){
+ -webkit-background-size: $size;
+ -moz-background-size: $size;
+ -o-background-size: $size;
+ background-size: $size;
+}
+
+
+// Box sizing
+@mixin box-sizing($boxmodel) {
+ -webkit-box-sizing: $boxmodel;
+ -moz-box-sizing: $boxmodel;
+ box-sizing: $boxmodel;
+}
+
+// User select
+// For selecting text on the page
+@mixin user-select($select) {
+ -webkit-user-select: $select;
+ -moz-user-select: $select;
+ -o-user-select: $select;
+ user-select: $select;
+}
+
+// Resize anything
+@mixin resizable($direction: both) {
+ resize: $direction; // Options: horizontal, vertical, both
+ overflow: auto; // Safari fix
+}
+
+// CSS3 Content Columns
+@mixin content-columns($columnCount, $columnGap: $gridColumnGutter) {
+ -webkit-column-count: $columnCount;
+ -moz-column-count: $columnCount;
+ column-count: $columnCount;
+ -webkit-column-gap: $columnGap;
+ -moz-column-gap: $columnGap;
+ column-gap: $columnGap;
+}
+
+// Opacity
+@mixin opacity($opacity: 100) {
+ opacity: $opacity / 100;
+ filter: alpha(opacity=$opacity);
+}
+
+
+
+// BACKGROUNDS
+// --------------------------------------------------
+
+// Add an alphatransparency value to any background or border color (via Elyse Holladay)
+@mixin translucent-background($color: $white, $alpha: 1) {
+ background-color: hsla(hue($color), saturation($color), lightness($color), $alpha);
+}
+@mixin translucent-border($color: $white, $alpha: 1) {
+ border-color: hsla(hue($color), saturation($color), lightness($color), $alpha);
+ @include background-clip(padding-box);
+}
+
+
+
+// Gradients
+@mixin gradient-horizontal($startColor: #555, $endColor: #333) {
+ background-color: $endColor;
+ background-image: -moz-linear-gradient(left, $startColor, $endColor); // FF 3.6+
+ background-image: -ms-linear-gradient(left, $startColor, $endColor); // IE10
+ background-image: -webkit-gradient(linear, 0 0, 100% 0, from($startColor), to($endColor)); // Safari 4+, Chrome 2+
+ background-image: -webkit-linear-gradient(left, $startColor, $endColor); // Safari 5.1+, Chrome 10+
+ background-image: -o-linear-gradient(left, $startColor, $endColor); // Opera 11.10
+ background-image: linear-gradient(left, $startColor, $endColor); // Le standard
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#{$startColor}', endColorstr='#{$endColor}', GradientType=1), $startColor, $endColor; // IE9 and down
+}
+@mixin gradient-vertical($startColor: #555, $endColor: #333) {
+ background-color: mix($startColor, $endColor, 60%);
+ background-image: -moz-linear-gradient(top, $startColor, $endColor); // FF 3.6+
+ background-image: -ms-linear-gradient(top, $startColor, $endColor); // IE10
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from($startColor), to($endColor)); // Safari 4+, Chrome 2+
+ background-image: -webkit-linear-gradient(top, $startColor, $endColor); // Safari 5.1+, Chrome 10+
+ background-image: -o-linear-gradient(top, $startColor, $endColor); // Opera 11.10
+ background-image: linear-gradient(top, $startColor, $endColor); // The standard
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#{$startColor}', endColorstr='#{$endColor}', GradientType=0),$startColor,$endColor; // IE9 and down
+}
+@mixin gradient-directional($startColor: #555, $endColor: #333, $deg: 45deg) {
+ background-color: $endColor;
+ background-repeat: repeat-x;
+ background-image: -moz-linear-gradient($deg, $startColor, $endColor); // FF 3.6+
+ background-image: -ms-linear-gradient($deg, $startColor, $endColor); // IE10
+ background-image: -webkit-linear-gradient($deg, $startColor, $endColor); // Safari 5.1+, Chrome 10+
+ background-image: -o-linear-gradient($deg, $startColor, $endColor); // Opera 11.10
+ background-image: linear-gradient($deg, $startColor, $endColor); // The standard
+}
+@mixin gradient-vertical-three-colors($startColor: #00b3ee, $midColor: #7a43b6, $colorStop: 50%, $endColor: #c3325f) {
+ background-color: mix($midColor, $endColor, 80%);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from($startColor), color-stop($colorStop, $midColor), to($endColor));
+ background-image: -webkit-linear-gradient($startColor, $midColor $colorStop, $endColor);
+ background-image: -moz-linear-gradient(top, $startColor, $midColor $colorStop, $endColor);
+ background-image: -ms-linear-gradient($startColor, $midColor $colorStop, $endColor);
+ background-image: -o-linear-gradient($startColor, $midColor $colorStop, $endColor);
+ background-image: linear-gradient($startColor, $midColor $colorStop, $endColor);
+ background-repeat: no-repeat;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#{$startColor}', endColorstr='#{$endColor}', GradientType=0), $startColor, $endColor; // IE9 and down, gets no color-stop at all the proper fallback
+}
+@mixin gradient-radial($innerColor: #555, $outerColor: #333) {
+ background-color: $outerColor;
+ background-image: -webkit-gradient(radial, center center, 0, center center, 460, from($innerColor), to($outerColor));
+ background-image: -webkit-radial-gradient(circle, $innerColor, $outerColor);
+ background-image: -moz-radial-gradient(circle, $innerColor, $outerColor);
+ background-image: -ms-radial-gradient(circle, $innerColor, $outerColor);
+ background-repeat: no-repeat;
+ // Opera cannot do radial gradients yet
+}
+@mixin gradient-striped($color,$angle: -45deg) {
+ background-color: $color;
+ background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(.25, rgba(255,255,255,.15)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, rgba(255,255,255,.15)), color-stop(.75, rgba(255,255,255,.15)), color-stop(.75, transparent), to(transparent));
+ background-image: -webkit-linear-gradient($angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent);
+ background-image: -moz-linear-gradient($angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent);
+ background-image: -ms-linear-gradient($angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent);
+ background-image: -o-linear-gradient($angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent);
+ //background-image: linear-gradient($angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent);
+ }
+
+// Gradient Bar Colors for buttons and alerts
+@mixin gradientBar($primaryColor, $secondaryColor) {
+ @include gradient-vertical($primaryColor, $secondaryColor);
+ border-color: $secondaryColor $secondaryColor darken($secondaryColor, 15%);
+ border-color: rgba(0,0,0,.1) rgba(0,0,0,.1) fade-in(rgba(0,0,0,.1), 0.15);
+}
+
+// Reset filters for IE
+@mixin reset-filter() {
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+}
+
+// Mixin for generating button backgrounds
+// ---------------------------------------
+@mixin buttonBackground($startColor, $endColor) {
+ // gradientBar will set the background to a pleasing blend of these, to support IE<=9
+ @include gradientBar($startColor, $endColor);
+ @include reset-filter();
+
+ // in these cases the gradient won't cover the background, so we override
+ &:hover, &:active, &.active, &.disabled, &[disabled] {
+ background-color: $endColor;
+ }
+
+ // IE 7 + 8 can't handle box-shadow to show active, so we darken a bit ourselves
+ &:active,
+ &.active {
+ background-color: darken($endColor, 10%) #{"\9"};
+ }
+}
+
+
+// COMPONENT MIXINS
+// --------------------------------------------------
+
+// POPOVER ARROWS
+// -------------------------
+// For tipsies and popovers
+@mixin popoverArrow-top($arrowWidth: 5px) {
+ bottom: 0;
+ left: 50%;
+ margin-left: -$arrowWidth;
+ border-left: $arrowWidth solid transparent;
+ border-right: $arrowWidth solid transparent;
+ border-top: $arrowWidth solid $black;
+}
+@mixin popoverArrow-left($arrowWidth: 5px) {
+ top: 50%;
+ right: 0;
+ margin-top: -$arrowWidth;
+ border-top: $arrowWidth solid transparent;
+ border-bottom: $arrowWidth solid transparent;
+ border-left: $arrowWidth solid $black;
+}
+@mixin popoverArrow-bottom($arrowWidth: 5px) {
+ top: 0;
+ left: 50%;
+ margin-left: -$arrowWidth;
+ border-left: $arrowWidth solid transparent;
+ border-right: $arrowWidth solid transparent;
+ border-bottom: $arrowWidth solid $black;
+}
+@mixin popoverArrow-right($arrowWidth: 5px) {
+ top: 50%;
+ left: 0;
+ margin-top: -$arrowWidth;
+ border-top: $arrowWidth solid transparent;
+ border-bottom: $arrowWidth solid transparent;
+ border-right: $arrowWidth solid $black;
+}
diff --git a/app/assets/stylesheets/bootstrap/_modals.scss b/app/assets/stylesheets/bootstrap/_modals.scss
new file mode 100644
index 0000000..1e3a176
--- /dev/null
+++ b/app/assets/stylesheets/bootstrap/_modals.scss
@@ -0,0 +1,84 @@
+// MODALS
+// ------
+
+// Recalculate z-index where appropriate
+.modal-open {
+ .dropdown-menu { z-index: $zindexDropdown + $zindexModal; }
+ .dropdown.open { *z-index: $zindexDropdown + $zindexModal; }
+ .popover { z-index: $zindexPopover + $zindexModal; }
+ .tooltip { z-index: $zindexTooltip + $zindexModal; }
+}
+
+// Background
+.modal-backdrop {
+ position: fixed;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ z-index: $zindexModalBackdrop;
+ background-color: $black;
+ // Fade for backdrop
+ &.fade { opacity: 0; }
+}
+
+.modal-backdrop,
+.modal-backdrop.fade.in {
+ @include opacity(80);
+}
+
+// Base modal
+.modal {
+ position: fixed;
+ top: 50%;
+ left: 50%;
+ z-index: $zindexModal;
+ max-height: 500px;
+ overflow: auto;
+ width: 560px;
+ margin: -250px 0 0 -280px;
+ background-color: $white;
+ border: 1px solid #999;
+ border: 1px solid rgba(0,0,0,.3);
+ *border: 1px solid #999; /* IE6-7 */
+ @include border-radius(6px);
+ @include box-shadow(0 3px 7px rgba(0,0,0,0.3));
+ @include background-clip(padding-box);
+ &.fade {
+ @include transition(opacity .3s linear);
+ // @include transition(top .3s ease-out);
+ top: -25%;
+ }
+ &.fade.in { top: 50%; }
+}
+.modal-header {
+ padding: 9px 15px;
+ border-bottom: 1px solid #eee;
+ // Close icon
+ .close { margin-top: 2px; }
+}
+
+// Body (where all modal content resises)
+.modal-body {
+ padding: 15px;
+}
+// Remove bottom margin if need be
+.modal-body .modal-form {
+ margin-bottom: 0;
+}
+
+// Footer (for actions)
+.modal-footer {
+ padding: 14px 15px 15px;
+ margin-bottom: 0;
+ background-color: #f5f5f5;
+ border-top: 1px solid #ddd;
+ @include border-radius(0 0 6px 6px);
+ @include box-shadow(inset 0 1px 0 $white);
+ @include clearfix();
+ .btn {
+ float: right;
+ margin-left: 5px;
+ margin-bottom: 0; // account for input[type="submit"] which gets the bottom margin like all other inputs
+ }
+}
diff --git a/app/assets/stylesheets/bootstrap/_navbar.scss b/app/assets/stylesheets/bootstrap/_navbar.scss
new file mode 100644
index 0000000..a702092
--- /dev/null
+++ b/app/assets/stylesheets/bootstrap/_navbar.scss
@@ -0,0 +1,299 @@
+// NAVBAR (FIXED AND STATIC)
+// -------------------------
+
+
+// COMMON STYLES
+// -------------
+
+.navbar {
+ overflow: visible;
+ margin-bottom: $baseLineHeight;
+}
+
+// Gradient is applied to it's own element because overflow visible is not honored by IE when filter is present
+.navbar-inner {
+ padding-left: 20px;
+ padding-right: 20px;
+ @include gradient-vertical($navbarBackgroundHighlight, $navbarBackground);
+ @include border-radius(4px);
+ $shadow: 0 1px 3px rgba(0,0,0,.25), inset 0 -1px 0 rgba(0,0,0,.1);
+ @include box-shadow($shadow);
+}
+
+// Navbar button for toggling navbar items in responsive layouts
+.btn-navbar {
+ display: none;
+ float: right;
+ padding: 7px 10px;
+ margin-left: 5px;
+ margin-right: 5px;
+ @include buttonBackground($navbarBackgroundHighlight, $navbarBackground);
+ $shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075);
+ @include box-shadow($shadow);
+}
+.btn-navbar .icon-bar {
+ display: block;
+ width: 18px;
+ height: 2px;
+ background-color: #f5f5f5;
+ @include border-radius(1px);
+ @include box-shadow(0 1px 0 rgba(0,0,0,.25));
+}
+.btn-navbar .icon-bar + .icon-bar {
+ margin-top: 3px;
+}
+// Override the default collapsed state
+.nav-collapse.collapse {
+ height: auto;
+}
+
+
+// Brand, links, text, and buttons
+.navbar {
+ // Hover and active states
+ .brand:hover {
+ text-decoration: none;
+ }
+ // Website or project name
+ .brand {
+ float: left;
+ display: block;
+ padding: 8px 20px 12px;
+ margin-left: -20px; // negative indent to left-align the text down the page
+ font-size: 20px;
+ font-weight: 200;
+ line-height: 1;
+ color: $white;
+ }
+ // Plain text in topbar
+ .navbar-text {
+ margin-bottom: 0;
+ line-height: 40px;
+ color: $navbarText;
+ a:hover {
+ color: $white;
+ background-color: transparent;
+ }
+ }
+ // Buttons in navbar
+ .btn,
+ .btn-group {
+ margin-top: 5px; // make buttons vertically centered in navbar
+ }
+ .btn-group .btn {
+ margin-top: 0; // then undo the margin here so we don't accidentally double it
+ }
+}
+
+// Navbar forms
+.navbar-form {
+ margin-bottom: 0; // remove default bottom margin
+ @include clearfix();
+ input,
+ select {
+ display: inline-block;
+ margin-top: 5px;
+ margin-bottom: 0;
+ }
+ .radio,
+ .checkbox {
+ margin-top: 5px;
+ }
+ input[type="image"],
+ input[type="checkbox"],
+ input[type="radio"] {
+ margin-top: 3px;
+ }
+ .input-append,
+ .input-prepend {
+ margin-top: 6px;
+ white-space: nowrap; // preven two items from separating within a .navbar-form that has .pull-left
+ input {
+ margin-top: 0; // remove the margin on top since it's on the parent
+ }
+ }
+}
+
+// Navbar search
+.navbar-search {
+ position: relative;
+ float: left;
+ margin-top: 6px;
+ margin-bottom: 0;
+ .search-query {
+ padding: 4px 9px;
+ @include font-sans-serif(13px, normal, 1);
+ color: $white;
+ color: rgba(255,255,255,.75);
+ background: #666;
+ background: rgba(255,255,255,.3);
+ border: 1px solid #111;
+ $shadow: inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0px rgba(255,255,255,.15);
+ @include box-shadow($shadow);
+ @include transition(none);
+
+ // Placeholder text gets special styles; can't be bundled together though for some reason
+ @include placeholder($grayLighter);
+
+ // Hover states
+ &:hover {
+ color: $white;
+ background-color: $grayLight;
+ background-color: rgba(255,255,255,.5);
+ }
+ // Focus states (we use .focused since IE7-8 and down doesn't support :focus)
+ &:focus,
+ &.focused {
+ padding: 5px 10px;
+ color: $grayDark;
+ text-shadow: 0 1px 0 $white;
+ background-color: $white;
+ border: 0;
+ @include box-shadow(0 0 3px rgba(0,0,0,.15));
+ outline: 0;
+ }
+ }
+}
+
+
+// FIXED NAVBAR
+// ------------
+
+.navbar-fixed-top {
+ position: fixed;
+ top: 0;
+ right: 0;
+ left: 0;
+ z-index: $zindexFixedNavbar;
+}
+.navbar-fixed-top .navbar-inner {
+ padding-left: 0;
+ padding-right: 0;
+ @include border-radius(0);
+}
+
+
+// NAVIGATION
+// ----------
+
+.navbar .nav {
+ position: relative;
+ left: 0;
+ display: block;
+ float: left;
+ margin: 0 10px 0 0;
+}
+.navbar .nav.pull-right {
+ float: right; // redeclare due to specificity
+}
+.navbar .nav > li {
+ display: block;
+ float: left;
+}
+
+// Links
+.navbar .nav > li > a {
+ float: none;
+ padding: 10px 10px 11px;
+ line-height: 19px;
+ color: $navbarLinkColor;
+ text-decoration: none;
+ text-shadow: 0 -1px 0 rgba(0,0,0,.25);
+}
+// Hover
+.navbar .nav > li > a:hover {
+ background-color: $navbarLinkBackgroundHover; // "transparent" is default to differentiate :hover from .active
+ color: $navbarLinkColorHover;
+ text-decoration: none;
+}
+
+// Active nav items
+.navbar .nav .active > a,
+.navbar .nav .active > a:hover {
+ color: $navbarLinkColorHover;
+ text-decoration: none;
+ background-color: $navbarBackground;
+}
+
+// Dividers (basically a vertical hr)
+.navbar .divider-vertical {
+ height: $navbarHeight;
+ width: 1px;
+ margin: 0 9px;
+ overflow: hidden;
+ background-color: $navbarBackground;
+ border-right: 1px solid $navbarBackgroundHighlight;
+}
+
+// Secondary (floated right) nav in topbar
+.navbar .nav.pull-right {
+ margin-left: 10px;
+ margin-right: 0;
+}
+
+
+
+// Dropdown menus
+// --------------
+
+// Menu position and menu carets
+.navbar .dropdown-menu {
+ margin-top: 1px;
+ @include border-radius(4px);
+ &:before {
+ content: '';
+ display: inline-block;
+ border-left: 7px solid transparent;
+ border-right: 7px solid transparent;
+ border-bottom: 7px solid #ccc;
+ border-bottom-color: rgba(0,0,0,.2);
+ position: absolute;
+ top: -7px;
+ left: 9px;
+ }
+ &:after {
+ content: '';
+ display: inline-block;
+ border-left: 6px solid transparent;
+ border-right: 6px solid transparent;
+ border-bottom: 6px solid $white;
+ position: absolute;
+ top: -6px;
+ left: 10px;
+ }
+}
+
+// Dropdown toggle caret
+.navbar .nav .dropdown-toggle .caret,
+.navbar .nav .open.dropdown .caret {
+ border-top-color: $white;
+}
+.navbar .nav .active .caret {
+ @include opacity(100);
+}
+
+// Remove background color from open dropdown
+.navbar .nav .open > .dropdown-toggle,
+.navbar .nav .active > .dropdown-toggle,
+.navbar .nav .open.active > .dropdown-toggle {
+ background-color: transparent;
+}
+
+// Dropdown link on hover
+.navbar .nav .active > .dropdown-toggle:hover {
+ color: $white;
+}
+
+// Right aligned menus need alt position
+.navbar .nav.pull-right .dropdown-menu {
+ left: auto;
+ right: 0;
+ &:before {
+ left: auto;
+ right: 12px;
+ }
+ &:after {
+ left: auto;
+ right: 13px;
+ }
+}
diff --git a/app/assets/stylesheets/bootstrap/_navs.scss b/app/assets/stylesheets/bootstrap/_navs.scss
new file mode 100644
index 0000000..0f59458
--- /dev/null
+++ b/app/assets/stylesheets/bootstrap/_navs.scss
@@ -0,0 +1,353 @@
+// NAVIGATIONS
+// -----------
+
+
+
+// BASE CLASS
+// ----------
+
+.nav {
+ margin-left: 0;
+ margin-bottom: $baseLineHeight;
+ list-style: none;
+}
+
+// Make links block level
+.nav > li > a {
+ display: block;
+}
+.nav > li > a:hover {
+ text-decoration: none;
+ background-color: $grayLighter;
+}
+
+// Nav headers (for dropdowns and lists)
+.nav .nav-header {
+ display: block;
+ padding: 3px 15px;
+ font-size: 11px;
+ font-weight: bold;
+ line-height: $baseLineHeight;
+ color: $grayLight;
+ text-shadow: 0 1px 0 rgba(255,255,255,.5);
+ text-transform: uppercase;
+}
+// Space them out when they follow another list item (link)
+.nav li + .nav-header {
+ margin-top: 9px;
+}
+
+
+// NAV LIST
+// --------
+
+.nav-list {
+ padding-left: 14px;
+ padding-right: 14px;
+ margin-bottom: 0;
+}
+.nav-list > li > a,
+.nav-list .nav-header {
+ margin-left: -15px;
+ margin-right: -15px;
+ text-shadow: 0 1px 0 rgba(255,255,255,.5);
+}
+.nav-list > li > a {
+ padding: 3px 15px;
+}
+.nav-list .active > a,
+.nav-list .active > a:hover {
+ color: $white;
+ text-shadow: 0 -1px 0 rgba(0,0,0,.2);
+ background-color: $linkColor;
+}
+.nav-list [class^="icon-"] {
+ margin-right: 2px;
+}
+
+
+
+// TABS AND PILLS
+// -------------
+
+// Common styles
+.nav-tabs,
+.nav-pills {
+ @include clearfix();
+}
+.nav-tabs > li,
+.nav-pills > li {
+ float: left;
+}
+.nav-tabs > li > a,
+.nav-pills > li > a {
+ padding-right: 12px;
+ padding-left: 12px;
+ margin-right: 2px;
+ line-height: 14px; // keeps the overall height an even number
+}
+
+// TABS
+// ----
+
+// Give the tabs something to sit on
+.nav-tabs {
+ border-bottom: 1px solid #ddd;
+}
+
+// Make the list-items overlay the bottom border
+.nav-tabs > li {
+ margin-bottom: -1px;
+}
+
+// Actual tabs (as links)
+.nav-tabs > li > a {
+ padding-top: 9px;
+ padding-bottom: 9px;
+ border: 1px solid transparent;
+ @include border-radius(4px 4px 0 0);
+ &:hover {
+ border-color: $grayLighter $grayLighter #ddd;
+ }
+}
+// Active state, and it's :hover to override normal :hover
+.nav-tabs > .active > a,
+.nav-tabs > .active > a:hover {
+ color: $gray;
+ background-color: $white;
+ border: 1px solid #ddd;
+ border-bottom-color: transparent;
+ cursor: default;
+}
+
+// PILLS
+// -----
+
+// Links rendered as pills
+.nav-pills > li > a {
+ padding-top: 8px;
+ padding-bottom: 8px;
+ margin-top: 2px;
+ margin-bottom: 2px;
+ @include border-radius(5px);
+}
+
+// Active state
+.nav-pills .active > a,
+.nav-pills .active > a:hover {
+ color: $white;
+ background-color: $linkColor;
+}
+
+
+
+// STACKED NAV
+// -----------
+
+// Stacked tabs and pills
+.nav-stacked > li {
+ float: none;
+}
+.nav-stacked > li > a {
+ margin-right: 0; // no need for the gap between nav items
+}
+
+// Tabs
+.nav-tabs.nav-stacked {
+ border-bottom: 0;
+}
+.nav-tabs.nav-stacked > li > a {
+ border: 1px solid #ddd;
+ @include border-radius(0);
+}
+.nav-tabs.nav-stacked > li:first-child > a {
+ @include border-radius(4px 4px 0 0);
+}
+.nav-tabs.nav-stacked > li:last-child > a {
+ @include border-radius(0 0 4px 4px);
+}
+.nav-tabs.nav-stacked > li > a:hover {
+ border-color: #ddd;
+ z-index: 2;
+}
+
+// Pills
+.nav-pills.nav-stacked > li > a {
+ margin-bottom: 3px;
+}
+.nav-pills.nav-stacked > li:last-child > a {
+ margin-bottom: 1px; // decrease margin to match sizing of stacked tabs
+}
+
+
+
+// DROPDOWNS
+// ---------
+
+// Position the menu
+.nav-tabs .dropdown-menu,
+.nav-pills .dropdown-menu {
+ margin-top: 1px;
+ border-width: 1px;
+}
+.nav-pills .dropdown-menu {
+ @include border-radius(4px);
+}
+
+// Default dropdown links
+// -------------------------
+// Make carets use linkColor to start
+.nav-tabs .dropdown-toggle .caret,
+.nav-pills .dropdown-toggle .caret {
+ border-top-color: $linkColor;
+ margin-top: 6px;
+}
+.nav-tabs .dropdown-toggle:hover .caret,
+.nav-pills .dropdown-toggle:hover .caret {
+ border-top-color: $linkColorHover;
+}
+
+// Active dropdown links
+// -------------------------
+.nav-tabs .active .dropdown-toggle .caret,
+.nav-pills .active .dropdown-toggle .caret {
+ border-top-color: $grayDark;
+}
+
+// Active:hover dropdown links
+// -------------------------
+.nav > .dropdown.active > a:hover {
+ color: $black;
+ cursor: pointer;
+}
+
+// Open dropdowns
+// -------------------------
+.nav-tabs .open .dropdown-toggle,
+.nav-pills .open .dropdown-toggle,
+.nav > .open.active > a:hover {
+ color: $white;
+ background-color: $grayLight;
+ border-color: $grayLight;
+}
+.nav .open .caret,
+.nav .open.active .caret,
+.nav .open a:hover .caret {
+ border-top-color: $white;
+ @include opacity(100);
+}
+
+// Dropdowns in stacked tabs
+.tabs-stacked .open > a:hover {
+ border-color: $grayLight;
+}
+
+
+
+// TABBABLE
+// --------
+
+
+// COMMON STYLES
+// -------------
+
+// Clear any floats
+.tabbable {
+ @include clearfix();
+}
+.tab-content {
+ overflow: hidden; // prevent content from running below tabs
+}
+
+// Remove border on bottom, left, right
+.tabs-below .nav-tabs,
+.tabs-right .nav-tabs,
+.tabs-left .nav-tabs {
+ border-bottom: 0;
+}
+
+// Show/hide tabbable areas
+.tab-content > .tab-pane,
+.pill-content > .pill-pane {
+ display: none;
+}
+.tab-content > .active,
+.pill-content > .active {
+ display: block;
+}
+
+
+// BOTTOM
+// ------
+
+.tabs-below .nav-tabs {
+ border-top: 1px solid #ddd;
+}
+.tabs-below .nav-tabs > li {
+ margin-top: -1px;
+ margin-bottom: 0;
+}
+.tabs-below .nav-tabs > li > a {
+ @include border-radius(0 0 4px 4px);
+ &:hover {
+ border-bottom-color: transparent;
+ border-top-color: #ddd;
+ }
+}
+.tabs-below .nav-tabs .active > a,
+.tabs-below .nav-tabs .active > a:hover {
+ border-color: transparent #ddd #ddd #ddd;
+}
+
+// LEFT & RIGHT
+// ------------
+
+// Common styles
+.tabs-left .nav-tabs > li,
+.tabs-right .nav-tabs > li {
+ float: none;
+}
+.tabs-left .nav-tabs > li > a,
+.tabs-right .nav-tabs > li > a {
+ min-width: 74px;
+ margin-right: 0;
+ margin-bottom: 3px;
+}
+
+// Tabs on the left
+.tabs-left .nav-tabs {
+ float: left;
+ margin-right: 19px;
+ border-right: 1px solid #ddd;
+}
+.tabs-left .nav-tabs > li > a {
+ margin-right: -1px;
+ @include border-radius(4px 0 0 4px);
+}
+.tabs-left .nav-tabs > li > a:hover {
+ border-color: $grayLighter #ddd $grayLighter $grayLighter;
+}
+.tabs-left .nav-tabs .active > a,
+.tabs-left .nav-tabs .active > a:hover {
+ border-color: #ddd transparent #ddd #ddd;
+ *border-right-color: $white;
+}
+
+// Tabs on the right
+.tabs-right .nav-tabs {
+ float: right;
+ margin-left: 19px;
+ border-left: 1px solid #ddd;
+}
+.tabs-right .nav-tabs > li > a {
+ margin-left: -1px;
+ @include border-radius(0 4px 4px 0);
+}
+.tabs-right .nav-tabs > li > a:hover {
+ border-color: $grayLighter $grayLighter $grayLighter #ddd;
+}
+.tabs-right .nav-tabs .active > a,
+.tabs-right .nav-tabs .active > a:hover {
+ border-color: #ddd #ddd #ddd transparent;
+ *border-left-color: $white;
+}
diff --git a/app/assets/stylesheets/bootstrap/_pager.scss b/app/assets/stylesheets/bootstrap/_pager.scss
new file mode 100644
index 0000000..12f4da2
--- /dev/null
+++ b/app/assets/stylesheets/bootstrap/_pager.scss
@@ -0,0 +1,30 @@
+// PAGER
+// -----
+
+.pager {
+ margin-left: 0;
+ margin-bottom: $baseLineHeight;
+ list-style: none;
+ text-align: center;
+ @include clearfix();
+}
+.pager li {
+ display: inline;
+}
+.pager a {
+ display: inline-block;
+ padding: 5px 14px;
+ background-color: #fff;
+ border: 1px solid #ddd;
+ @include border-radius(15px);
+}
+.pager a:hover {
+ text-decoration: none;
+ background-color: #f5f5f5;
+}
+.pager .next a {
+ float: right;
+}
+.pager .previous a {
+ float: left;
+}
diff --git a/app/assets/stylesheets/bootstrap/_pagination.scss b/app/assets/stylesheets/bootstrap/_pagination.scss
new file mode 100644
index 0000000..6957128
--- /dev/null
+++ b/app/assets/stylesheets/bootstrap/_pagination.scss
@@ -0,0 +1,55 @@
+// PAGINATION
+// ----------
+
+.pagination {
+ height: $baseLineHeight * 2;
+ margin: $baseLineHeight 0;
+ }
+.pagination ul {
+ display: inline-block;
+ @include ie7-inline-block();
+ margin-left: 0;
+ margin-bottom: 0;
+ @include border-radius(3px);
+ @include box-shadow(0 1px 2px rgba(0,0,0,.05));
+}
+.pagination li {
+ display: inline;
+ }
+.pagination a {
+ float: left;
+ padding: 0 14px;
+ line-height: ($baseLineHeight * 2) - 2;
+ text-decoration: none;
+ border: 1px solid #ddd;
+ border-left-width: 0;
+}
+.pagination a:hover,
+.pagination .active a {
+ background-color: #f5f5f5;
+}
+.pagination .active a {
+ color: $grayLight;
+ cursor: default;
+}
+.pagination .disabled a,
+.pagination .disabled a:hover {
+ color: $grayLight;
+ background-color: transparent;
+ cursor: default;
+}
+.pagination li:first-child a {
+ border-left-width: 1px;
+ @include border-radius(3px 0 0 3px);
+}
+.pagination li:last-child a {
+ @include border-radius(0 3px 3px 0);
+}
+
+// Centered
+.pagination-centered {
+ text-align: center;
+}
+.pagination-right {
+ text-align: right;
+}
diff --git a/app/assets/stylesheets/bootstrap/_popovers.scss b/app/assets/stylesheets/bootstrap/_popovers.scss
new file mode 100644
index 0000000..a20f2d5
--- /dev/null
+++ b/app/assets/stylesheets/bootstrap/_popovers.scss
@@ -0,0 +1,49 @@
+// POPOVERS
+// --------
+
+.popover {
+ position: absolute;
+ top: 0;
+ left: 0;
+ z-index: $zindexPopover;
+ display: none;
+ padding: 5px;
+ &.top { margin-top: -5px; }
+ &.right { margin-left: 5px; }
+ &.bottom { margin-top: 5px; }
+ &.left { margin-left: -5px; }
+ &.top .arrow { @include popoverArrow-top(); }
+ &.right .arrow { @include popoverArrow-right(); }
+ &.bottom .arrow { @include popoverArrow-bottom(); }
+ &.left .arrow { @include popoverArrow-left(); }
+ .arrow {
+ position: absolute;
+ width: 0;
+ height: 0;
+ }
+}
+.popover-inner {
+ padding: 3px;
+ width: 280px;
+ overflow: hidden;
+ background: $black; // has to be full background declaration for IE fallback
+ background: rgba(0,0,0,.8);
+ @include border-radius(6px);
+ @include box-shadow(0 3px 7px rgba(0,0,0,0.3));
+}
+.popover-title {
+ padding: 9px 15px;
+ line-height: 1;
+ background-color: #f5f5f5;
+ border-bottom:1px solid #eee;
+ @include border-radius(3px 3px 0 0);
+}
+.popover-content {
+ padding: 14px;
+ background-color: $white;
+ @include border-radius(0 0 3px 3px);
+ @include background-clip(padding-box);
+ p, ul, ol {
+ margin-bottom: 0;
+ }
+}
diff --git a/app/assets/stylesheets/bootstrap/_progress-bars.scss b/app/assets/stylesheets/bootstrap/_progress-bars.scss
new file mode 100644
index 0000000..91dbbef
--- /dev/null
+++ b/app/assets/stylesheets/bootstrap/_progress-bars.scss
@@ -0,0 +1,95 @@
+// PROGRESS BARS
+// -------------
+
+
+// ANIMATIONS
+// ----------
+
+// Webkit
+@-webkit-keyframes progress-bar-stripes {
+ from { background-position: 0 0; }
+ to { background-position: 40px 0; }
+}
+
+// Firefox
+@-moz-keyframes progress-bar-stripes {
+ from { background-position: 0 0; }
+ to { background-position: 40px 0; }
+}
+
+// Spec
+@keyframes progress-bar-stripes {
+ from { background-position: 0 0; }
+ to { background-position: 40px 0; }
+}
+
+
+
+// THE BARS
+// --------
+
+// Outer container
+.progress {
+ overflow: hidden;
+ height: 18px;
+ margin-bottom: 18px;
+ @include gradient-vertical(#f5f5f5, #f9f9f9);
+ @include box-shadow(inset 0 1px 2px rgba(0,0,0,.1));
+ @include border-radius(4px);
+}
+
+// Bar of progress
+.progress .bar {
+ width: 0%;
+ height: 18px;
+ color: $white;
+ font-size: 12px;
+ text-align: center;
+ text-shadow: 0 -1px 0 rgba(0,0,0,.25);
+ @include gradient-vertical(#149bdf, #0480be);
+ @include box-shadow(inset 0 -1px 0 rgba(0,0,0,.15));
+ @include box-sizing(border-box);
+ @include transition(width .6s ease);
+}
+
+// Striped bars
+.progress-striped .bar {
+ @include gradient-striped(#62c462);
+ @include background-size(40px 40px);
+}
+
+// Call animation for the active one
+.progress.active .bar {
+ -webkit-animation: progress-bar-stripes 2s linear infinite;
+ -moz-animation: progress-bar-stripes 2s linear infinite;
+ animation: progress-bar-stripes 2s linear infinite;
+}
+
+
+
+// COLORS
+// ------
+
+// Danger (red)
+.progress-danger .bar {
+ @include gradient-vertical(#ee5f5b, #c43c35);
+}
+.progress-danger.progress-striped .bar {
+ @include gradient-striped(#ee5f5b);
+}
+
+// Success (green)
+.progress-success .bar {
+ @include gradient-vertical(#62c462, #57a957);
+}
+.progress-success.progress-striped .bar {
+ @include gradient-striped(#62c462);
+}
+
+// Info (teal)
+.progress.info .bar {
+ @include gradient-vertical(#5bc0de, #339bb9);
+}
+.progress-info.progress-striped .bar {
+ @include gradient-striped(#5bc0de);
+}
diff --git a/app/assets/stylesheets/bootstrap/_reset.scss b/app/assets/stylesheets/bootstrap/_reset.scss
new file mode 100644
index 0000000..26d3f36
--- /dev/null
+++ b/app/assets/stylesheets/bootstrap/_reset.scss
@@ -0,0 +1,126 @@
+// Reset.scss
+// Adapted from Normalize.css http://github.com/necolas/normalize.css
+// ------------------------------------------------------------------------
+
+// Display in IE6-9 and FF3
+// -------------------------
+
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+nav,
+section {
+ display: block;
+}
+
+// Display block in IE6-9 and FF3
+// -------------------------
+
+audio,
+canvas,
+video {
+ display: inline-block;
+ *display: inline;
+ *zoom: 1;
+}
+
+// Prevents modern browsers from displaying 'audio' without controls
+// -------------------------
+
+audio:not([controls]) {
+ display: none;
+}
+
+// Base settings
+// -------------------------
+
+html {
+ font-size: 100%;
+ -webkit-text-size-adjust: 100%;
+ -ms-text-size-adjust: 100%;
+}
+// Focus states
+a:focus {
+ @include tab-focus();
+}
+// Hover & Active
+a:hover,
+a:active {
+ outline: 0;
+}
+
+// Prevents sub and sup affecting line-height in all browsers
+// -------------------------
+
+sub,
+sup {
+ position: relative;
+ font-size: 75%;
+ line-height: 0;
+ vertical-align: baseline;
+}
+sup {
+ top: -0.5em;
+}
+sub {
+ bottom: -0.25em;
+}
+
+// Img border in a's and image quality
+// -------------------------
+
+img {
+ max-width: 100%;
+ height: auto;
+ border: 0;
+ -ms-interpolation-mode: bicubic;
+}
+
+// Forms
+// -------------------------
+
+// Font size in all browsers, margin changes, misc consistency
+button,
+input,
+select,
+textarea {
+ margin: 0;
+ font-size: 100%;
+ vertical-align: middle;
+}
+button,
+input {
+ *overflow: visible; // Inner spacing ie IE6/7
+ line-height: normal; // FF3/4 have !important on line-height in UA stylesheet
+}
+button::-moz-focus-inner,
+input::-moz-focus-inner { // Inner padding and border oddities in FF3/4
+ padding: 0;
+ border: 0;
+}
+button,
+input[type="button"],
+input[type="reset"],
+input[type="submit"] {
+ cursor: pointer; // Cursors on all buttons applied consistently
+ -webkit-appearance: button; // Style clickable inputs in iOS
+}
+input[type="search"] { // Appearance in Safari/Chrome
+ -webkit-appearance: textfield;
+ -webkit-box-sizing: content-box;
+ -moz-box-sizing: content-box;
+ box-sizing: content-box;
+}
+input[type="search"]::-webkit-search-decoration,
+input[type="search"]::-webkit-search-cancel-button {
+ -webkit-appearance: none; // Inner-padding issues in Chrome OSX, Safari 5
+}
+textarea {
+ overflow: auto; // Remove vertical scrollbar in IE6-9
+ vertical-align: top; // Readability and alignment cross-browser
+}
diff --git a/app/assets/stylesheets/bootstrap/_scaffolding.scss b/app/assets/stylesheets/bootstrap/_scaffolding.scss
new file mode 100644
index 0000000..3312d01
--- /dev/null
+++ b/app/assets/stylesheets/bootstrap/_scaffolding.scss
@@ -0,0 +1,33 @@
+// Scaffolding
+// Basic and global styles for generating a grid system, structural layout, and page templates
+// -------------------------------------------------------------------------------------------
+
+
+// STRUCTURAL LAYOUT
+// -----------------
+
+.clearfix {
+ @include clearfix();
+}
+
+body {
+ margin: 0;
+ font-family: $baseFontFamily;
+ font-size: $baseFontSize;
+ line-height: $baseLineHeight;
+ color: $textColor;
+ background-color: $white;
+}
+
+
+// LINKS
+// -----
+
+a {
+ color: $linkColor;
+ text-decoration: none;
+}
+a:hover {
+ color: $linkColorHover;
+ text-decoration: underline;
+}
diff --git a/app/assets/stylesheets/bootstrap/_sprites.scss b/app/assets/stylesheets/bootstrap/_sprites.scss
new file mode 100644
index 0000000..493e9f7
--- /dev/null
+++ b/app/assets/stylesheets/bootstrap/_sprites.scss
@@ -0,0 +1,158 @@
+// SPRITES
+// Glyphs and icons for buttons, nav, and more
+// -------------------------------------------
+
+
+// ICONS
+// -----
+
+// All icons receive the styles of the <i> tag with a base class
+// of .i and are then given a unique class to add width, height,
+// and background-position. Your resulting HTML will look like
+// <i class="icon-inbox"></i>.
+
+// For the white version of the icons, just add the .icon-white class:
+// <i class="icon-inbox icon-white"></i>
+
+[class^="icon-"],
+[class*=" icon-"] {
+ display: inline-block;
+ width: 14px;
+ height: 14px;
+ line-height: 14px;
+ vertical-align: text-top;
+ background-image: url($iconSpritePath);
+ background-position: 14px 14px;
+ background-repeat: no-repeat;
+
+ @include ie7-restore-right-whitespace();
+}
+.icon-white {
+ background-image: url($iconWhiteSpritePath);
+}
+
+.icon-glass { background-position: 0 0; }
+.icon-music { background-position: -24px 0; }
+.icon-search { background-position: -48px 0; }
+.icon-envelope { background-position: -72px 0; }
+.icon-heart { background-position: -96px 0; }
+.icon-star { background-position: -120px 0; }
+.icon-star-empty { background-position: -144px 0; }
+.icon-user { background-position: -168px 0; }
+.icon-film { background-position: -192px 0; }
+.icon-th-large { background-position: -216px 0; }
+.icon-th { background-position: -240px 0; }
+.icon-th-list { background-position: -264px 0; }
+.icon-ok { background-position: -288px 0; }
+.icon-remove { background-position: -312px 0; }
+.icon-zoom-in { background-position: -336px 0; }
+.icon-zoom-out { background-position: -360px 0; }
+.icon-off { background-position: -384px 0; }
+.icon-signal { background-position: -408px 0; }
+.icon-cog { background-position: -432px 0; }
+.icon-trash { background-position: -456px 0; }
+
+.icon-home { background-position: 0 -24px; }
+.icon-file { background-position: -24px -24px; }
+.icon-time { background-position: -48px -24px; }
+.icon-road { background-position: -72px -24px; }
+.icon-download-alt { background-position: -96px -24px; }
+.icon-download { background-position: -120px -24px; }
+.icon-upload { background-position: -144px -24px; }
+.icon-inbox { background-position: -168px -24px; }
+.icon-play-circle { background-position: -192px -24px; }
+.icon-repeat { background-position: -216px -24px; }
+.icon-refresh { background-position: -240px -24px; }
+.icon-list-alt { background-position: -264px -24px; }
+.icon-lock { background-position: -287px -24px; } // 1px off
+.icon-flag { background-position: -312px -24px; }
+.icon-headphones { background-position: -336px -24px; }
+.icon-volume-off { background-position: -360px -24px; }
+.icon-volume-down { background-position: -384px -24px; }
+.icon-volume-up { background-position: -408px -24px; }
+.icon-qrcode { background-position: -432px -24px; }
+.icon-barcode { background-position: -456px -24px; }
+
+.icon-tag { background-position: 0 -48px; }
+.icon-tags { background-position: -25px -48px; } // 1px off
+.icon-book { background-position: -48px -48px; }
+.icon-bookmark { background-position: -72px -48px; }
+.icon-print { background-position: -96px -48px; }
+.icon-camera { background-position: -120px -48px; }
+.icon-font { background-position: -144px -48px; }
+.icon-bold { background-position: -167px -48px; } // 1px off
+.icon-italic { background-position: -192px -48px; }
+.icon-text-height { background-position: -216px -48px; }
+.icon-text-width { background-position: -240px -48px; }
+.icon-align-left { background-position: -264px -48px; }
+.icon-align-center { background-position: -288px -48px; }
+.icon-align-right { background-position: -312px -48px; }
+.icon-align-justify { background-position: -336px -48px; }
+.icon-list { background-position: -360px -48px; }
+.icon-indent-left { background-position: -384px -48px; }
+.icon-indent-right { background-position: -408px -48px; }
+.icon-facetime-video { background-position: -432px -48px; }
+.icon-picture { background-position: -456px -48px; }
+
+.icon-pencil { background-position: 0 -72px; }
+.icon-map-marker { background-position: -24px -72px; }
+.icon-adjust { background-position: -48px -72px; }
+.icon-tint { background-position: -72px -72px; }
+.icon-edit { background-position: -96px -72px; }
+.icon-share { background-position: -120px -72px; }
+.icon-check { background-position: -144px -72px; }
+.icon-move { background-position: -168px -72px; }
+.icon-step-backward { background-position: -192px -72px; }
+.icon-fast-backward { background-position: -216px -72px; }
+.icon-backward { background-position: -240px -72px; }
+.icon-play { background-position: -264px -72px; }
+.icon-pause { background-position: -288px -72px; }
+.icon-stop { background-position: -312px -72px; }
+.icon-forward { background-position: -336px -72px; }
+.icon-fast-forward { background-position: -360px -72px; }
+.icon-step-forward { background-position: -384px -72px; }
+.icon-eject { background-position: -408px -72px; }
+.icon-chevron-left { background-position: -432px -72px; }
+.icon-chevron-right { background-position: -456px -72px; }
+
+.icon-plus-sign { background-position: 0 -96px; }
+.icon-minus-sign { background-position: -24px -96px; }
+.icon-remove-sign { background-position: -48px -96px; }
+.icon-ok-sign { background-position: -72px -96px; }
+.icon-question-sign { background-position: -96px -96px; }
+.icon-info-sign { background-position: -120px -96px; }
+.icon-screenshot { background-position: -144px -96px; }
+.icon-remove-circle { background-position: -168px -96px; }
+.icon-ok-circle { background-position: -192px -96px; }
+.icon-ban-circle { background-position: -216px -96px; }
+.icon-arrow-left { background-position: -240px -96px; }
+.icon-arrow-right { background-position: -264px -96px; }
+.icon-arrow-up { background-position: -289px -96px; } // 1px off
+.icon-arrow-down { background-position: -312px -96px; }
+.icon-share-alt { background-position: -336px -96px; }
+.icon-resize-full { background-position: -360px -96px; }
+.icon-resize-small { background-position: -384px -96px; }
+.icon-plus { background-position: -408px -96px; }
+.icon-minus { background-position: -433px -96px; }
+.icon-asterisk { background-position: -456px -96px; }
+
+.icon-exclamation-sign { background-position: 0 -120px; }
+.icon-gift { background-position: -24px -120px; }
+.icon-leaf { background-position: -48px -120px; }
+.icon-fire { background-position: -72px -120px; }
+.icon-eye-open { background-position: -96px -120px; }
+.icon-eye-close { background-position: -120px -120px; }
+.icon-warning-sign { background-position: -144px -120px; }
+.icon-plane { background-position: -168px -120px; }
+.icon-calendar { background-position: -192px -120px; }
+.icon-random { background-position: -216px -120px; }
+.icon-comment { background-position: -240px -120px; }
+.icon-magnet { background-position: -264px -120px; }
+.icon-chevron-up { background-position: -288px -120px; }
+.icon-chevron-down { background-position: -313px -119px; } // 1px off
+.icon-retweet { background-position: -336px -120px; }
+.icon-shopping-cart { background-position: -360px -120px; }
+.icon-folder-close { background-position: -384px -120px; }
+.icon-folder-open { background-position: -408px -120px; }
+.icon-resize-vertical { background-position: -432px -119px; }
+.icon-resize-horizontal { background-position: -456px -118px; }
diff --git a/app/assets/stylesheets/bootstrap/_tables.scss b/app/assets/stylesheets/bootstrap/_tables.scss
new file mode 100644
index 0000000..9dda11c
--- /dev/null
+++ b/app/assets/stylesheets/bootstrap/_tables.scss
@@ -0,0 +1,150 @@
+//
+// Tables.scss
+// Tables for, you guessed it, tabular data
+// ----------------------------------------
+
+
+// BASE TABLES
+// -----------------
+
+table {
+ max-width: 100%;
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+
+// BASELINE STYLES
+// ---------------
+
+.table {
+ width: 100%;
+ margin-bottom: $baseLineHeight;
+ // Cells
+ th,
+ td {
+ padding: 8px;
+ line-height: $baseLineHeight;
+ text-align: left;
+ vertical-align: top;
+ border-top: 1px solid #ddd;
+ }
+ th {
+ font-weight: bold;
+ }
+ // Bottom align for column headings
+ thead th {
+ vertical-align: bottom;
+ }
+ // Remove top border from thead by default
+ thead:first-child tr th,
+ thead:first-child tr td {
+ border-top: 0;
+ }
+ // Account for multiple tbody instances
+ tbody + tbody {
+ border-top: 2px solid #ddd;
+ }
+}
+
+
+
+// CONDENSED TABLE W/ HALF PADDING
+// -------------------------------
+
+.table-condensed {
+ th,
+ td {
+ padding: 4px 5px;
+ }
+}
+
+
+// BORDERED VERSION
+// ----------------
+
+.table-bordered {
+ border: 1px solid #ddd;
+ border-collapse: separate; // Done so we can round those corners!
+ *border-collapse: collapsed; // IE7 can't round corners anyway
+ @include border-radius(4px);
+ th + th,
+ td + td,
+ th + td,
+ td + th {
+ border-left: 1px solid #ddd;
+ }
+ // Prevent a double border
+ thead:first-child tr:first-child th,
+ tbody:first-child tr:first-child th,
+ tbody:first-child tr:first-child td {
+ border-top: 0;
+ }
+ // For first th or td in the first row in the first thead or tbody
+ thead:first-child tr:first-child th:first-child,
+ tbody:first-child tr:first-child td:first-child {
+ @include border-radius(4px 0 0 0);
+ }
+ thead:first-child tr:first-child th:last-child,
+ tbody:first-child tr:first-child td:last-child {
+ @include border-radius(0 4px 0 0);
+ }
+ // For first th or td in the first row in the first thead or tbody
+ thead:last-child tr:last-child th:first-child,
+ tbody:last-child tr:last-child td:first-child {
+ @include border-radius(0 0 0 4px);
+ }
+ thead:last-child tr:last-child th:last-child,
+ tbody:last-child tr:last-child td:last-child {
+ @include border-radius(0 0 4px 0);
+ }
+}
+
+
+// ZEBRA-STRIPING
+// --------------
+
+// Default zebra-stripe styles (alternating gray and transparent backgrounds)
+.table-striped {
+ tbody {
+ tr:nth-child(odd) td,
+ tr:nth-child(odd) th {
+ background-color: #f9f9f9;
+ }
+ }
+}
+
+
+// HOVER EFFECT
+// ------------
+// Placed here since it has to come after the potential zebra striping
+.table {
+ tbody tr:hover td,
+ tbody tr:hover th {
+ background-color: #f5f5f5;
+ }
+}
+
+
+// TABLE CELL SIZING
+// -----------------
+
+// Change the columns
+@mixin tableColumns($columnSpan: 1) {
+ float: none;
+ width: (($gridColumnWidth) * $columnSpan) + ($gridGutterWidth * ($columnSpan - 1)) - 16;
+ margin-left: 0;
+}
+table {
+ .span1 { @include tableColumns(1); }
+ .span2 { @include tableColumns(2); }
+ .span3 { @include tableColumns(3); }
+ .span4 { @include tableColumns(4); }
+ .span5 { @include tableColumns(5); }
+ .span6 { @include tableColumns(6); }
+ .span7 { @include tableColumns(7); }
+ .span8 { @include tableColumns(8); }
+ .span9 { @include tableColumns(9); }
+ .span10 { @include tableColumns(10); }
+ .span11 { @include tableColumns(11); }
+ .span12 { @include tableColumns(12); }
+}
diff --git a/app/assets/stylesheets/bootstrap/_thumbnails.scss b/app/assets/stylesheets/bootstrap/_thumbnails.scss
new file mode 100644
index 0000000..a9795dc
--- /dev/null
+++ b/app/assets/stylesheets/bootstrap/_thumbnails.scss
@@ -0,0 +1,35 @@
+// THUMBNAILS
+// ----------
+
+.thumbnails {
+ margin-left: -$gridGutterWidth;
+ list-style: none;
+ @include clearfix();
+}
+.thumbnails > li {
+ float: left;
+ margin: 0 0 $baseLineHeight $gridGutterWidth;
+}
+.thumbnail {
+ display: block;
+ padding: 4px;
+ line-height: 1;
+ border: 1px solid #ddd;
+ @include border-radius(4px);
+ @include box-shadow(0 1px 1px rgba(0,0,0,.075));
+}
+// Add a hover state for linked versions only
+a.thumbnail:hover {
+ border-color: $linkColor;
+ @include box-shadow(0 1px 4px rgba(0,105,214,.25));
+}
+// Images and captions
+.thumbnail > img {
+ display: block;
+ max-width: 100%;
+ margin-left: auto;
+ margin-right: auto;
+}
+.thumbnail .caption {
+ padding: 9px;
+}
diff --git a/app/assets/stylesheets/bootstrap/_tooltip.scss b/app/assets/stylesheets/bootstrap/_tooltip.scss
new file mode 100644
index 0000000..89d77f9
--- /dev/null
+++ b/app/assets/stylesheets/bootstrap/_tooltip.scss
@@ -0,0 +1,35 @@
+// TOOLTIP
+// -------
+
+.tooltip {
+ position: absolute;
+ z-index: $zindexTooltip;
+ display: block;
+ visibility: visible;
+ padding: 5px;
+ font-size: 11px;
+ @include opacity(0);
+ &.in { @include opacity(80); }
+ &.top { margin-top: -2px; }
+ &.right { margin-left: 2px; }
+ &.bottom { margin-top: 2px; }
+ &.left { margin-left: -2px; }
+ &.top .tooltip-arrow { @include popoverArrow-top(); }
+ &.left .tooltip-arrow { @include popoverArrow-left(); }
+ &.bottom .tooltip-arrow { @include popoverArrow-bottom(); }
+ &.right .tooltip-arrow { @include popoverArrow-right(); }
+}
+.tooltip-inner {
+ max-width: 200px;
+ padding: 3px 8px;
+ color: $white;
+ text-align: center;
+ text-decoration: none;
+ background-color: $black;
+ @include border-radius(4px);
+}
+.tooltip-arrow {
+ position: absolute;
+ width: 0;
+ height: 0;
+}
diff --git a/app/assets/stylesheets/bootstrap/_type.scss b/app/assets/stylesheets/bootstrap/_type.scss
new file mode 100644
index 0000000..478c786
--- /dev/null
+++ b/app/assets/stylesheets/bootstrap/_type.scss
@@ -0,0 +1,218 @@
+// Typography.scss
+// Headings, body text, lists, code, and more for a versatile and durable typography system
+// ----------------------------------------------------------------------------------------
+
+
+// BODY TEXT
+// ---------
+
+p {
+ margin: 0 0 $baseLineHeight / 2;
+ font-family: $baseFontFamily;
+ font-size: $baseFontSize;
+ line-height: $baseLineHeight;
+ small {
+ font-size: $baseFontSize - 2;
+ color: $grayLight;
+ }
+}
+.lead {
+ margin-bottom: $baseLineHeight;
+ font-size: 20px;
+ font-weight: 200;
+ line-height: $baseLineHeight * 1.5;
+}
+
+// HEADINGS
+// --------
+
+h1, h2, h3, h4, h5, h6 {
+ margin: 0;
+ font-weight: bold;
+ color: $grayDark;
+ text-rendering: optimizelegibility; // Fix the character spacing for headings
+ small {
+ font-weight: normal;
+ color: $grayLight;
+ }
+}
+h1 {
+ font-size: 30px;
+ line-height: $baseLineHeight * 2;
+ small {
+ font-size: 18px;
+ }
+}
+h2 {
+ font-size: 24px;
+ line-height: $baseLineHeight * 2;
+ small {
+ font-size: 18px;
+ }
+}
+h3 {
+ line-height: $baseLineHeight * 1.5;
+ font-size: 18px;
+ small {
+ font-size: 14px;
+ }
+}
+h4, h5, h6 {
+ line-height: $baseLineHeight;
+}
+h4 {
+ font-size: 14px;
+ small {
+ font-size: 12px;
+ }
+}
+h5 {
+ font-size: 12px;
+}
+h6 {
+ font-size: 11px;
+ color: $grayLight;
+ text-transform: uppercase;
+}
+
+// Page header
+.page-header {
+ padding-bottom: $baseLineHeight - 1;
+ margin: $baseLineHeight 0;
+ border-bottom: 1px solid $grayLighter;
+}
+.page-header h1 {
+ line-height: 1;
+}
+
+
+
+// LISTS
+// -----
+
+// Unordered and Ordered lists
+ul, ol {
+ padding: 0;
+ margin: 0 0 $baseLineHeight / 2 25px;
+}
+ul ul,
+ul ol,
+ol ol,
+ol ul {
+ margin-bottom: 0;
+}
+ul {
+ list-style: disc;
+}
+ol {
+ list-style: decimal;
+}
+li {
+ line-height: $baseLineHeight;
+}
+ul.unstyled,
+ol.unstyled {
+ margin-left: 0;
+ list-style: none;
+}
+
+// Description Lists
+dl {
+ margin-bottom: $baseLineHeight;
+}
+dt,
+dd {
+ line-height: $baseLineHeight;
+}
+dt {
+ font-weight: bold;
+}
+dd {
+ margin-left: $baseLineHeight / 2;
+}
+
+// MISC
+// ----
+
+// Horizontal rules
+hr {
+ margin: $baseLineHeight 0;
+ border: 0;
+ border-top: 1px solid $hrBorder;
+ border-bottom: 1px solid $white;
+}
+
+// Emphasis
+strong {
+ font-weight: bold;
+}
+em {
+ font-style: italic;
+}
+.muted {
+ color: $grayLight;
+}
+
+// Abbreviations and acronyms
+abbr {
+ font-size: 90%;
+ text-transform: uppercase;
+ border-bottom: 1px dotted #ddd;
+ cursor: help;
+}
+
+// Blockquotes
+blockquote {
+ padding: 0 0 0 15px;
+ margin: 0 0 $baseLineHeight;
+ border-left: 5px solid $grayLighter;
+ p {
+ margin-bottom: 0;
+ @include font-shorthand(16px,300,$baseLineHeight * 1.25);
+ }
+ small {
+ display: block;
+ line-height: $baseLineHeight;
+ color: $grayLight;
+ &:before {
+ content: '\2014 \00A0';
+ }
+ }
+
+ // Float right with text-align: right
+ &.pull-right {
+ float: right;
+ padding-left: 0;
+ padding-right: 15px;
+ border-left: 0;
+ border-right: 5px solid $grayLighter;
+ p,
+ small {
+ text-align: right;
+ }
+ }
+}
+
+// Quotes
+q:before,
+q:after,
+blockquote:before,
+blockquote:after {
+ content: "";
+}
+
+// Addresses
+address {
+ display: block;
+ margin-bottom: $baseLineHeight;
+ line-height: $baseLineHeight;
+ font-style: normal;
+}
+
+// Misc
+small {
+ font-size: 100%;
+}
+cite {
+ font-style: normal;
+}
diff --git a/app/assets/stylesheets/bootstrap/_utilities.scss b/app/assets/stylesheets/bootstrap/_utilities.scss
new file mode 100644
index 0000000..d60d220
--- /dev/null
+++ b/app/assets/stylesheets/bootstrap/_utilities.scss
@@ -0,0 +1,23 @@
+// UTILITY CLASSES
+// ---------------
+
+// Quick floats
+.pull-right {
+ float: right;
+}
+.pull-left {
+ float: left;
+}
+
+// Toggling content
+.hide {
+ display: none;
+}
+.show {
+ display: block;
+}
+
+// Visibility
+.invisible {
+ visibility: hidden;
+}
diff --git a/app/assets/stylesheets/bootstrap/_variables.scss b/app/assets/stylesheets/bootstrap/_variables.scss
new file mode 100644
index 0000000..8fc17b0
--- /dev/null
+++ b/app/assets/stylesheets/bootstrap/_variables.scss
@@ -0,0 +1,107 @@
+// Variables.scss
+// Variables to customize the look and feel of Bootstrap
+// -----------------------------------------------------
+
+
+
+// GLOBAL VALUES
+// --------------------------------------------------
+
+// Links
+$linkColor: #08c !default;
+$linkColorHover: darken($linkColor, 15) !default;
+
+// Grays
+$black: #000 !default;
+$grayDarker: #222 !default;
+$grayDark: #333 !default;
+$gray: #555 !default;
+$grayLight: #999 !default;
+$grayLighter: #eee !default;
+$white: #fff !default;
+
+// Accent colors
+$blue: #049cdb !default;
+$blueDark: #0064cd !default;
+$green: #46a546 !default;
+$red: #9d261d !default;
+$yellow: #ffc40d !default;
+$orange: #f89406 !default;
+$pink: #c3325f !default;
+$purple: #7a43b6 !default;
+
+// Typography
+$baseFontSize: 13px !default;
+$baseFontFamily: "Helvetica Neue", Helvetica, Arial, sans-serif !default;
+$baseLineHeight: 18px !default;
+$textColor: $grayDark !default;
+
+// Buttons
+$primaryButtonBackground: $linkColor !default;
+
+
+
+// COMPONENT VARIABLES
+// --------------------------------------------------
+
+// Z-index master list
+// Used for a bird's eye view of components dependent on the z-axis
+// Try to avoid customizing these :)
+$zindexDropdown: 1000 !default;
+$zindexPopover: 1010 !default;
+$zindexTooltip: 1020 !default;
+$zindexFixedNavbar: 1030 !default;
+$zindexModalBackdrop: 1040 !default;
+$zindexModal: 1050 !default;
+
+// Sprite icons path
+$iconSpritePath: "../img/glyphicons-halflings.png";
+$iconWhiteSpritePath: "../img/glyphicons-halflings-white.png";
+
+// Input placeholder text color
+$placeholderText: $grayLight !default;
+
+// Hr border color
+$hrBorder: $grayLighter !default;
+
+// Navbar
+$navbarHeight: 40px !default;
+$navbarBackground: $grayDarker !default;
+$navbarBackgroundHighlight: $grayDark !default;
+$navbarLinkBackgroundHover: transparent !default;
+
+$navbarText: $grayLight !default;
+$navbarLinkColor: $grayLight !default;
+$navbarLinkColorHover: $white !default;
+
+// Form states and alerts
+$warningText: #c09853 !default;
+$warningBackground: #fcf8e3 !default;
+$warningBorder: darken(adjust-hue($warningBackground, -10), 3%) !default;
+
+$errorText: #b94a48 !default;
+$errorBackground: #f2dede !default;
+$errorBorder: darken(adjust-hue($errorBackground, -10), 3%) !default;
+
+$successText: #468847 !default;
+$successBackground: #dff0d8 !default;
+$successBorder: darken(adjust-hue($successBackground, -10), 5%) !default;
+
+$infoText: #3a87ad !default;
+$infoBackground: #d9edf7 !default;
+$infoBorder: darken(adjust-hue($infoBackground, -10), 7%) !default;
+
+
+
+// GRID
+// --------------------------------------------------
+
+// Default 940px grid
+$gridColumns: 12 !default;
+$gridColumnWidth: 60px !default;
+$gridGutterWidth: 20px !default;
+$gridRowWidth: ($gridColumns * $gridColumnWidth) + ($gridGutterWidth * ($gridColumns - 1));
+
+// Fluid grid
+$fluidGridColumnWidth: 6.382978723% !default;
+$fluidGridGutterWidth: 2.127659574% !default;
diff --git a/app/assets/stylesheets/bootstrap/_wells.scss b/app/assets/stylesheets/bootstrap/_wells.scss
new file mode 100644
index 0000000..7ad2d17
--- /dev/null
+++ b/app/assets/stylesheets/bootstrap/_wells.scss
@@ -0,0 +1,17 @@
+// WELLS
+// -----
+
+.well {
+ min-height: 20px;
+ padding: 19px;
+ margin-bottom: 20px;
+ background-color: #f5f5f5;
+ border: 1px solid #eee;
+ border: 1px solid rgba(0,0,0,.05);
+ @include border-radius(4px);
+ @include box-shadow(inset 0 1px 1px rgba(0,0,0,.05));
+ blockquote {
+ border-color: #ddd;
+ border-color: rgba(0,0,0,.15);
+ }
+}
diff --git a/app/assets/stylesheets/bootstrap/bootstrap.scss b/app/assets/stylesheets/bootstrap/bootstrap.scss
new file mode 100644
index 0000000..d65b194
--- /dev/null
+++ b/app/assets/stylesheets/bootstrap/bootstrap.scss
@@ -0,0 +1,66 @@
+/*!
+ * Bootstrap v2.0.1
+ *
+ * Copyright 2012 Twitter, Inc
+ * Licensed under the Apache License v2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Designed and built with all the love in the world @twitter by @mdo and @fat.
+ *
+ * Converted to Sass by @johnwlong / @m5o.
+ *
+ * Date: @DATE
+ */
+
+// Core variables and mixins
+@import "variables"; // Modify this for custom colors, font-sizes, etc
+@import "mixins";
+
+// CSS Reset
+@import "reset";
+
+// Grid system and page structure
+@import "scaffolding";
+@import "grid";
+@import "layouts";
+
+// Base CSS
+@import "type";
+@import "code";
+@import "forms";
+@import "tables";
+
+// Components: common
+@import "sprites";
+@import "dropdowns";
+@import "wells";
+@import "component-animations";
+@import "close";
+
+// Components: Buttons & Alerts
+@import "buttons";
+@import "button-groups";
+@import "alerts"; // Note: alerts share common CSS with buttons and thus have styles in buttons.scss
+
+// Components: Nav
+@import "navs";
+@import "navbar";
+@import "breadcrumbs";
+@import "pagination";
+@import "pager";
+
+// Components: Popovers
+@import "modals";
+@import "tooltip";
+@import "popovers";
+
+// Components: Misc
+@import "thumbnails";
+@import "labels";
+@import "progress-bars";
+@import "accordion";
+@import "carousel";
+@import "hero-unit";
+
+// Utility classes
+@import "utilities"; // Has to be last to override when necessary
diff --git a/app/assets/stylesheets/bootstrap/responsive.scss b/app/assets/stylesheets/bootstrap/responsive.scss
new file mode 100644
index 0000000..f7bd96d
--- /dev/null
+++ b/app/assets/stylesheets/bootstrap/responsive.scss
@@ -0,0 +1,337 @@
+/*!
+ * Bootstrap Responsive v2.0.1
+ *
+ * Copyright 2012 Twitter, Inc
+ * Licensed under the Apache License v2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Designed and built with all the love in the world @twitter by @mdo and @fat.
+ *
+ * Converted to Sass by @johnwlong / @m5o.
+ *
+ * Date: @DATE
+ */
+
+// Responsive.scss
+// For phone and tablet devices
+// -------------------------------------------------------------
+
+
+// REPEAT VARIABLES & MIXINS
+// -------------------------
+// Required since we compile the responsive stuff separately
+
+@import "variables"; // Modify this for custom colors, font-sizes, etc
+@import "mixins";
+
+.clearfix {
+ @include clearfix();
+}
+
+// RESPONSIVE CLASSES
+// ------------------
+
+// Hide from screenreaders and browsers
+// Credit: HTML5 Boilerplate
+.hidden {
+ display: none;
+ visibility: hidden;
+}
+
+
+
+// UP TO LANDSCAPE PHONE
+// ---------------------
+
+@media (max-width: 480px) {
+
+ // Smooth out the collapsing/expanding nav
+ .nav-collapse {
+ -webkit-transform: translate3d(0, 0, 0); // activate the GPU
+ }
+
+ // Block level the page header small tag for readability
+ .page-header h1 small {
+ display: block;
+ line-height: $baseLineHeight;
+ }
+
+ // Make span* classes full width
+ input[class*="span"],
+ select[class*="span"],
+ textarea[class*="span"],
+ .uneditable-input {
+ display: block;
+ width: 100%;
+ min-height: 28px; /* Make inputs at least the height of their button counterpart */
+ /* Makes inputs behave like true block-level elements */
+ -webkit-box-sizing: border-box; /* Older Webkit */
+ -moz-box-sizing: border-box; /* Older FF */
+ -ms-box-sizing: border-box; /* IE8 */
+ box-sizing: border-box; /* CSS3 spec*/
+ }
+ // But don't let it screw up prepend/append inputs
+ .input-prepend input[class*="span"],
+ .input-append input[class*="span"] {
+ width: auto;
+ }
+
+ // Update checkboxes for iOS
+ input[type="checkbox"],
+ input[type="radio"] {
+ border: 1px solid #ccc;
+ }
+
+ // Remove the horizontal form styles
+ .form-horizontal .control-group > label {
+ float: none;
+ width: auto;
+ padding-top: 0;
+ text-align: left;
+ }
+ // Move over all input controls and content
+ .form-horizontal .controls {
+ margin-left: 0;
+ }
+ // Move the options list down to align with labels
+ .form-horizontal .control-list {
+ padding-top: 0; // has to be padding because margin collaspes
+ }
+ // Move over buttons in .form-actions to align with .controls
+ .form-horizontal .form-actions {
+ padding-left: 10px;
+ padding-right: 10px;
+ }
+
+ // Modals
+ .modal {
+ position: absolute;
+ top: 10px;
+ left: 10px;
+ right: 10px;
+ width: auto;
+ margin: 0;
+ &.fade.in { top: auto; }
+ }
+ .modal-header .close {
+ padding: 10px;
+ margin: -10px;
+ }
+
+ // Carousel
+ .carousel-caption {
+ position: static;
+ }
+
+}
+
+
+
+// LANDSCAPE PHONE TO SMALL DESKTOP & PORTRAIT TABLET
+// --------------------------------------------------
+
+// @media (max-width: 767px) {
+// elijah: i think 767px is too wide to switch to single column.
+
+@media (max-width: 480px) {
+ // GRID & CONTAINERS
+ // -----------------
+ // Remove width from containers
+ .container {
+ width: auto;
+ padding: 0 20px;
+ }
+ // Fluid rows
+ .row-fluid {
+ width: 100%;
+ }
+ // Undo negative margin on rows
+ .row {
+ margin-left: 0;
+ }
+ // Make all columns even
+ .row > [class*="span"],
+ .row-fluid > [class*="span"] {
+ float: none;
+ display: block;
+ width: auto;
+ margin: 0;
+ }
+}
+
+
+
+// PORTRAIT TABLET TO DEFAULT DESKTOP
+// ----------------------------------
+
+@media (min-width: 768px) and (max-width: 979px) {
+
+ // Fixed grid
+ @include gridSystem-generate(12, 42px, 20px);
+
+ // Fluid grid
+ @include fluidGridSystem-generate(12, 5.801104972%, 2.762430939%);
+
+ // Input grid
+ @include inputGridSystem-generate(12, 42px, 20px);
+
+}
+
+
+
+// TABLETS AND BELOW
+// -----------------
+@media (max-width: 979px) {
+
+ // UNFIX THE TOPBAR
+ // ----------------
+ // Remove any padding from the body
+ body {
+ padding-top: 0;
+ }
+ // Unfix the navbar
+ .navbar-fixed-top {
+ position: static;
+ margin-bottom: $baseLineHeight;
+ }
+ .navbar-fixed-top .navbar-inner {
+ padding: 5px;
+ }
+ .navbar .container {
+ width: auto;
+ padding: 0;
+ }
+ // Account for brand name
+ .navbar .brand {
+ padding-left: 10px;
+ padding-right: 10px;
+ margin: 0 0 0 -5px;
+ }
+ // Nav collapse clears brand
+ .navbar .nav-collapse {
+ clear: left;
+ }
+ // Block-level the nav
+ .navbar .nav {
+ float: none;
+ margin: 0 0 ($baseLineHeight / 2);
+ }
+ .navbar .nav > li {
+ float: none;
+ }
+ .navbar .nav > li > a {
+ margin-bottom: 2px;
+ }
+ .navbar .nav > .divider-vertical {
+ display: none;
+ }
+ .navbar .nav .nav-header {
+ color: $navbarText;
+ text-shadow: none;
+ }
+ // Nav and dropdown links in navbar
+ .navbar .nav > li > a,
+ .navbar .dropdown-menu a {
+ padding: 6px 15px;
+ font-weight: bold;
+ color: $navbarLinkColor;
+ @include border-radius(3px);
+ }
+ .navbar .dropdown-menu li + li a {
+ margin-bottom: 2px;
+ }
+ .navbar .nav > li > a:hover,
+ .navbar .dropdown-menu a:hover {
+ background-color: $navbarBackground;
+ }
+ // Dropdowns in the navbar
+ .navbar .dropdown-menu {
+ position: static;
+ top: auto;
+ left: auto;
+ float: none;
+ display: block;
+ max-width: none;
+ margin: 0 15px;
+ padding: 0;
+ background-color: transparent;
+ border: none;
+ @include border-radius(0);
+ @include box-shadow(none);
+ }
+ .navbar .dropdown-menu:before,
+ .navbar .dropdown-menu:after {
+ display: none;
+ }
+ .navbar .dropdown-menu .divider {
+ display: none;
+ }
+ // Forms in navbar
+ .navbar-form,
+ .navbar-search {
+ float: none;
+ padding: ($baseLineHeight / 2) 15px;
+ margin: ($baseLineHeight / 2) 0;
+ border-top: 1px solid $navbarBackground;
+ border-bottom: 1px solid $navbarBackground;
+ $shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);
+ @include box-shadow($shadow);
+ }
+ // Pull right (secondary) nav content
+ .navbar .nav.pull-right {
+ float: none;
+ margin-left: 0;
+ }
+ // Static navbar
+ .navbar-static .navbar-inner {
+ padding-left: 10px;
+ padding-right: 10px;
+ }
+ // Navbar button
+ .btn-navbar {
+ display: block;
+ }
+
+ // Hide everything in the navbar save .brand and toggle button */
+ .nav-collapse {
+ overflow: hidden;
+ height: 0;
+ }
+}
+
+
+
+// DEFAULT DESKTOP
+// ---------------
+
+@media (min-width: 980px) {
+ .nav-collapse.collapse {
+ height: auto !important;
+ }
+}
+
+
+
+// LARGE DESKTOP & UP
+// ------------------
+
+@media (min-width: 1200px) {
+
+ // Fixed grid
+ //@include gridSystem-generate(12, 70px, 30px);
+
+ // Fluid grid
+ @include fluidGridSystem-generate(12, 5.982905983%, 2.564102564%);
+
+ // Input grid
+ @include inputGridSystem-generate(12, 70px, 30px);
+
+ // Thumbnails
+ .thumbnails {
+ margin-left: -30px;
+ }
+ .thumbnails > li {
+ margin-left: 30px;
+ }
+
+}
diff --git a/app/assets/stylesheets/leap.scss b/app/assets/stylesheets/leap.scss
new file mode 100644
index 0000000..71be997
--- /dev/null
+++ b/app/assets/stylesheets/leap.scss
@@ -0,0 +1,176 @@
+
+
+$background_color: #fff;
+
+$masthead_border_color: black; // rgba(0,0,0,0.5);
+$masthead_border: 1px solid $masthead_border_color;
+$masthead_bg_color: #333; // rgba(96,96,96,0.2);
+$masthead_color: #fff;
+$masthead_height: 128px;
+
+$masthead_text_left_margin: 150px;
+$masthead_text_top_margin: 45px;
+$masthead_text_size: 36px;
+
+$cutout_color: darken($background_color,12%);
+
+$side_column_bg_color: #d0d0d0; // rgba(0,0,0,0.05); // #e3e3e3
+$side_column_border_color: #aaa; // rgba(0,0,0,0.2);
+$side_column_active_bg_color: #000;
+$side_column_active_color: $masthead_color;
+
+$well_color: #fff;
+$well_bg_color: #fff;
+$well_border_color: #555;
+
+body {
+ //background: #F5F1E8 url(/img/bg-sand.png) repeat-x;
+ background-color: $background_color;
+}
+
+.masthead {
+ border: $masthead_border;
+ background: $masthead_bg_color;
+ @include gradient-vertical(lighten($masthead_bg_color,8%),$masthead_bg_color);
+ border-top: none;
+ box-shadow: inset 0 0 8px 1px darken($masthead_bg_color, 8%);
+ box-shadow-top: 0;
+ .contents {
+ @include cutout-menu(topnav, $masthead_text_left_margin, $cutout_color, $masthead_border);
+ height: $masthead_height;
+ background: url(/img/leap-color-small.png) 10px 50% no-repeat;
+ }
+ h1 {
+ margin: 0;
+ color: $masthead_color;
+ line-height: $masthead_height;
+ font-size: $masthead_text_size;
+ white-space: nowrap;
+ overflow: hidden;
+ padding-left: $masthead_text_left_margin - 2px;
+ }
+ #topnav a.tab {
+ font-weight: bold;
+ color: white;
+ background: rgba(0,0,0,0.5);
+ &.active {
+ color: black;
+ }
+ }
+}
+
+.nav-tabs.nav-stacked li {
+ background: $side_column_bg_color;
+ a {
+ border-radius: 0 !important;
+ border: 0; //1px solid $side_column_border_color;
+ border-right: 4px solid $side_column_active_bg_color;
+ color: black;
+ line-height: 1.2em;
+ &:hover {
+ background: lighten($side_column_bg_color,20%);
+ border-color: lighten($side_column_active_bg_color, 50%);
+ text-decoration: underline;
+ // border: 1px solid $side_column_border_color;
+ }
+ &.level2 {
+ padding-left: 2em;
+ }
+ }
+ &.active a {
+ border: 0;
+ border-color: $side_column_active_bg_color;
+ background: $side_column_active_bg_color;
+ color: $side_column_active_color;
+ cursor: pointer;
+ }
+}
+
+.side_column ul {
+ box-shadow: 2px 4px 4px 0px darken($background_color,40%);
+ //background: $side_column_bg_color;
+ //box-shadow: inset 0px 0px 5px 2px darken($side_column_bg_color,10%);
+}
+
+.background {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ height: 400px;
+ z-index: -1;
+ @include gradient-vertical(darken($background_color, 17%), $background_color);
+}
+
+.pullout {
+ background: rgba(0,0,0,.1);
+}
+
+//
+// like bootstrap well, but not roundy
+//
+
+.well {
+ min-height: 20px;
+ padding: 19px;
+ margin-bottom: 11px; // same as 'p', not sure what variable this is.
+ background-color: $well_bg_color;
+ //@include gradient-vertical($well_bg_color, lighten($well_bg_color, 20%));
+ box-shadow: inset 0px 0px 4px 2px darken($well_bg_color,10%);
+ //box-shadow: 3px 3px 4px 2px rgba(0,0,0,0.05); // darken($background_color,10%);
+ border: 1px solid lighten($well_border_color,50%);
+ .heading {
+ margin-top: -6px;
+ margin-bottom: 6px;
+ //margin: -20px;
+ //margin-bottom: 0.75em;
+ //padding: 6px 19px;
+ //background: $well_border_color;
+ //color: $well_color;
+ font-weight: bold;
+ font-size: 1.1em;
+ }
+}
+
+//
+// inverted headings
+//
+
+.invert {
+ color: white;
+ background-color: $well_border_color;
+ padding-left: 12px;
+}
+
+
+table.timeline {
+ td:first-child {
+ text-align: right;
+ white-space: nowrap;
+ padding-right: 0;
+ }
+ td {
+ vertical-align: top;
+ padding: 6px;
+ }
+}
+
+//
+// blog stuff
+//
+
+
+article.blog_summary {
+ .byline {
+ color: #999;
+ }
+}
+
+article.blog_full {
+ .byline {
+ font-weight: bold;
+ margin-bottom: 0.5em;
+ font-size: 1em;
+ color: #999;
+ }
+}
diff --git a/app/assets/stylesheets/mixins.scss b/app/assets/stylesheets/mixins.scss
new file mode 100644
index 0000000..93cbc44
--- /dev/null
+++ b/app/assets/stylesheets/mixins.scss
@@ -0,0 +1,172 @@
+// Gradients
+@mixin gradient-horizontal($startColor: #555, $endColor: #333) {
+ background-color: $endColor;
+ background-image: -moz-linear-gradient(left, $startColor, $endColor); // FF 3.6+
+ background-image: -ms-linear-gradient(left, $startColor, $endColor); // IE10
+ background-image: -webkit-gradient(linear, 0 0, 100% 0, from($startColor), to($endColor)); // Safari 4+, Chrome 2+
+ background-image: -webkit-linear-gradient(left, $startColor, $endColor); // Safari 5.1+, Chrome 10+
+ background-image: -o-linear-gradient(left, $startColor, $endColor); // Opera 11.10
+ background-image: linear-gradient(left, $startColor, $endColor); // Le standard
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#{$startColor}', endColorstr='#{$endColor}', GradientType=1), $startColor, $endColor; // IE9 and down
+}
+@mixin gradient-vertical($startColor: #555, $endColor: #333) {
+ background-color: mix($startColor, $endColor, 60%);
+ background-image: -moz-linear-gradient(top, $startColor, $endColor); // FF 3.6+
+ background-image: -ms-linear-gradient(top, $startColor, $endColor); // IE10
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from($startColor), to($endColor)); // Safari 4+, Chrome 2+
+ background-image: -webkit-linear-gradient(top, $startColor, $endColor); // Safari 5.1+, Chrome 10+
+ background-image: -o-linear-gradient(top, $startColor, $endColor); // Opera 11.10
+ background-image: linear-gradient(top, $startColor, $endColor); // The standard
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#{$startColor}', endColorstr='#{$endColor}', GradientType=0),$startColor,$endColor; // IE9 and down
+}
+@mixin gradient-directional($startColor: #555, $endColor: #333, $deg: 45deg) {
+ background-color: $endColor;
+ background-repeat: repeat-x;
+ background-image: -moz-linear-gradient($deg, $startColor, $endColor); // FF 3.6+
+ background-image: -ms-linear-gradient($deg, $startColor, $endColor); // IE10
+ background-image: -webkit-linear-gradient($deg, $startColor, $endColor); // Safari 5.1+, Chrome 10+
+ background-image: -o-linear-gradient($deg, $startColor, $endColor); // Opera 11.10
+ background-image: linear-gradient($deg, $startColor, $endColor); // The standard
+}
+@mixin gradient-vertical-three-colors($startColor: #00b3ee, $midColor: #7a43b6, $colorStop: 50%, $endColor: #c3325f) {
+ background-color: mix($midColor, $endColor, 80%);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from($startColor), color-stop($colorStop, $midColor), to($endColor));
+ background-image: -webkit-linear-gradient($startColor, $midColor $colorStop, $endColor);
+ background-image: -moz-linear-gradient(top, $startColor, $midColor $colorStop, $endColor);
+ background-image: -ms-linear-gradient($startColor, $midColor $colorStop, $endColor);
+ background-image: -o-linear-gradient($startColor, $midColor $colorStop, $endColor);
+ background-image: linear-gradient($startColor, $midColor $colorStop, $endColor);
+ background-repeat: no-repeat;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#{$startColor}', endColorstr='#{$endColor}', GradientType=0), $startColor, $endColor; // IE9 and down, gets no color-stop at all the proper fallback
+}
+@mixin gradient-radial($innerColor: #555, $outerColor: #333) {
+ background-color: $outerColor;
+ background-image: -webkit-gradient(radial, center center, 0, center center, 460, from($innerColor), to($outerColor));
+ background-image: -webkit-radial-gradient(circle, $innerColor, $outerColor);
+ background-image: -moz-radial-gradient(circle, $innerColor, $outerColor);
+ background-image: -ms-radial-gradient(circle, $innerColor, $outerColor);
+ background-repeat: no-repeat;
+ // Opera cannot do radial gradients yet
+}
+@mixin gradient-striped($color,$angle: -45deg) {
+ background-color: $color;
+ background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(.25, rgba(255,255,255,.15)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, rgba(255,255,255,.15)), color-stop(.75, rgba(255,255,255,.15)), color-stop(.75, transparent), to(transparent));
+ background-image: -webkit-linear-gradient($angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent);
+ background-image: -moz-linear-gradient($angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent);
+ background-image: -ms-linear-gradient($angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent);
+ background-image: -o-linear-gradient($angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent);
+ //background-image: linear-gradient($angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent);
+ }
+
+// Gradient Bar Colors for buttons and alerts
+@mixin gradientBar($primaryColor, $secondaryColor) {
+ @include gradient-vertical($primaryColor, $secondaryColor);
+ border-color: $secondaryColor $secondaryColor darken($secondaryColor, 15%);
+ border-color: rgba(0,0,0,.1) rgba(0,0,0,.1) fade-in(rgba(0,0,0,.1), 0.15);
+}
+
+// Reset filters for IE
+@mixin reset-filter() {
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+}
+
+
+//
+// An UL,LI menu that looks like a cutout and is positioned at the bottom
+// of the enclosing block.
+//
+// This mixin is applied to the enclosing block.
+//
+// the markup should look like this:
+//
+// enclosing-block
+// ul#id
+// li.tab
+// a.tab
+// li.tab
+// a.tab
+//
+// the id for the ul is passed in as the first argument.
+//
+// it is difficult to create cutout tabs with a border that look good
+// in all browsers and at different client font-sizes.
+//
+// the problem is that the tab element needs to line up exactly with the
+// bottom of the enclosing block in order to make the cutout illusion work.
+// most methods of doing this create weird jitters in webkit
+// and gecko when resizing the screen or changing the font size. it does not
+// look so good to have a dark line under your tab, breaking the illusion of
+// a cutout.
+//
+// the method which makes this jitter-free is to use a height and a line-height
+// for the <a> tag instead of vertical padding. This requires that <a> is a block
+// which requires that the <li> is block & floated, instead of inline.
+//
+// This method seems to produce by far the most consistant results of letting
+// the active tab sit snugly on the bottom of the enclosing div.
+//
+// Change with caution: I spent way too much time getting this to work.
+//
+
+@mixin cutout-menu(
+ $ul_id,
+ $tab_margin: 10px,
+ $active_background: white,
+ $active_border: false) {
+
+ // allows us to put the menu at the bottom
+ position: relative;
+
+ ul##{$ul_id} {
+ margin: 0;
+ padding: 0;
+
+ // allows us to put the menu at the bottom
+ position: absolute;
+
+ // puts the menu at the bottom of the enclosing block,
+ // minus the overhand needed to cover the border:
+ // bottom: -(border_width($active_border));
+ bottom: -1px;
+
+ // padding-left: don't do it.
+ // ^^ In some cases, we need width of 100% to actually be the screen width,
+ // but adding padding makes 100% width be wider than the screen.
+ // So, instead, we add margin to the first and last li.
+
+ white-space: nowrap;
+
+ li.tab {
+ display: block;
+ float: left;
+ &.first {margin-left: $tab_margin;}
+ &.last {margin-right: $tab_margin;}
+ a.tab {
+ // @include cg-hover-link;
+ display: block;
+ padding: 3px 15px;
+
+ // using height and line-height makes for much more consistant rendering
+ // than using vertical padding. essential to prevent tabs from looking
+ // horrible at different fonts sizes.
+ height: 1.75em;
+ line-height: 1.75em;
+
+ // the transparent border is needed to prevent the menu from jittering
+ // when the active border is applied.
+ border: 1px solid transparent;
+ border-bottom: 0;
+
+ &.active {
+ background-color: $active_background;
+ @if $active_border {
+ border: $active_border;
+ border-bottom: 0;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/app/assets/stylesheets/superfluid.scss b/app/assets/stylesheets/superfluid.scss
new file mode 100644
index 0000000..3280fb6
--- /dev/null
+++ b/app/assets/stylesheets/superfluid.scss
@@ -0,0 +1,113 @@
+//
+// This is a simple CSS for a very fluid layout. One could say it is SUPER fluid.
+// functions taken from susy.
+//
+// HTML
+//
+// .top
+// .column_countainer
+// .column_content
+// .middle
+// .column_container
+// .column_content
+// .bottom
+// .column_container
+// .column_content
+//
+
+//
+// DEFAULTS
+//
+
+$total-columns: $gridColumns !default;
+$side-columns: 2 !default;
+
+$column-width: $gridColumnWidth !default;
+$gutter-width: $gridGutterWidth !default;
+
+//
+// FUNCTIONS
+//
+
+//
+// Returns the width of the specified number of columns
+// $columns => The number of columns to get width for.
+//
+@function columns-width($columns : $total-columns) {
+ @return ($columns * $column-width) + (ceil($columns - 1) * $gutter-width);
+}
+
+//
+// Returns the full width of all columns
+//
+@function full-width() {
+ @return columns-width();
+}
+
+//
+// Return the percentage width of a single gutter in a given column context.
+// $context => The grid context in columns, if nested.
+//
+@function gutter($context : $total-columns) {
+ @return percentage($gutter-width / columns-width($context));
+}
+
+//
+// Return the percentage width of multiple 'columns' in a given 'context'.
+// $columns => The number of columns to get relative width for.
+// $context => The grid context in columns, if nested.
+//
+@function columns($columns, $context : $total-columns) {
+ @return percentage(columns-width($columns) / columns-width($context));
+}
+
+//
+// CSS
+//
+
+.column_container {
+ *zoom: 1;
+ margin-left: auto;
+ margin-right: auto;
+ width: full-width();
+ max-width: 100%;
+}
+
+.column_content {
+ padding-left: gutter();
+ padding-right: gutter();
+}
+
+.middle .column_container:after {
+ content: "\0020";
+ display: block;
+ height: 0;
+ clear: both;
+ overflow: hidden;
+ visibility: hidden;
+}
+
+.middle .column_content {
+ padding-top: gutter();
+ padding-bottom: gutter();
+}
+
+.main_column.with_side_column {
+ width: columns($total-columns - $side-columns);
+ margin-left: gutter();
+ float: left;
+ // without left float, we would use this:
+ // margin-left: columns($side-columns) + gutter();
+ // but that creates problems if we have floated columns inside this main column
+}
+
+//.article.full {
+// margin-left: 0;
+// width: columns;
+//}
+
+.side_column {
+ display: inline;
+ float: left;
+ width: columns($side-columns);
+}
diff --git a/app/assets/stylesheets/typography.scss b/app/assets/stylesheets/typography.scss
new file mode 100644
index 0000000..651eebf
--- /dev/null
+++ b/app/assets/stylesheets/typography.scss
@@ -0,0 +1,33 @@
+.p {
+ margin-top: 1em;
+ margin-bottom: 1em;
+ &:first-child {
+ margin-top: 0;
+ }
+}
+
+//
+// make headings and paragraphs that are at the top of the page fit more snugly against the top.
+//
+h1, h2, h3 {
+ &.first {
+ line-height: 0.8em;
+ margin-bottom: 0.4em
+ }
+}
+p.first {
+ margin-top: 0 !important;
+}
+
+.ol {@extend ol}
+.li {@extend li}
+
+.h1 {@extend h1}
+.h2 {@extend h2}
+.h3 {@extend h3}
+
+.bigger {
+ font-size: 140%;
+ line-height: 140%;
+ margin: 20px 0;
+} \ No newline at end of file
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
new file mode 100644
index 0000000..62a4e13
--- /dev/null
+++ b/app/controllers/application_controller.rb
@@ -0,0 +1,88 @@
+
+class ApplicationController < ActionController::Base
+ protect_from_forgery
+ before_filter :set_locale, :initialize_pages
+
+ if Rails.env == 'production'
+ rescue_from Exception, :with => :render_500
+ rescue_from ActionController::RoutingError, :with => :render_404
+ end
+
+ protected
+
+ ##
+ ## LOCALIZATION
+ ##
+
+ #
+ # ensure that the locale is encoded as the url prefix and I18n.locale is set.
+ #
+ def set_locale
+ if params[:locale].nil? || !AVAILABLE_LANGUAGES.include?(params[:locale])
+ locale = HttpAcceptLanguage::compatible_language_from(request.headers['HTTP_ACCEPT_LANGUAGE'], AVAILABLE_LANGUAGES) || DEFAULT_LOCALE
+ locale = locale.to_s.sub('-', '_').sub(/_\w\w/, '')
+ if request.path == '/'
+ url = '/' + locale
+ else
+ url = url_for(params.merge(:locale => locale))
+ end
+ redirect_to url
+ else
+ I18n.locale = params[:locale]
+ self.default_url_options[:locale] = params[:locale]
+ end
+ end
+
+ #def default_url_options
+ # {:locale => locale }
+ #end
+
+ ##
+ ## RENDERING
+ ##
+
+ def render_500
+ render :template => 'errors/error', :status => 500
+ end
+
+ def render_404
+ render :template => 'errors/not_found', :status => 404
+ end
+
+ #
+ # renders the content of a static page
+ #
+ def render_page(page)
+ begin
+ render :template => page.template_path
+ rescue ActionView::MissingTemplate => exc
+ begin
+ render :template => page.template_path(DEFAULT_LOCALE)
+ rescue
+ raise exc
+ end
+ end
+ end
+
+ ##
+ ## INITIALIZATION
+ ##
+
+ #
+ # run every time in development mode, run once in production mode
+ #
+ def initialize_pages
+ run_once(:unless => Rails.env.development?) do
+ StaticPage.load(PAGE_DIRECTORY)
+ Menu.load(PAGE_DIRECTORY + '/menu.txt')
+ end
+ end
+
+ def run_once(options={})
+ if !@run_once || !options[:unless]
+ yield
+ end
+ @run_once = true
+ end
+
+end
diff --git a/app/controllers/pages_controller.rb b/app/controllers/pages_controller.rb
new file mode 100644
index 0000000..c86f313
--- /dev/null
+++ b/app/controllers/pages_controller.rb
@@ -0,0 +1,29 @@
+class PagesController < ApplicationController
+
+ class PageNotFound < Exception; end
+
+ layout :choose_layout
+ rescue_from ActionView::MissingTemplate, :with => :render_404
+ rescue_from PageNotFound, :with => :render_404
+
+ def show
+ @page = StaticPage.find(params[:page])
+ if @page
+ render_page(@page)
+ else
+ raise PageNotFound.new
+ end
+ end
+
+ protected
+
+ def choose_layout
+ if @page && @page.props.layout
+ @page.props.layout
+ else
+ 'application'
+ end
+ end
+
+end
+
diff --git a/app/controllers/root_controller.rb b/app/controllers/root_controller.rb
new file mode 100644
index 0000000..939145d
--- /dev/null
+++ b/app/controllers/root_controller.rb
@@ -0,0 +1,11 @@
+class RootController < ApplicationController
+
+ #
+ # for now, just redirect to locale using before filter set in ApplicationController
+ #
+ def index
+ # never called
+ end
+
+end
+
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
new file mode 100644
index 0000000..903549b
--- /dev/null
+++ b/app/helpers/application_helper.rb
@@ -0,0 +1,91 @@
+module ApplicationHelper
+
+ def main_column_class
+ if has_side_column?
+ 'with_side_column'
+ else
+ 'full'
+ end
+ end
+
+ #
+ # two forms:
+ #
+ # (1) link('page-name')
+ # (2) link('label' => 'page-name')
+ #
+ # both accept optional options hash:
+ #
+ # (1) link('page-name', :class => 'x')
+ # (2) link('label' => 'page-name', :class => 'x')
+ #
+ def link(name, options=nil)
+ if name.is_a? Hash
+ klass = name.delete(:class)
+ label, name = name.to_a.first
+ if label.is_a? Symbol
+ label = I18n.t label
+ end
+ else
+ klass = options[:class] if options
+ end
+ if name.starts_with?('#')
+ path = name
+ else
+ page = StaticPage.find(name)
+ if page
+ label ||= page.title
+ path = page_path(page)
+ else
+ label = '[dead link]'
+ path = '/'
+ end
+ end
+ link_to label, path, {:class => klass}
+ end
+
+ def page_path(page)
+ '/' + ([I18n.locale.to_s] + page.path).join('/')
+ end
+
+ #
+ # allows a template to render a partial giving a relative path (relative to the calling template)
+ #
+ def render_local_template(arg, locals={})
+ caller_path = Pathname.new(caller.first.gsub(/^([^:]*).*$/, '\1'))
+ doc_root = Pathname.new(Rails.root + 'app/views')
+ template_path = File.dirname(caller_path.relative_path_from(doc_root).to_s) + '/' + arg
+ begin
+ render :template => template_path, :locals => locals
+ rescue ActionView::MissingTemplate => exc
+ "<!-- template missing %s -->" % template_path
+ end
+ end
+
+ def page_title
+ if @page
+ @page.props.title || @page.title
+ else
+ ""
+ end
+ end
+
+ #
+ # renders the content of a static page
+ # this is an ugly duplicate of the application controller render_page, because
+ # they call two different 'render' methods (controller and view renders behave differently).
+ # TODO: figure out how to combine into one helper_method.
+ #
+ def render_page(page)
+ begin
+ render :template => page.template_path
+ rescue ActionView::MissingTemplate => exc
+ begin
+ render :template => page.template_path(DEFAULT_LOCALE)
+ rescue
+ raise exc
+ end
+ end
+ end
+
+end
diff --git a/app/helpers/blog_helper.rb b/app/helpers/blog_helper.rb
new file mode 100644
index 0000000..20e4113
--- /dev/null
+++ b/app/helpers/blog_helper.rb
@@ -0,0 +1,15 @@
+module BlogHelper
+
+ def recent_blog_summaries(path)
+ root = StaticPage.find(path)
+ if root
+ pages = root.all_children.order_by(:posted_at).limit(PAGINATION_SIZE)
+ haml do
+ pages.each do |page|
+ haml render(:partial => 'layouts/blog/summary', :locals => {:page => page})
+ end
+ end
+ end
+ end
+
+end
diff --git a/app/helpers/haml_helper.rb b/app/helpers/haml_helper.rb
new file mode 100644
index 0000000..dae0149
--- /dev/null
+++ b/app/helpers/haml_helper.rb
@@ -0,0 +1,54 @@
+require 'pathname'
+
+module HamlHelper
+
+ #
+ # acts like haml_tag, capture_haml, or haml_concat, depending on how it is called.
+ #
+ # two or more args --> like haml_tag
+ # one arg and a block --> like haml_tag
+ # zero args and a block --> like capture_haml
+ # one arg and no block --> like haml_concat
+ #
+ # additionally, we allow the use of more than one class.
+ #
+ # some examples of these usages:
+ #
+ # def display_robot(robot)
+ # haml do # like capture_haml
+ # haml '.head', robot.head_html # like haml_tag
+ # haml '.head' do # same
+ # haml robot.head_html
+ # end
+ # haml '.body.metal', robot.body_html # like haml_tag, but with multiple classes
+ # haml '<a href="/x">link</a>' # like haml_concat
+ # end
+ # end
+ #
+ # wrapping the helper in a capture_haml call is very useful, because then
+ # the helper can be used wherever a normal helper would be.
+ #
+ def haml(name=nil, *args, &block)
+ if name
+ if args.empty? and block.nil?
+ haml_concat name
+ else
+ if name =~ /^(.*?\.[^\.]*)(\..*)$/
+ # allow chaining of classes if there are multiple '.' in the first arg
+ name = $1
+ classes = $2.gsub('.',' ')
+ hsh = args.detect{|i| i.is_a?(Hash)}
+ unless hsh
+ hsh = {}
+ args << hsh
+ end
+ hsh[:class] = classes
+ end
+ haml_tag(name, *args, &block)
+ end
+ else
+ capture_haml(&block)
+ end
+ end
+
+end \ No newline at end of file
diff --git a/app/helpers/navigation_helper.rb b/app/helpers/navigation_helper.rb
new file mode 100644
index 0000000..8582391
--- /dev/null
+++ b/app/helpers/navigation_helper.rb
@@ -0,0 +1,84 @@
+module NavigationHelper
+
+ def has_side_column?
+ second_level_children_count = Menu.menu.submenu(current_page_path.first).try(:size)
+ if second_level_children_count.nil?
+ false
+ else
+ second_level_children_count > 1
+ end
+ end
+
+ def top_level_navigation_links
+ haml do
+ first = 'first'
+ Menu.menu.each do |item|
+ active = current_page_path.first == item.name ? 'active' : ''
+ haml 'li.tab', :class => first do
+ haml 'a.tab', I18n.t('pages.' + item.name), :href => menu_item_path(item), :class => active
+ end
+ first = ''
+ end
+ end
+ end
+
+ def side_column_navigation_links
+ if menu = Menu.menu.submenu(current_page_path.first)
+ haml do
+ haml 'ul.nav.nav-tabs.nav-stacked' do
+ display_menu(menu, 1)
+ end
+ end
+ end
+ end
+
+ def act_as(page)
+ page = StaticPage.find(page)
+ @current_page_path = page.path
+ render_page(page)
+ end
+
+ private
+
+ def menu_item_path(item)
+ "/#{I18n.locale}/#{item.path.join('/')}"
+ end
+
+ def display_menu(menu, level=0)
+ menu.each do |item|
+ haml 'li', :class => path_active(current_page_path, item) do
+ haml 'a', I18n.t('pages.'+item.name), :href => menu_item_path(item), :class => "level#{level}"
+ end
+ display_menu(item.submenu, level+1)
+ end
+ end
+
+ def path_active(page_path, menu_item)
+ array_starts_with(page_path, menu_item.path) ? 'active' : ''
+ end
+
+ def current_page_path
+ @current_page_path ||= begin
+ if @page
+ @page.path
+ elsif params[:page].is_a? String
+ params[:page].split('/')
+ else
+ []
+ end
+ end
+ end
+
+ #
+ # returns true if first part of array_long contains array_short
+ #
+ def array_starts_with(array_long, array_short)
+ array_short.length.times do |i|
+ if array_short[i] != array_long[i]
+ return false
+ end
+ end
+ return true
+ end
+
+end
diff --git a/app/mailers/.gitkeep b/app/mailers/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/app/mailers/.gitkeep
diff --git a/app/models/.gitkeep b/app/models/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/app/models/.gitkeep
diff --git a/app/views/errors/error.html.haml b/app/views/errors/error.html.haml
new file mode 100644
index 0000000..7f16eb5
--- /dev/null
+++ b/app/views/errors/error.html.haml
@@ -0,0 +1,3 @@
+.dialog
+ %h1
+ We're sorry, but something went wrong. \ No newline at end of file
diff --git a/app/views/errors/not_found.html.haml b/app/views/errors/not_found.html.haml
new file mode 100644
index 0000000..79cbbf9
--- /dev/null
+++ b/app/views/errors/not_found.html.haml
@@ -0,0 +1,3 @@
+.dialog
+ %h1 The page you were looking for doesn't exist.
+ %p You may have mistyped the address or the page may have moved.
diff --git a/app/views/layouts/_footer.haml b/app/views/layouts/_footer.haml
new file mode 100644
index 0000000..94ea6dc
--- /dev/null
+++ b/app/views/layouts/_footer.haml
@@ -0,0 +1,7 @@
+%div{:style => 'max-width:500px; margin: 3em auto 0 auto; text-align: center; font-size: 0.85em'}
+ (cc) Attribution, Share-Alike
+ &nbsp;
+ %a{:rel => "license", :href => "https://creativecommons.org/licenses/by-sa/3.0/"}<
+ %img{:alt => "Creative Commons License", :style => "border-width:0; vertical-align: middle", :src => "/img/by-sa-3.0-80x15.png"}
+ &nbsp;
+ (c) 2012 LEAP Encryption Access Project \ No newline at end of file
diff --git a/app/views/layouts/_masthead.html.haml b/app/views/layouts/_masthead.html.haml
new file mode 100644
index 0000000..5055c81
--- /dev/null
+++ b/app/views/layouts/_masthead.html.haml
@@ -0,0 +1,7 @@
+.container.masthead
+ .contents
+ .text
+ %h1 LEAP Encryption Access Project
+ %ul#topnav
+ = top_level_navigation_links
+
diff --git a/app/views/layouts/_topnav.html.haml b/app/views/layouts/_topnav.html.haml
new file mode 100644
index 0000000..d0d553e
--- /dev/null
+++ b/app/views/layouts/_topnav.html.haml
@@ -0,0 +1,8 @@
+%ul#topnav
+ = top_level_navigation_links
+ %li.tab.first
+ %a.tab{:href => '#'} Home
+ %li.tab
+ %a.tab.active{:href => '#'} Technology
+ %li.tab
+ %a.tab About Us \ No newline at end of file
diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml
new file mode 100644
index 0000000..fe0888a
--- /dev/null
+++ b/app/views/layouts/application.html.haml
@@ -0,0 +1,29 @@
+!!! 5
+%html{:dir=>'ltr'}
+ %head
+ %title #{SITE_TITLE} - #{page_title}
+ = stylesheet_link_tag "application", :media => "all"
+ = javascript_include_tag "application"
+ = csrf_meta_tags
+ %body
+ .top
+ .column_container
+ .column_content
+ .masthead
+ .contents
+ %h1 LEAP Encryption Access Project
+ %ul#topnav
+ = top_level_navigation_links
+ .middle
+ .column_container
+ .column_content
+ - if has_side_column?
+ .side_column
+ = side_column_navigation_links
+ .main_column{:class => main_column_class}
+ = content_for?(:content) ? yield(:content) : yield
+ .bottom
+ .column_container
+ .column_content
+ = render :partial => 'layouts/footer'
+ .background
diff --git a/app/views/layouts/blog.html.haml b/app/views/layouts/blog.html.haml
new file mode 100644
index 0000000..3e693c9
--- /dev/null
+++ b/app/views/layouts/blog.html.haml
@@ -0,0 +1,6 @@
+- content_for :content do
+ - if @page
+ = render :template => 'layouts/blog/show'
+ - else
+ = yield
+= render :template => 'layouts/application' \ No newline at end of file
diff --git a/app/views/layouts/blog/_summary.html.haml b/app/views/layouts/blog/_summary.html.haml
new file mode 100644
index 0000000..c1f7784
--- /dev/null
+++ b/app/views/layouts/blog/_summary.html.haml
@@ -0,0 +1,17 @@
+%article.blog_summary
+ %heading.h3= link_to(page.title, page_path(page))
+ .byline
+ - if page.props.author
+ %span.author>= page.props.author
+ - if page.props.author && page.props.posted_at
+ \.
+ - if page.props.posted_at
+ %i
+ = time_tag(page.props.posted_at.to_date, :format => :long, :pubdate => true)
+ %div.content
+ - if page.props.preview
+ = page.props.preview
+ - if page.props.body.try(:any?)
+ = link_to(I18n.t(:read_more), page_path(page))
+ - else
+ = render :template => page.template_path \ No newline at end of file
diff --git a/app/views/layouts/blog/show.html.haml b/app/views/layouts/blog/show.html.haml
new file mode 100644
index 0000000..b5bc983
--- /dev/null
+++ b/app/views/layouts/blog/show.html.haml
@@ -0,0 +1,20 @@
+%article.blog_full
+
+ %h1.first= @page.title
+
+ .byline
+ - if @page.props.author
+ %span.author>= I18n.t('posted_by') + ' ' + @page.props.author
+ - if @page.props.author && @page.props.posted_at
+ \.
+ - if @page.props.posted_at
+ %i
+ = time_tag(@page.props.posted_at.to_date, :format => :long, :pubdate => true)
+
+ - content_for :blog_content do
+ = yield
+
+ - if content_for?(:blog_content)
+ = yield(:blog_content)
+ - else
+ = @page.props.preview \ No newline at end of file
diff --git a/app/views/pages/about-us/contact/en.haml b/app/views/pages/about-us/contact/en.haml
new file mode 100644
index 0000000..e96323e
--- /dev/null
+++ b/app/views/pages/about-us/contact/en.haml
@@ -0,0 +1,32 @@
+%h3 IRC
+
+Probably the fastest and most reliable way to contact anyone involved with LEAP. Don't despair if you don't get a reply right away, we are all in different time zones and we all are able to read the scrollback history, so someone will reply eventually.
+
+.well
+ \#leap-dev on freenode.net
+
+%h3 Email
+
+Email is pretty good too.
+
+.well
+ info@leap.se
+
+%h3 Postal Address
+
+It may take us a very long time to respond to postal mail.
+
+.well
+ PO Box 4422
+ %br
+ Seattle, WA 98194 USA
+
+%h3 Phone (Voice Mail)
+
+Leave us a message, bonus points if you sing your message.
+
+.well
+ +1 (206) 420-6613
+
+
+
diff --git a/app/views/pages/about-us/en.haml b/app/views/pages/about-us/en.haml
new file mode 100644
index 0000000..efca933
--- /dev/null
+++ b/app/views/pages/about-us/en.haml
@@ -0,0 +1 @@
+= act_as('vision') \ No newline at end of file
diff --git a/app/views/pages/about-us/news/2012/en.haml b/app/views/pages/about-us/news/2012/en.haml
new file mode 100644
index 0000000..dc68ad5
--- /dev/null
+++ b/app/views/pages/about-us/news/2012/en.haml
@@ -0,0 +1 @@
+= recent_blog_summaries('news/2012')
diff --git a/app/views/pages/about-us/news/2012/first-post/en.haml b/app/views/pages/about-us/news/2012/first-post/en.haml
new file mode 100644
index 0000000..d32753a
--- /dev/null
+++ b/app/views/pages/about-us/news/2012/first-post/en.haml
@@ -0,0 +1,10 @@
+- @title = "Tada! A website"
+- @author = "Elijah"
+- @posted_at = "2012-08-24"
+- @tags = ['']
+- @categories = ['']
+- @preview = capture_haml do
+ :textile
+ I just put up the official and uncensored LEAP website. Everything needs a beginning, and I suppose this is our beginning--not with a whimper or a bang, but with a "tada!" Poke around, check us out, and please <a href="/about-us/contact">send us</a> your questions, angry tirades, or love letters. More updates to follow shortly.
+
+
diff --git a/app/views/pages/about-us/news/en.haml b/app/views/pages/about-us/news/en.haml
new file mode 100644
index 0000000..220be02
--- /dev/null
+++ b/app/views/pages/about-us/news/en.haml
@@ -0,0 +1,2 @@
+- @layout = 'blog'
+= recent_blog_summaries('about-us/news') \ No newline at end of file
diff --git a/app/views/pages/about-us/partners/en.haml b/app/views/pages/about-us/partners/en.haml
new file mode 100644
index 0000000..9c3c95c
--- /dev/null
+++ b/app/views/pages/about-us/partners/en.haml
@@ -0,0 +1,9 @@
+%p
+ <a href="https://www.calyxinstitute.org/">Calyx Institute</a>
+ is a research, education and legal support group devoted to researching and implementing privacy technology and tools to promote free speech, free expression, civic engagement and privacy rights on the Internet.
+
+%p
+ <a href="http://f2c.rfa.org/">Freedom2Connect</a> program is designed to ensure secure communication tools exist for millions of individuals whose online interactions are being monitored or obstructed by repressive governments. Through support of research, development, and implementation of globally-accessible secure communications, freedom2connect champions the goals of Article 19 of the Universal Declaration of Human Rights.
+
+%p
+ <a href="https://riseup.net">Riseup Networks</a> is a provider of email, chat, and lists for activist organizations. \ No newline at end of file
diff --git a/app/views/pages/about-us/vision/en.haml b/app/views/pages/about-us/vision/en.haml
new file mode 100644
index 0000000..1de129b
--- /dev/null
+++ b/app/views/pages/about-us/vision/en.haml
@@ -0,0 +1,26 @@
+%h2.first The Right to Whisper
+
+%p LEAP fights for the right to whisper.
+
+%p Like free speech, the right to whisper is an <b>necessary precondition for a free society</b>. Without it, civil society and political freedom become impossible. As the importance of digital communication for civic participation increases, so does the importance of the ability to digitally whisper.
+
+%p Unfortunately, advances in surveillance technology are <b>rapidly eroding the ability to whisper</b>. This is a worldwide problem, not simply an issue for people in repressive contexts. Acceptance of poor security in the West creates a global standard of insecure practice, even among civil society actors who urgently need the ability to communicate safely.
+
+%p The stakes could not be higher. Activists are dying because their communication technologies betray their identity, location, and conversations. When activists attempt to secure their communications, they face confusing software, a dearth of secure providers, and a greater risk of being flagged as potential troublemakers. In other words, <b>problems of usability, availability, and adoption</b>.
+
+%h2 Our vision
+
+%p The LEAP vision is to attack these problems of usability, availability, and adoption head on.
+
+%p
+ %b To address usability,
+ we are creating a complete system where the user-facing client software is tightly coupled with the cloud-base components of the system. All our software will be auto-configuring, prevent users from practicing insecure behavior, and primarily limit the configuration options to those moments when the user is placing their trust in another entity.
+
+%p
+ %b To address availability,
+ LEAP will work closely with service providers to adopt our open source, #{link 'automated platform' => 'platform'} for running high-availability #{link 'communication services' => 'services'}. By lowering the barriers of entry to become a reliable provider, we can increase the supply and decrease the cost of secure communications.
+
+%p
+ %b To address adoption,
+ the LEAP platform #{link 'layers higher security' => 'infosec'} on top of existing protocols to allow users a gradual transition path and backward compatibility. Our goal is to create services that are attractive in terms of features, usability, and price for users in both democratic and repressive contexts.
+
diff --git a/app/views/pages/development/en.haml b/app/views/pages/development/en.haml
new file mode 100644
index 0000000..2de6fb0
--- /dev/null
+++ b/app/views/pages/development/en.haml
@@ -0,0 +1,68 @@
+%h1 IRC
+
+Join us on freenode at #leap-dev.
+
+%h1 Source Code
+
+%p Links coming soon.
+
+%h3 Client
+
+%table.table.table-bordered
+ %tr
+ %td leap-client
+ %td Easy to use client for secure communication
+
+%h3 Service provider platform
+
+%table.table.table-bordered
+ %tr
+ %td leap-platform
+ %td Turn-key automation for communication service providers
+ %tr
+ %td leap-ca
+ %td Client certificate generation daemon
+
+%h3 Web applications and libraries
+
+%table.table.table-bordered
+ %tr
+ %td{:colspan => 2} leap-web
+ %td The complete web app that includes the following plugins...
+ %tr
+ %td
+ %td leap-web-core
+ %td provides common stuff like bootstrap, ui helpers, etc
+ %tr
+ %td
+ %td leap-web-users
+ %td user registration and management
+ %tr
+ %td
+ %td leap-web-certs
+ %td certificate management
+ %tr
+ %td
+ %td leap-web-billing
+ %td subscription and billing management
+ %tr
+ %td
+ %td leap-web-helpdesk
+ %td user tickets and documentation
+ %tr
+ %td{:colspan => 2} leap-web-demo
+ %td Demo site
+ %tr
+ %td{:colspan => 2} leap-public-site
+ %td This website
+ %tr
+ %td{:colspan => 2} srp-js
+ %td Secure Remote Password (SRP) library for javascript
+
+%h1 Mailing List
+
+%p Coming soon.
+
+%h1 Wiki
+
+%p Coming soon.
diff --git a/app/views/pages/home/en.haml b/app/views/pages/home/en.haml
new file mode 100644
index 0000000..c7bb73b
--- /dev/null
+++ b/app/views/pages/home/en.haml
@@ -0,0 +1,61 @@
+%p.bigger.first
+ %b Bring fire to the people.
+ LEAP is a non-profit dedicated to giving all internet users access to secure communication. Our focus is on adapting encryption technology to make it easy to use and widely available. #{link 'More about LEAP »' => 'about-us'}
+
+.row-fluid.p
+ .span4
+ .well
+ .heading For Users
+ %p We are working to create a suite of high security communication tools that are reliable and easy to use.
+ = link(:read_more => 'services', :class => 'btn')
+ .span4
+ .well
+ .heading For Providers
+ %p We are working on tools to automate the deployment of a secure service provider infrastructure.
+ = link(:read_more => 'platform', :class => 'btn')
+ .span4
+ .well
+ .heading For Hackers
+ %p Got skills? We need them. Fork, contribute, pentest, and patch our software. Always 100% Free/Libre.
+ = link(:read_more => 'development', :class => 'btn')
+
+.row-fluid
+ -# .span6
+ -# %h2.invert LEAP Blog
+ -# = recent_blog_summaries('blog')
+ .span6
+ %h3.first Recent News
+ = recent_blog_summaries('news')
+ .span6
+ %h3 LEAP Development Roadmap
+
+ %table.timeline
+ %tr
+ %td Jan
+ %td 2013
+ %td Automated deployment of #{link 'eip'} service, with client support on Windows, Linux, and Mac.
+ %tr
+ %td June
+ %td 2013
+ %td Android client for #{link 'eip'}.
+ %tr
+ %td Jan
+ %td 2014
+ %td Initial release of #{link 'secure email' => 'email'} as part of the LEAP platform.
+ %tr
+ %td June
+ %td 2014
+ %td #{link('email')} with #{link 'federated trust' => 'identity'} identity validation.
+ %tr
+ %td
+ %td 2015
+ %td Initial release of #{link 'secure chat' => 'chat'} as part of the LEAP platform.
+ %tr
+ %td
+ %td 2016
+ %td Initial release of secure file sync as part of the LEAP platform.
+ %tr
+ %td
+ %td 2018
+ %td Initial release of secure voice conference as part of the LEAP platform.
+
diff --git a/app/views/pages/menu.txt b/app/views/pages/menu.txt
new file mode 100644
index 0000000..246df81
--- /dev/null
+++ b/app/views/pages/menu.txt
@@ -0,0 +1,24 @@
+home
+services
+ eip
+ email
+ chat
+ #files
+ #voice
+technology
+ infosec
+ platform
+ client
+ #cloud
+ identity
+ routing
+ critiques
+ #sync
+ #authentication
+development
+about-us
+ vision
+ #people
+ contact
+ news
+ partners
diff --git a/app/views/pages/services/chat/en.haml b/app/views/pages/services/chat/en.haml
new file mode 100644
index 0000000..e27dcf3
--- /dev/null
+++ b/app/views/pages/services/chat/en.haml
@@ -0,0 +1,27 @@
+:textile
+
+ h1(first). Small messages, big hearts
+
+ Short messages and chat have proven to be indispensable tools for mobilization for activists around the world, particularly on mobile devices. Unfortunately, very few options exist that are both secure and easy to use. Even solutions that people rely on for high security, such as OTR, are vulnerable to association mapping and do not work with asynchronous communication (where both parties do not need to be online at the same time).
+
+ Experimental secure peer-to-peer messaging does exist, but adoption rates have been low because these protocols are incompatible with existing message networks and typically require both parties to be running the application at the same time. When asynchronous messaging is supported, it is slow and lacks the reliability users have come to rely on.
+
+ h1. Secure and federated chat
+
+ The LEAP approach to instant message and chat is to build on stable, federated chat technologies and add support for greatly enhanced security. The goal is to allow users to communicate with existing messaging networks, as well as enjoy a higher degree of protection when communicating with networks that support the enhanced protocols.
+
+ h3. Open protocols, improved
+
+ The primary open protocol for chat is called XMPP. It provides a good foundation for federated chat, but it is sorely lacking key security safeguards and standards for asynchronous messaging. Our additions to XMPP address these limitations:
+
+ *Secure identity:*
+
+ *Client-encrypted cloud data:* Chat applications work much better with a cloud component. For example, this allows you to have the same roster, chat history, and account information on all your clients. There is currently no provision in XMPP for client-encrypting this data. We will create one, and implement it on the client and server.
+
+ *Asynchronous messages:* Currently, patchy adoption of different methods of handling offline messaging result in confusing situations where you often have no indication if a message will be delivered to its recipient or not.
+
+ *Anonymous rosters:* XMPP requires that the server is aware of your list of contacts. This part cannot be client-encrypted, but it can be made highly resistant to association mapping by adding one-time aliases. If a friend on another server wants to add me to their roster, I will give them a unique alias for my actual chat address. Only my server will know that the alias belongs to me.
+
+ *Secure groups:*
+
+ *Required TLS:* As with email, there is no mechanism in XMPP for requiring TLS (the server can advertise that TLS is required, but this is easily thwarted by an attacker). We will add one.
diff --git a/app/views/pages/services/eip/en.haml b/app/views/pages/services/eip/en.haml
new file mode 100644
index 0000000..6589cfd
--- /dev/null
+++ b/app/views/pages/services/eip/en.haml
@@ -0,0 +1,62 @@
+:textile
+
+ h1(first). Encrypted Internet Proxy (EIP)
+
+ Around the world VPN and Tor technologies are essentially for protecting network traffic, bypass network monitoring, and circumventing censorship. Unfortunately, both VPN and Tor can be very difficult to set up and to configure correctly in a manner that actually provides high security.
+
+ The LEAP platform includes an Encrypted Internet Proxy (EIP) service that is hassle-free, automatically self-configuring, and provides an enhanced level of security. Initial, this EIP service will be built using OpenVPN, but we may include the option of using Tor as an alternate transport in the future.
+
+ h1. Features
+
+ LEAP's EIP client will:
+
+ * Automatically self-configure.
+ * Prevent unencrypted network traffic while the EIP is down (by default).
+ * Automatically starts on startup (by default).
+ * Prevent security leaks caused by problems with DNS, IPv6, and other common misconfigurations.
+
+ h1. Benefits
+
+ Traditional VPN or Tor provide a user with considerable benefit. These technologies allow a user to bypass network-based censorship and surveillance by the local ISP. They also aid in safe browsing by preventing web sites from capturing a user’s IP address, and thus geographic location. In the case of VPN, using a VPN can also give you a secure connection to a DNS server.
+
+ LEAP's Encrypted Internet Proxy provides additional benefits when paired with other communication services.
+
+ Current vulnerabilities in TLS and the x.509 certificate authority system make it nearly impossible to establish a secure internet connection with a website or a service provider. New initiatives, like Convergence and Sovereign Keys, hold long-term potential for solving this problem, but are either not available today or work only in limited circumstances.
+
+ By connecting to the internet through an EIP that is part of the LEAP platform, a user will be able to effectively establish out-of-band validation of their network encryption with the service provider.
+
+ h1. Future plans
+
+ h2. Tor
+
+ In the long run, we hope to offer both OpenVPN and Tor as possible transports for the EIP service.
+
+ Tor is an incredibly important project, but it makes different trade-offs than traditional VPN service does. For example, Tor affords the user greater anonymity, but at the cost of slower speed. The user should be able to make this choice. Currently, Tor does not include support UDP traffic, but when it does, we hope to allow the user to substitute Tor for OpenVPN via the LEAP client.
+
+ In the short run, our goal is to make all the LEAP services also work under well under Tor (as Tor hidden services), should a user decide to use Tor instead of LEAP's EIP.
+
+ h2. Darknet
+
+ We plan to eventually create a system to allow service providers who are deploying the LEAP platform to easily establish IPSec encryption of all network traffic with other service providers.
+
+ This will provide nearly complete end-to-end encryption of all the network traffic sent from one user to any other user. Each service provider, however, will still have cleartext access to the traffic of their users. The LEAP "darknet" protects against outside threats, not a compromised service provider.
+
+ h2. Anonymous Client Certificates
+
+ The LEAP platform is designed to de-couple a user's identity from the client certificate they use to connect to the EIP. The service provider will not know what user corresponds to which EIP network connection.
+
+ However, a compromised or nefarious provider could modify the LEAP platform to record a correspondence between username and EIP certificate. In the future, we would like to make this impossible.
+
+ Unfortunately, this is not an easy problem. The problem essentially boils down to this:
+
+ * Time 1: User authenticates with the provider to prove they are a valid user and receives a token.
+ * Time 2: User redeems this token to get services in a way that does not reveal their identity.
+
+ This is theoretically possible using various #{link_to 'zero-knowledge proofs', 'https://en.wikipedia.org/wiki/Zero_knowledge_proof'}. In the long run, we hope to support this capability.
+
+
+ h2. Friend in the middle
+
+ We plan to explore the feasibility of adding a "friend in the middle" to the EIP service. The idea is that the service provider can filter traffic in a way that benefits the privacy and security of the user. For example, the EIP gateway could filter advertising or third party behavioral tracking companies. More ambitiously, the friend in the middle could terminate TLS connections with compromised certificates using a server-side implementation of something like #{link_to 'convergence', 'http://convergence.io/'}.
+
+
diff --git a/app/views/pages/services/email/en.haml b/app/views/pages/services/email/en.haml
new file mode 100644
index 0000000..af2eb67
--- /dev/null
+++ b/app/views/pages/services/email/en.haml
@@ -0,0 +1,22 @@
+:textile
+
+ h1(first). Email and its discontents
+
+ !>/img/gif/animated-gifs-email-007.gif!
+
+ Email continues to be a vital communication tool. Unfortunately, the email protocol was designed in the Paleocene era of the internet and is unable to cope with the security threats common today.
+
+ For example, there is no standard for ensuring secure relay between mail providers (StartTLS is easily thwarted) and email encryption technology (PGP and S/MIME) has proven to be too cumbersome to reach beyond a very small audience. Even PGP and S/MIME, however, offer no protection against association mapping since the email headers remain unencrypted. Finally, email providers have an unfortunate habit of handing over users' data to non-democratic regimes.
+
+ h1. Email for the modern era
+
+ The LEAP approach to email is to support communication with the legacy email infrastructure while also adding optional layers to the protocol that bring email more in line with modern security practices.
+
+ *Opportunistic Content Encryption:* Whenever possible, all outgoing email will be encrypted to all the recipients. Encryption keys will be automatically discovered and verified using the #{link 'LEAP Identity' => 'identity'} service.
+
+ *Client-encrypted Mail Storage:* Incoming clear-text mail will get encrypted to the user's public key, stored in their cloud storage space, and sync'ed locally for direct access by a mail client.
+
+ *Secure Routing:* When possible, if both recipient and sender are using #{link 'LEAP Secure Routing' => 'routing'}, then neither the sender's service provider nor the recipient's service provider will be able to map the pattern of communication between sender and recipient.
+
+ *Required TLS:* We will develop a protocol for discovery of mail relays that support TLS as a requirement. In cases where the other server supports it, this will protect the email from social network analysis when in transit from server to server. It is important to have required TLS, and not just include support for StartTLS, because StartTLS can be easily downgraded to cleartext by an attacker.
+
diff --git a/app/views/pages/services/en.haml b/app/views/pages/services/en.haml
new file mode 100644
index 0000000..6535126
--- /dev/null
+++ b/app/views/pages/services/en.haml
@@ -0,0 +1,17 @@
+%p LEAP's multi-year plan to secure everyday communication breaks down into discrete services, to be rolled out one at a time. When we introduce a new service, integrated support will be added to both the user-facing #{link 'client'} and the server-side #{link 'platform'}. All communication content will be client-side encrypted, and as much of the metadata as possible. Most importantly, all LEAP services will be based on our prosed system of #{link 'federated secure identity' => 'identity'} and #{link 'unmappable routing' => 'routing'}.
+
+%h3 Phase 1 - Encrypted Internet Proxy
+
+Our first service will be #{link 'eip'}, providing circumvention, location anonymization, and traffic encryption that is hassle-free, automatically self-configuring, and has an enhanced level of security.
+
+%h3 Phase 2 - Email
+
+Our second service will be #{link 'client-encrypted email' => 'email'}. The LEAP approach to email is to support communication with the legacy email infrastructure while also adding optional layers to the protocol that bring email more in line with modern security practices. Encryption and decryption will take place transparently via local IMAP and SMTP proxies, allowing the user their choice of mail client.
+
+%h3 Phase 3 - Chat
+
+Our third service will be #{link 'secure chat' => 'chat'}. We plan to build on top of XMPP, but modify the protocol to allow for higher security and greater usability (while being able to fall back to traditional XMPP when necessary).
+
+%h3 Phases 4, 5, 6
+
+In the long term, we plan to develop and deploy client-encrypted file sync/backup, voice communication, and document collaboration.
diff --git a/app/views/pages/technology/client/en.haml b/app/views/pages/technology/client/en.haml
new file mode 100644
index 0000000..17dacac
--- /dev/null
+++ b/app/views/pages/technology/client/en.haml
@@ -0,0 +1,107 @@
+%p The LEAP Client will run on the user's device and grant the user access to the #{link 'cloud-based services' => 'services'} of the #{link 'LEAP Platform' => 'platform'}. As new services are added to the LEAP Platform, the LEAP Client will be developed in tandem to work with these services.
+
+%h1 Client crypto, cloud assistance
+
+%p For users of cloud-based communication services, there is only one approach that can achieve a reasonable level of security: client-side encryption.
+
+%p The model proposed here is neither peer-to-peer nor pure cloud; rather, it is a hybrid designed to make a client-encrypted cloud function more smoothly. Some client-encrypted communication services do not require cooperation on the part of the cloud provider. For example, if you simply want to backup files, you just need a program like Duplicity which can be pointed at the storage provider of your choice.
+
+%p Most other services, however, will only work if the server-side software is designed to work with client-encrypted data. A hybrid model shares the advantages that a pure cloud model has over peer-to-peer: the service is more reliable, is not subject to data loss, works the same on all devices, is faster, and is much easier to use.
+
+-# insert a chart here...
+
+ plain-cloud
+ cloud with no encryption or server-side encryption only
+ pretty much all cloud services fall into this category.
+ Twitter
+ Dropbox
+
+ crypto-cloud
+ cloud with layered client-side encryption
+ some enterprising users have bolted encryption on top of the cloud based services they use. the cloud services are not designed to work with client-side encryption, the the operation is typically awkward, but it can work.
+ Facebook Chat + OTR
+ Amazon S3 + Duplicity
+ gmail + FireGPG
+
+ integrated cloud
+ cloud with integrated client-encryption
+
+ cloud-side encryption is not really any better than cloud without encryption, so it is not listed in this table.
+
+ Except in the case of EIP, all LEAP services are designed to place little or no trust in the service provider.
+
+%h1 Crypto for mere mortals
+
+%p After security, our primary goal with the client is to make it as easy to use as possible. There are several ways we are approaching the problem of usability:
+
+%p
+ %b Auto-configuration &mdash;
+ There are a lot of powerful tools for secure communication out there, and most of them are incredibly difficult to set up and configure correctly in a way that ensures you don't compromise your security. Our goal with the LEAP client is to tightly couple the client with the services so that the client will be able to configure itself correctly without user intervention.
+
+%p
+ %b The best UI is no UI &mdash;
+ We plan to make the interface for the client as minimal as possible. For EIP, the client will do everything it can to troubleshoot on its own to get a stable encrypted tunnel established. For the messaging services like email and chat, the LEAP Client is a proxy that handles encryption/decryption locally on the user's device, allowing the user to continue to use whatever client software they are comfortable with.
+
+%h1 Software updates
+
+%p We want service providers in repressive and hostile contexts to still be able to adopt the LEAP Platform. In order to protect the service provider, the LEAP Client will accept security patches and code upgrades from the LEAP non-profit organization, not from the service provider.
+
+%p Every LEAP Client will include the public key used to sign updates. When a new client version is available, and the provider supports the API version of the new client, then the new code will be download from LEAP and verified using the keys included with the first download. Alternately, on platforms with good package management, like Debian or Redhat variants of GNU/Linux, updates to the LEAP Client will go through the normal platform specific channels.
+
+%p This system still leaves open the problem of how to distribute the initial client that is first installed. This is a difficult problem, and one which we hope to work on in the future.
+
+%h1 Cross platform
+
+%p Initially, the LEAP Client will support Windows, Mac, and Linux. We are committed to extending support to mobile devices once the desktop version is stable (although currently, Apple's terms of service for the appstore prevent GPL licensed apps, so until this changes we can't distribute on iOS). The mobile version of the LEAP Client will lag behind the desktop version, but our goal is to provide eventual feature parity.
+
+%p Recent advancements in Javascript and HTML have begun to blur the distinction between client applications that a user installs and client applications that run in a web browser environment. Although there are numerous projects actively working on client-encrypted communication that runs inside the browser, such in-browser efforts are currently crippled by a lack of standardized and trusted cryptographic primitives inside the browser and are so vulnerable to a number of common attacks. We plan to work closely with the new W3C Web Cryptography Working Group in order maximize the deployment of client-encrypted applications, both in currently safe clients as well as more experimental native applications in the browser.
+
+%h1 Branded and unbranded
+
+%p The LEAP client will come in two flavors: branded and unbranded.
+
+%p
+ %b The branded client
+ will but customized with the name and graphics of the service provider using the LEAP Platform. It will be pre-configured to work the with service provider.
+
+%p
+ %b The unbranded client
+ will work with any service provider that runs the LEAP platform. When the user first runs the unbranded client, they will be presented with a list of available service provider and the option to type in the name of a provider that is not in the list. Once the user picks a provider, the client will download a file from the provider that defines the capabilities of the provider and allows the client to autoconfigure itself for use with that provider.
+
+
+%h1 Trust issues
+
+%p As much as possible, our goal is to design a system that requires very little trust of the service provider. However, there are a few areas where the user will need to trust either LEAP or their service provider:
+
+%ul
+ %li
+ %b Encrypted Internet Proxy:
+ If the user chooses to enable the EIP service, then all their internet traffic passes through the service provider. A nefarious provider could sniff this traffic, if it was using a cleartext protocol like plain HTTP.
+ %li
+ %b Notary Keys:
+ The LEAP Client will come with a set of public keys for the notaries used for #{link 'identity discovery and validation' => 'identity'}. If a supermajority of these notaries conspire or get hacked then the security of the identity system will be compromised.
+ %li
+ %b Client Software:
+ Unless the user builds the client software from the source code, the user will trust LEAP Encryption Access Project for the client builds and code updates.
+
+
+
+%h1 Secrets recovery
+
+%p What should LEAP do when a user has lost their secrets (either human-memorizable or private keys)? There is no right answer for every situation.
+
+%p
+ %b No recovery:
+ In some situations, it makes the most sense to simply do without the ability to recover lost secrets.
+
+%p
+ %b Recovery document:
+ The LEAP client will give the user the option to export a text file with a complete copy of their private keys and authorization information, either password protected or not. This "recovery document" can be printed or saved electronically as the user sees fit. If the user needs to recover their data, they can load this recover document into any LEAP client. The user can also type the recovery document in manually, although it will be long and very painful to copy manually.
+
+%p
+ %b Cloud recovery:
+ The user is presented with a small ten by ten grid of digits (with QR code) that can be printed. To recover, the user types in these 100 digits into any LEAP client (or scans the QR code using a mobile device). This method is like manual recovery, but it is much easier to type in manually. To achieve this, the full recovery document is encrypted and then stored on the server. The user is then presented with a small code that serves as an encoded index and passphrase to retrieve the full recovery document. This method is desirable when the user does not want to be responsible for storing an electronic copy of the full recovery document. It will also serve as an easy way to set up the LEAP client on a mobile device. The disadvantage of this method is that there is potential for attack on the cloud-stored recovery document.
+
+%p
+ %b Email recovery:
+ The novice user should have the option to recover their secret by a simple email verification. This is less horrible than it sounds. It will work like this: when the user first installs the client, they are given the option to entrust one or more email addresses with the ability to unlock their recovery document. Additionally, they must decide how many of these email addresses must confirm the secret recovery in order for it to succeed. The LEAP client then registers these emails with a third party secret escrow service in such a way that no single party has access to the full secret (unless there is just one email). When the user triggers the reset process, the LEAP client contacts the escrow service and gives it a token to request the release of the recovery document. Once the email accounts have replied to the escrow service with confirmation of assent to the secret recovery, the LEAP client can retrieve the lost secret from the escrow service. This is a complicated process, but from the user's perspective they just hit a "recover" button and then wait for people to reply to the confirmation emails. This is a potential long term enhancement.
diff --git a/app/views/pages/technology/critiques/en.haml b/app/views/pages/technology/critiques/en.haml
new file mode 100644
index 0000000..8eb6019
--- /dev/null
+++ b/app/views/pages/technology/critiques/en.haml
@@ -0,0 +1,57 @@
+:textile
+ Here is a collection of some of the critiques we have heard or anticipate.
+
+ h3. Isn't LEAP too ambitious?
+
+ Yes. However, someone needs to be working on a long term plan to add real security and usability to federated messaging architectures. It will not be easy, but we think it is possible.
+
+ h3. Isn't LEAP just like FreedomBox?
+
+ LEAP and FreedomBox share a similar goal of ensuring that everyone has the right to communicate securely and without censorship. However, the projects use different strategies for achieving this goal.
+
+ * *FreedomBox:* Empower every user to control the hardware on which all their data is stored. Users become their own service providers, running their own hardware.
+ * *LEAP:* Allow service providers to deploy a cloud-based infrastructure that can scale and is easily maintained. In addition to the performance and usability found in traditional cloud services, LEAP services are also designed to bring a very high level of security to everyday users.
+
+ FreedomBox is an important project. It faces, however, some significant hurdles. Most users demand high availability, but current technology does not allow for hardware or software that is self healing. If it did, sysadmins would be out of work. Things go wrong all the time. Take, for example, email: it is very common for an email server to get spam-bombed, or added to a blacklist, or any number of other problems that require manual intervention by a system administrator to fix. Also, most ISPs block the port needed for email rely.
+
+ In the long run, FreedomBox has a lot of potential. But for the foreseeable future, we think it is important to also pursue the LEAP strategy.
+
+ h3. We should not encourage users to store any data in the cloud, encrypted or not
+
+ Even the best encryption is no guarantee of confidentiality; data in the cloud always has the potential to be decrypted by a determined attacker.
+
+ The entire issue boils down to a matter of degree. Although there is no necessary trade off between security and convenience, you can usually achieve a higher level of security in any system by sacrificing some convenience. But what level of protection and convenience is appropriate for a particular user?
+
+ There are very few people for whom client-encrypted data stored in the cloud will be the weakest link in the confidentiality of their communication and stored data. Most likely, there will be many aspects of their communication that are much more attractive targets to a determined adversary.
+
+ If a person has a threat model that includes an adversary with the resources to both acquire the user's cloud data and to decrypt it, then there is little that LEAP or any other third party can do for them. They will need to become highly proficient at managing and protecting all their own data.
+
+ There are many tools and projects out there to help a user do this. LEAP is designed for a different audience, one not adequately addressed by existing technology: people who want high security but don't have the capacity to become highly skilled in self-managing their encryption. There is room--and need--for both approaches, and it is likely that the amount of people who want high security but do not have the time or skills to adequately self-manage their own environment is already large and increasingly rapidly.
+
+ h3. If you make your system architecture public, then you have given adversaries a blueprint to attack you
+
+ This is, of course, similar to the arguments about the security of FLOSS. Openness can indeed lead to attacks, but more eyes leads to better security.
+
+ In the case of an entire service provider infrastructure, however, it could be argued that things are different. We are not talking about a single piece of software, but the whole integration across many servers and services. A related critique is the potential problem of monoculture: if LEAP is successful, then a high percentage of the secure service providers will be using systems with the same vulnerabilities.
+
+ Monoculture and openness are both interesting issues that could pose problems for the future. We can only be diligent in assessing LEAP once it is deployed by a variety of organizations. With enough flexibility in configuration, it may be that each LEAP deployment is sufficiently distinct from the others to mitigate these concerns.
+
+ h3. Users will not be willing to download a custom client
+
+ This will indeed be the case for a large number of potential users. Because meaningful levels of security cannot be achieved using current technology without a custom client, our hope is that a critical mass of users can be induced to use one. There are two parts to this inducement: increasing awareness as to why an extra step to ensure security is worthwhile, and decreasing the difficulty in actually taking this step. With sufficient education and an improved user experience, many users should be willing to install a custom client.
+
+ On the other hand, rapid developments in Javascript and web browser technology have raised the possibility of running advanced client applications within the browser itself. In this case, a user would not have to install any additional software. However, in-browser crypto is still an area of active research but is currently not safe for deployment, with some areas still to be worked out (like sufficient entropy). LEAP does not depend upon the presence of cryptography in the browser, but would benefit from this should it become viable. The lead W3C employee who began the standardization of Javascript Cryptography is on the board of LEAP, and he will liaise tightly with LEAP as the work matures.
+
+ h3. Users who need security often don't have their own device or access to the internet
+
+ This is absolutely true. The digital divide is alive and well, and LEAP does nothing to bridge the gap between the technological haves and have-nots. However, in the long run, IP-based communication--dependent upon advanced devices such as smart phones--is likely to replace most other forms of communication. The cost of such IP-based communication devices and their connectivity is declining rapidly. It behooves us to lay the groundwork now for a secure IP-based communication infrastructure, both for the people who currently rely on the internet and for the next billion who will gain access to the internet in the near future.
+
+ h3. Client encryption is excessive for most people
+
+ The argument against client encryption is something like this: a secure connection is good enough, so long as the service provider is located in a country with adequate legal protection and without repressive laws.
+
+ There are many reasons why users should be put in control of their data and should not be made to rely on a third party to safeguard it. Third parties have proven to be highly undeserving of trust--They might close shop, bow to pressure from local government, become compromised by external attacks, or accidentally leak sensitive data due to carelessness.
+
+ Our goal is to make secure communication the default for a critical mass of users worldwide. A vital part of this strategy is cooperation with ISPs and service providers who speak the local language of their users and who are attuned to the needs of a particular context. These local service providers don't have the luxury of determining which government's jurisdiction they fall under. However, so long as encryption technology itself is not outlawed, local providers using the LEAP platform will be able to provide a high level of security for their users.
+
+ By requiring client encryption for all services, LEAP also helps to mitigate against the myriad vulnerabilities inherent with most devices. While the LEAP client cannot defend against keyloggers, malware, or penetration of the host OS, it can ensure that all the LEAP cloud data synced by the device is stored in an encrypted format. \ No newline at end of file
diff --git a/app/views/pages/technology/en.haml b/app/views/pages/technology/en.haml
new file mode 100644
index 0000000..83a6d6a
--- /dev/null
+++ b/app/views/pages/technology/en.haml
@@ -0,0 +1,30 @@
+%h1.first Key Technologies
+
+%p The long term LEAP plan consists of a set of #{link 'communication services' => 'services'} built upon the core technologies detailed here.
+
+%p
+ %b #{link 'Information Security' => 'infosec'}:
+ An analysis of different approaches to information security and how the LEAP strategy compares.
+
+%p
+ %b #{link 'Provider Platform' => 'platform'}:
+ Turn-key automation for communication service providers.
+
+%p
+ %b #{link 'LEAP Client' => 'client'}:
+ Easy to use client for secure communication.
+
+%p
+ %b #{link 'Secure Identity' => 'identity'}:
+ Federated system to automate validation of cryptographic identity.
+
+%p
+ %b #{link 'Map Resistant Routing' => 'routing'}:
+ A system for message routing that is resistant to association mapping.
+
+%p
+ %b #{link 'Critiques' => 'critiques'}:
+ Anticipated critiques of the LEAP architecture.
+
+
+-# https://guardianproject.info/wiki/Always_Secure_Messaging \ No newline at end of file
diff --git a/app/views/pages/technology/identity/en.haml b/app/views/pages/technology/identity/en.haml
new file mode 100644
index 0000000..f90d07b
--- /dev/null
+++ b/app/views/pages/technology/identity/en.haml
@@ -0,0 +1,45 @@
+%h1.first The sad, sorry state of cryptographic identity
+
+%p Existing forms of secure identity are deeply flawed. These systems rely on either a single trusted entity (e.g. Skype), a vulnerable Certificate Authority system (e.g. S/MIME), or keys that cannot be made human memorable (e.g. OpenPGP, OTR). When an identity system is hard to use, it is effectively compromised because too few people take the time to use it properly.
+
+%p The broken nature of existing identities systems (either in security or in usability) is especially troubling because identity remains a bedrock precondition for any message security: you cannot ensure confidentiality or integrity without confirming the authenticity of the other party.
+
+%h1 NickID
+
+%p The cornerstone of the LEAP design is a system to make digital identity for messaging both secure and easy to use. We call this system NickID, since the goal is for the individual to be able to think of cryptographic identity in terms of a domain qualified nickname just as they do with email addresses.
+
+%p NickID is based on a federated structure where the difficult work is pushed to the service providers. Each provider is responsible for the due diligence of properly signing the keys of other providers, akin to the distributed web of trust model of OpenPGP. Providers also are responsible for signing the keys of their users, akin to the Certificate Authority model.
+
+%p When a user sends or receives a message, their software will discovery the other party's key and trace a chain of signature's back to the user's service provider. NickID allows for identity that is verified through an end-to-end trust path from any user to any other user in a way that can be automated and is human memorable (e.g. identity in the form user@example.com).
+
+%h1 Users are not websites
+
+%p What about WebID or BrowserID (Mozilla Personas)? These are both interesting cryptographic identity standards that are gaining support and implementations. So why do we need something new?
+
+%p These protocols, and the poorly conceived OpenID Connect, are designed to address a fundamentally different problem: authenticating a user to a website. The problem of authenticating users to one another requires a different architecture entirely. There are some similarities, however, and in the long run a FWoT could be combined with something like BrowserID/Personas.
+
+%h1 Attacks and countermeasures
+
+%p Attacks on this system can be prevented with a simple “network perspectives” approach that keeps each service provider honest. Let's enumerate the attacks and how to prevent them. Suppose two providers, A and B.
+
+%p
+ %b Attack 1 - Intercept Outgoing:
+ provider A signs an impostor key for provider B and distributes it to users of A (in order to intercept outgoing messages sent to B).
+
+%p
+ %b Attack 2 - Intercept Incoming:
+ provider A signs an impostor key for one of its own users, and distributes to users of B (in order to intercept incoming messages).
+
+%p
+ %b Attack 3 - Association Mapping:
+ A provider tracks all the requests for key discovery in order to build a map of association.
+
+%p To prevent these attacks, NickID will support independent notaries who sole purpose is to answer a single question: "Do you see the same key that I see?"
+
+%p In order to prevent attack 1, the user's client software will not blindly trust that it has encountered the correct provider key for B. Instead, it will get confirmation from the notaries that they also received the same key (or a key signed by the same key).
+
+%p In order to prevent attack 2, the user's client software will regularly query the notaries for their own key. If the notaries see a different key, the user is alerted that their provider is attempting to intercept their messages.
+
+%p In order to prevent attack 3, the user's client software will be able to use the response of a notary as the initial key discovery, and to proxy a request to one notary through another. Each notary request will be encrypted to the public key of that notary.
+
+%p For this to work, client software that supports NickID will come pre-seeded with a list of notaries and their public keys. Although this sounds like a repeat of the problems associated with the Certificate Authority system, the notaries are actually quite different. Rather than placing irrevocable trust in an authority, clients are only using the notaries for a very narrowly defined ability to provide network perspective. \ No newline at end of file
diff --git a/app/views/pages/technology/infosec/en.haml b/app/views/pages/technology/infosec/en.haml
new file mode 100644
index 0000000..386ce10
--- /dev/null
+++ b/app/views/pages/technology/infosec/en.haml
@@ -0,0 +1,101 @@
+= render_local_template 'table-style'
+
+%h1.first You can't have it all
+
+%p Every messaging architecture makes certain design choices that privilege one property of information security over another. Although there is no intrinsically necessary trade off among different information security properties, when we examine the technical limitations of actual implementations we see clearly that existing architectures are structurally biased toward certain properties and against others.
+
+%h1 A fancy table
+
+%p This table provides a rough comparison of the choices made by common messaging architectures. See #{link 'below for details' => '#table-notes'} regarding the column and row headings.
+
+.p
+ %b Table 1. Information security of common messaging architectures
+ = render_local_template 'table', :table_type => :big
+
+%p Reasonable people may disagree: this table represents one defensible assessment of the various architecture categories. Many people would adjust one or two cells, but on the whole we believe this table is a fair and accurate comparison.
+
+%p In table 2 we see a simplified representation that highlights the relative differences between the encrypted architectures:
+
+.p
+ %b Table 2. Relative trade-offs of encrypted messaging architectures
+ = render_local_template 'table', :table_type => :small
+
+%p Relatively better is not necessarily good. For example, federated and peer-to-peer models have better authenticity than silo models, but usability problems make it so that their authenticity is often poor in practice.
+
+%h1 The LEAP strategy (you can have it all)
+
+%p In a nutshell, the LEAP strategy is this: take a federated architecture and improve the authenticity, unmappability, and usability. In table form, that looks like this:
+
+.p
+ %b Table 3. The LEAP strategy for improving federated architectures
+ = render_local_template 'table', :table_type => :leap
+
+%p Why this focus on authenticity, unmappability, and usability?
+
+%p First, there is a lot of room for improvement. We believe that there is actually no particular structural reason why these properties are so low in existing federated encrypted architectures.
+
+%p Second, these property are extremely important and yet are typically given low priority or are ignored completely.
+
+%ul
+ %li
+ %b Authenticity:
+ Message security rests entirely on a foundation of authenticity. Without proper validation of encryption keys, you cannot be assured of confidentiality or integrity. Unfortunately, current system of establishing message authenticity are so difficult to use that most users simply ignore this step. LEAP will address these problems with a system of #{link 'strong and automatic identity validation' => 'identity'}.
+ %li
+ %b Usability:
+ There are plenty of high security tools that are nearly impossible for the common user to use correctly. If the tool is too difficult, it will not be widely adopted and will likely be used incorrectly by those who do adopt it. LEAP with address these problems with the #{link 'LEAP client' => 'client'} that is tightly coupled with the server-side software and is autoconfiguring.
+ %li
+ %b Unmappability:
+ Recent advances in social network analysis and the greatly expanded of ability state and corporate actors to gather social graph information have made unmappability an urgent requirement for any architecture that seeks to address the surveillance situation we face today. LEAP will address these problems with our proposal for #{link 'graph resistant routing' => 'routing'}.
+
+%p Improvement in these areas will come at a price. Although LEAP communication tools will be backward compatible with existing federated standards, a user of the LEAP platform will not have the same degree of choice in client software and provider as does a user of a traditional federated system. Our goal is to actively help providers adopt the LEAP platform, in order to give users more options in the long run.
+
+%h1#table-notes Decoding the table
+
+%h2 Communication architectures (columns)
+
+(to be written)
+
+%h2 Aspects of information security (rows)
+
+%p Classical information security consists of a trio of properties: confidentiality, integrity, availability. To this list, others have added authenticity, control, and anonymity (among many others).
+
+%p For our purposes here, we also add usability, compatibility, and unmappability. What do all these mean? Let's use the example of a single message, and group these nine properties in three categories:
+
+%h3 Message Security
+
+%table.properties
+ %tr
+ %th Confidentiality
+ %td A message has highly confidentiality if only the intended recipients are able to read the message.
+ %tr
+ %th Integrity
+ %td A message has high integrity if the recipient is assured the message has not been altered.
+ %tr
+ %th Availability
+ %td A message has high availability if the user is able to get to the message when they so desire.
+
+%h3 Identity Security
+
+%table.properties
+ %tr
+ %th Authenticity
+ %td A message has high authenticity if the recipient is certain who sent the message and the sender is certain who received it.
+ %tr
+ %th Anonymity
+ %td A message has high anonymity if the identity of the sender cannot be established by examining the message or the pattern of message delivery.
+ %tr
+ %th Unmappability
+ %td A message has high unmappability if the social network that you communicate with cannot be easily discovered. Unmappability is often collapsed under anonymity. This is unfortunate. It is true the anonymity is one of the issue at stake with social network mapping, but it is just one of many. Because of recent advances in social network analysis and the ability to gather social graph information, we feel that unmappability deserves to be highlighted on its own.
+
+%h3 User Freedom
+
+%table.properties
+ %tr
+ %th Control
+ %td If a user is in possession of their own data and can do with it exactly what they want (and others cannot use the data in ways contrary to the wishes of the user), then we say that they have high control.
+ %tr
+ %th Usability
+ %td For a communication system to have high usability, the common user must be able to operate the system in a way that does not compromise their security.
+ %tr
+ %th Compatibility
+ %td For a system to have high compatibility, the user must not be locked into a particular provider or technology, but should have competing and compatible options available to them. In other words, a user's data should be portable and they should have a choice of clients.
diff --git a/app/views/pages/technology/infosec/table-style.haml b/app/views/pages/technology/infosec/table-style.haml
new file mode 100644
index 0000000..c9a3495
--- /dev/null
+++ b/app/views/pages/technology/infosec/table-style.haml
@@ -0,0 +1,59 @@
+%style
+ :sass
+ table.properties
+ td
+ vertical-align: top
+ padding-bottom: 0.75em
+ th
+ vertical-align: top
+ padding-right: 1em
+ text-align: right
+ font-weight: normal
+ font-style: italic
+
+ table.infosec
+ width: 100%
+ border-collapse: collapse
+ tbody
+ border-top: 1px solid black
+ border-bottom: 1px solid black
+ th span.normal
+ font-weight: normal
+ th.first, th.second, th.cell
+ width: 14.285714286%
+ th.spacer, td.spacer
+ width: 1px !important
+ padding: 0 !important
+ background: black
+ // border: 1px dotted black
+ //border: 0 !important
+ //th.second
+ // width: 0%
+ //th.cell
+ // width: 20%
+ td.cell
+ border-top: 1px solid black
+ border-bottom: 1px solid black
+ //border-right: 1px dotted rgba(0,0,0,.1)
+ border-left: 1px dotted rgba(0,0,0,.1)
+ text-align: center
+ padding: 4px
+ &.none
+ //background-color: #ccc
+ background: #888
+ &.low, &.lower, &.worse
+ //background-color: #FFCCCC
+ background: #aaa
+ &.medium, &.higher
+ //background-color: #FFFFCC
+ background: #ccc
+ &.high, &.better
+ //background-color: #CCFFCC
+ background: #e6e6e6
+ &.better, &.worse
+ font-weight: bold
+ tr.footer td
+ border-left: 1px dotted rgba(0,0,0,.1)
+ text-align: center
+ font-size: 0.8em
+
diff --git a/app/views/pages/technology/infosec/table.haml b/app/views/pages/technology/infosec/table.haml
new file mode 100644
index 0000000..0f6a92f
--- /dev/null
+++ b/app/views/pages/technology/infosec/table.haml
@@ -0,0 +1,233 @@
+:ruby
+
+ if table_type == :small
+ ##
+ ## SMALL TABLE
+ ##
+ columns = [:p2p, :ssilo, :sfed]
+ column_data = {
+ :ssilo => [:silo, :encrypted],
+ :sfed => [:federation, :encrypted],
+ :p2p => [:peer_to_peer, :encrypted]
+ }
+ rows = [:availability, :usability, :compatibility, :authenticity, :control, :anonymity]
+ row_groups = []
+ footer = false
+ cells = {
+ :ssilo => {
+ :control => [:lower],
+ :compatibility => [:lower],
+ :usability => [:higher],
+ :authenticity => [:lower],
+ :availability => [:higher],
+ :anonymity => [:lower]
+ },
+ :sfed => {
+ :control => [:higher],
+ :compatibility => [:higher],
+ :usability => [:lower],
+ :authenticity => [:higher],
+ :availability => [:lower],
+ :anonymity => [:lower]
+ },
+ :p2p => {
+ :control => [:higher],
+ :compatibility => [:lower],
+ :usability => [:lower],
+ :authenticity => [:higher],
+ :availability => [:lower],
+ :anonymity => [:higher]
+ }
+ }
+ elsif table_type == :big
+ ##
+ ## BIG TABLE
+ ##
+ columns = [:silo, :fed, :ssilo, :sfed, :p2p]
+ column_data = {
+ :silo => [:silo, :cleartext, :silo_example],
+ :fed => [:federation, :cleartext, :fed_example],
+ :ssilo => [:silo, :encrypted, :ssilo_example],
+ :sfed => [:federation, :encrypted, :sfed_example],
+ :p2p => [:peer_to_peer, :encrypted, :p2p_example],
+ :spacer => [:spacer, :spacer, :spacer]
+ }
+ rows = [
+ :control, :compatibility, :usability,
+ :anonymity, :unmappability, :authenticity,
+ :availability, :confidentiality, :integrity
+ ]
+ row_groups = [:message_security, :identity_security, :user_freedom]
+ row_groups_data = {
+ :user_freedom => [:control, :compatibility, :usability],
+ :identity_security => [:authenticity, :anonymity, :unmappability],
+ :message_security => [:confidentiality, :integrity, :availability]
+ }
+ footer = true
+ cells = {
+ :silo => {
+ :control => [:none],
+ :compatibility => [:none],
+ :usability => [:high],
+ :anonymity => [:none],
+ :unmappability => [:none],
+ :authenticity => [:none],
+ :availability => [:high],
+ :confidentiality => [:none],
+ :integrity => [:none]
+ },
+ :fed => {
+ :control => [:medium],
+ :compatibility => [:high],
+ :usability => [:medium],
+ :anonymity => [:none],
+ :unmappability => [:none],
+ :authenticity => [:none],
+ :availability => [:medium],
+ :confidentiality => [:none],
+ :integrity => [:none]
+ },
+ :ssilo => {
+ :control => [:none],
+ :compatibility => [:none],
+ :usability => [:high],
+ :anonymity => [:low],
+ :unmappability => [:none],
+ :authenticity => [:none],
+ :availability => [:high],
+ :confidentiality => [:high],
+ :integrity => [:high]
+ },
+ :sfed => {
+ :control => [:medium],
+ :compatibility => [:medium],
+ :usability => [:low],
+ :anonymity => [:low],
+ :unmappability => [:none],
+ :authenticity => [:low],
+ :availability => [:medium],
+ :confidentiality => [:high],
+ :integrity => [:high]
+ },
+ :p2p => {
+ :control => [:high],
+ :compatibility => [:none],
+ :usability => [:low],
+ :anonymity => [:medium],
+ :unmappability => [:medium],
+ :authenticity => [:low],
+ :availability => [:low],
+ :confidentiality => [:high],
+ :integrity => [:high]
+ },
+ :spacer => {
+ :control => [:spacer],
+ :compatibility => [:spacer],
+ :usability => [:spacer],
+ :anonymity => [:spacer],
+ :unmappability => [:spacer],
+ :authenticity => [:spacer],
+ :availability => [:spacer],
+ :confidentiality => [:spacer],
+ :integrity => [:spacer]
+ }
+ }
+ elsif table_type == :leap
+ ##
+ ## LEAP TABLE
+ ##
+ columns = [:fed, :sfed, :leap]
+ column_data = {
+ :ssilo => [:silo, :encrypted],
+ :sfed => [:federation, :encrypted],
+ :p2p => [:peer_to_peer, :encrypted],
+ :fed => [:federation, :cleartext],
+ :leap => [:leap, :encrypted]
+ }
+ rows = [
+ :control, :compatibility, :usability,
+ :anonymity, :unmappability, :authenticity,
+ :availability, :confidentiality, :integrity
+ ]
+ row_groups = [:message_security, :identity_security, :user_freedom]
+ row_groups_data = {
+ :user_freedom => [:control, :compatibility, :usability],
+ :identity_security => [:authenticity, :anonymity, :unmappability],
+ :message_security => [:confidentiality, :integrity, :availability]
+ }
+ footer = false
+ cells = {
+ :fed => {
+ :control => [:medium],
+ :compatibility => [:high],
+ :usability => [:medium],
+ :anonymity => [:none],
+ :unmappability => [:none],
+ :authenticity => [:none],
+ :availability => [:medium],
+ :confidentiality => [:none],
+ :integrity => [:none]
+ },
+ :sfed => {
+ :control => [:medium],
+ :compatibility => [:medium],
+ :usability => [:low],
+ :anonymity => [:low],
+ :unmappability => [:none],
+ :authenticity => [:low],
+ :availability => [:medium],
+ :confidentiality => [:high],
+ :integrity => [:high]
+ },
+ :leap => {
+ :control => [:medium],
+ :compatibility => [:worse],
+ :usability => [:better],
+ :anonymity => [:low],
+ :unmappability => [:better],
+ :authenticity => [:better],
+ :availability => [:medium],
+ :confidentiality => [:high],
+ :integrity => [:high]
+ }
+ }
+ end
+
+%table.infosec
+ %tr
+ %th.first
+ - if row_groups.any?
+ %th.second
+ - columns.each do |column|
+ - if column == :spacer
+ %th.spacer
+ - else
+ %th.cell
+ = I18n.t column_data[column][0], :scope => 'infosec'
+ %br<>
+ %span.normal
+ = I18n.t column_data[column][1], :scope => 'infosec'
+ - if row_groups.any?
+ - row_groups.each do |row_group|
+ %tbody
+ - rows = row_groups_data[row_group]
+ - rows.each do |row|
+ %tr
+ - if rows.first == row
+ %td{:rowspan=>3}= I18n.t(row_group, :scope => 'infosec').sub(' ', '<br/>').html_safe
+ %td= I18n.t row, :scope => 'infosec'
+ - columns.each do |column|
+ %td.cell{:class => cells[column][row]}= I18n.t cells[column][row], :scope => 'infosec'
+ - else
+ - rows.each do |row|
+ %tbody
+ %tr
+ %td= I18n.t row, :scope => 'infosec'
+ - columns.each do |column|
+ %td.cell{:class => cells[column][row]}= I18n.t cells[column][row], :scope => 'infosec'
+ - if footer
+ %tr.footer
+ %td{:colspan=>2}= I18n.t :for_example, :scope => 'infosec'
+ - columns.each do |column|
+ %td= I18n.t column_data[column][2], :scope => 'infosec'
+
diff --git a/app/views/pages/technology/platform/en.haml b/app/views/pages/technology/platform/en.haml
new file mode 100644
index 0000000..871122a
--- /dev/null
+++ b/app/views/pages/technology/platform/en.haml
@@ -0,0 +1,16 @@
+%h2.first git clone leap-platform
+
+%p The LEAP Provider Platform is the server-side part of LEAP that is run by service providers. It consists of a set of complementary packages and recipes to automate the maintenance of LEAP services in a hardened GNU/Linux environment. Our goal is to make it painless for service providers and ISPs to deploy a secure communications platform.
+
+%p The LEAP Platform is essentially a git repository of puppet recipes, with a few scripts to help with bootstrapping and deployment. A service provider who wants to deploy LEAP services will clone or fork this repository, edit the main configuration file to specify which services should run on which hosts, and run scripts to deploy this configuration.
+
+%h2 More providers, please
+
+%p We believe that the best way to defend the right to whisper is to bring encryption technology into wider adoption. Despite growing awareness of the importance of communication security, users who attempt to adopt better practices still have few places they can turn.
+
+%p Most people think of lack of security as a problem of insufficient demand. We think that there are actually enough people out there who would like to use communication tools with higher security but who face severe problems of supply.
+
+%p The goal of LEAP is to meet this demand with tools that are usable and secure. But the LEAP architecture is necessarily a #{link 'federated' => 'infosec'} one, and the enhanced security it provides is only possible once there is a health ecosystem of service providers using the LEAP platform.
+
+%p One way to get more service providers is to make the people who run them happy. With the LEAP Platform, we want to reduce the amount of bullshit work. We are not "dumbing down" the work it takes to run a service provider. Rather, our goal is to allow talented sysadmins to focus on the parts that really matter and spend less time wrestling with the frustrating and mundane aspects of system administration.
+
diff --git a/app/views/pages/technology/routing/en.haml b/app/views/pages/technology/routing/en.haml
new file mode 100644
index 0000000..35d52ed
--- /dev/null
+++ b/app/views/pages/technology/routing/en.haml
@@ -0,0 +1,52 @@
+%h1.first A social graph is highly sensitive data
+
+%p As the field of network analysis has advanced in recent years, the social graph has become highly sensitive and critical information. Knowledge of the social graph can give an attacker a blueprint into the inner workings of an organization or reveal surprisingly intimate personal details, such as sexual orientation or even health status.
+
+%p Unfortunately, existing technologies for secure routing, such as StartTLS for email or chat, are insufficient in today's environment and easily thwarted. StartTLS also does little to protect a service provider from being required to keep association records of its users.
+
+%h1 Map resistant routing
+
+%p One of the major goals of LEAP is to make message routing that is resistant to social graph mapping.
+
+-# The LEAP design includes an improved method of encrypted transport negotiation and an system for aliased message routing to protect the social graph from even the service providers themselves.
+
+%p How would this work? Imagine users Alice and Bob. Alice wants to correspond with Bob but doesn't want either her service provider or Bob's service provider to be able to record the association. She also doesn't want a network observer to be able to map the association.
+
+%p When Alice first sends a message to Bob, Alice's client will initiate the following chain of events on her behalf, automatically and behind the scenes.
+
+%ol
+ %li Alice's client requests a new alias from her service provider. If her normal address is alice@domain.org, she receives an alias hjj3fpwv84fn@domain.org that will forward messages to her account.
+ %li Alice's client uses automatic key discovery and validation to find Bob's public key and discover if Bob's service provider supports map resistant routing.
+ %li If Bob does support it, Alice's client will then send a special message, encrypted to Bob's key, that contains Alice's public address and her private alias.
+ %li When Bob's client encounters this special message, it records a mapping between Alice's public address (alice@domain.org) and the private alias she has created for Bob's use (hjj3fpwv84fn@domain.org).
+ %li Bob's client then creates an alias for Bob and sends it to Alice.
+ %li Alice's client receives this alias, and records the mapping between Bob's public address and his private alias.
+ %li Alice's client then relays the original message to Bob's alias.
+
+Subsequently, whenever Alice or Bob want to communicate, they use the normal public addresses for one another, but behind the scenes their clients will rewrite the source and recipient of the messages to use the private aliases.
+
+This scheme is backwards compatible with existing messaging protocols, such as SMTP and XMPP.
+
+%h1 Limitations
+
+%p There are four major limitations to this scheme:
+
+%ol
+ %li
+ %b Timing attacks:
+ a statistical analysis of the time that messages of a particular size are sent, received, and relayed by both service providers could reveal the map of associations.
+ %li
+ %b Log correlation problem:
+ a powerful attacker could gain access to the logs of both service providers, and thereby reconstruct the associations between the two providers.
+ %li
+ %b Single provider problem:
+ this scheme does not protect associations between people on the same service provider.
+ %li
+ %b Client problem:
+ if the user's device is compromised, the record of their actual associations can be discovered.
+
+%p At this point, we feel that it is OK to live with these limitations in order to be backward compatible with existing messaging protocols. The first two attacks are only possible by a very powerful adversary. One so powerful that association mapping is probably the least of your worries.
+
+%p This scheme is designed to prevent the casual, mass surveillance of all communication that currently takes place in repressive and democratic countries alike, by both governments and corporations. It greatly reduces the capacity for association mapping of both traffic over the wire and in stored communication. It is not designed to make a particular user anonymous in the face of a powerful adversary.
+
+%p However, a service provider using this scheme that has sufficient traffic will be in a very good position to be able to aggregate and time-shift the messages it relays in order to disrupt timing attacks&mdash;once researchers have a better understanding of how to effectively counter timing attacks. \ No newline at end of file