diff --git a/app/assets/main.html b/app/assets/main.html
index e4b18a262..6408aad6a 100644
--- a/app/assets/main.html
+++ b/app/assets/main.html
@@ -56,24 +56,8 @@
 
   <div id="modal-wrapper" class="modal-content"></div>
 
-  <div class="modal fade" id="module-loading-list">
-    <div class="modal-dialog">
-      <div class="modal-content">
-        <div class="modal-header">
-          <h4 class="modal-title">LOADING</h4>
-        </div>
-        <div class="modal-body">
-          <ul class="list-group"></ul>
-        </div>
-      </div>
-    </div>
+  <div class="progress" id="module-load-progress">
+    <div class="progress-bar"></div>
   </div>
-
-  <!--<div class="panel panel-primary" id="module-loading-list">-->
-    <!--<div class="panel-heading">-->
-      <!--<div class="panel-title">LOADING</div>-->
-    <!--</div>-->
-    <!--<ul class="list-group"></ul>-->
-  <!--</div>-->
 </body>
 </html>
diff --git a/app/core/ModuleLoader.coffee b/app/core/ModuleLoader.coffee
index 707e42528..c3be5aa65 100644
--- a/app/core/ModuleLoader.coffee
+++ b/app/core/ModuleLoader.coffee
@@ -24,10 +24,12 @@ module.exports = ModuleLoader = class ModuleLoader extends CocoClass
       return func(name, loaderPath)
     _.extend wrapped, window.require # for functions like 'list'
     window.require = wrapped
+    @updateProgress = _.throttle _.bind(@updateProgress, @), 700
+    @lastShownProgress = 0
 
   load: (path, first=true) ->
+    $('#module-load-progress').css('opacity', 1)
     if first
-      $('#module-loading-list ul').empty()
       @recentPaths = []
       @recentLoadedBytes = 0
       
@@ -35,14 +37,8 @@ module.exports = ModuleLoader = class ModuleLoader extends CocoClass
     wad = _.find ModuleLoader.WADS, (wad) -> _.string.startsWith(path, wad)
     path = wad if wad
     return false if @loaded[path]
-    $('#module-loading-list').modal('show') if first
     @loaded[path] = true
     @recentPaths.push(path)
-    li = $("<li class='list-group-item loading' data-path='#{path}'>#{path}</li>")
-      .prepend($("<span class='glyphicon glyphicon-minus'></span>"))
-      .prepend($("<span class='glyphicon glyphicon-ok'></span>"))
-    ul = $('#module-loading-list ul')
-    ul.append(li).scrollTop(ul[0].scrollHeight)
     console.debug 'Loading js file:', "/javascripts/app/#{path}.js" if LOG
     @queue.loadFile({
       id: path
@@ -59,8 +55,6 @@ module.exports = ModuleLoader = class ModuleLoader extends CocoClass
     return @load("locale/#{firstBit}", false) or loading
 
   onFileLoad: (e) =>
-    $("#module-loading-list li[data-path='#{e.item.id}']").removeClass('loading').addClass('success')
-
     # load dependencies if it's not a vendor library
     if not _.string.startsWith(e.item.id, 'vendor')
       have = window.require.list()
@@ -80,19 +74,25 @@ module.exports = ModuleLoader = class ModuleLoader extends CocoClass
 
     # get treema set up only when the library loads, if it loads
     if e.item.id is 'vendor/treema'
-      console.log 'setting up treema-ext'
       treemaExt = require 'core/treema-ext'
       treemaExt.setup()
 
     # a module and its dependencies have loaded!
     if @queue.progress is 1
-      $('#module-loading-list').modal('hide')
       @recentPaths.sort()
       console.debug @recentPaths.join('\n')
       console.debug 'loaded', @recentPaths.length, 'files,', parseInt(@recentLoadedBytes/1024), 'KB'
       @trigger 'load-complete'
       
     @trigger 'loaded', e.item
+    
+    @updateProgress()
+    
+  updateProgress: ->
+    return if @queue.progress < @lastShownProgress
+    $('#module-load-progress .progress-bar').css('width', (100*@queue.progress)+'%')
+    if @queue.progress is 1 
+      $('#module-load-progress').css('opacity', 0)
 
   parseDependencies: (raw) ->
     bits = raw.match(/(require\(['"](.+?)['"])|(register\(['"].+?['"])/g) or []
diff --git a/app/styles/common/common.sass b/app/styles/common/common.sass
index 31d9dacf4..b54695b29 100644
--- a/app/styles/common/common.sass
+++ b/app/styles/common/common.sass
@@ -353,26 +353,14 @@ html.no-borderimage
 body > iframe[src^="https://apis.google.com"]
   display: none
 
-#module-loading-list
-  .modal-content
-    background: white
-    border-shadow: 2px 2px 10px black
+#module-load-progress
+  position: absolute
+  top: 0
+  left: 0
+  right: 0
+  height: 5px
+  z-index: 1
+  transition: 1s
   
-  ul
-    max-height: 500px
-    overflow: scroll
-  
-  li
-    padding: 2px 15px
-    font-size: 10px
-    .glyphicon
-      margin-right: 10px
-    
-    &.loading
-      .glyphicon-ok
-        display: none
-        
-    &.success
-      font-weight: bold
-      .glyphicon-minus
-        display: none
+  .progress-bar
+    background-color: lightblue
diff --git a/app/templates/play/menu/inventory-modal.jade b/app/templates/play/menu/inventory-modal.jade
index 4aeb5a8f2..0129f59b2 100644
--- a/app/templates/play/menu/inventory-modal.jade
+++ b/app/templates/play/menu/inventory-modal.jade
@@ -31,9 +31,10 @@
             if itemGroups.availableItems.models.length
               h4#available-description(data-i18n="inventory.available_item")
               for item in itemGroups.availableItems.models
-                .item.available(class=item.classes, data-item-id=item.id)
-                  img(src=item.getPortraitURL())
-                  button.btn.equip-item(data-i18n="inventory.equip")
+                if selectedHeroClass && item.classes.indexOf(selectedHeroClass) > -1
+                  .item.available(class=item.classes, data-item-id=item.id)
+                    img
+                    button.btn.equip-item(data-i18n="inventory.equip")
               .clearfix
             
             #double-click-hint.alert.alert-info
@@ -43,15 +44,17 @@
             if itemGroups.restrictedItems.models.length
               h4#restricted-description(data-i18n="inventory.restricted_title")
               for item in itemGroups.restrictedItems.models
-                .item(class=item.classes, data-item-id=item.id)
-                  img(src=item.getPortraitURL(), draggable="false")
+                if selectedHeroClass && item.classes.indexOf(selectedHeroClass) > -1
+                  .item(class=item.classes, data-item-id=item.id)
+                    img(draggable="false")
               .clearfix
             
             if itemGroups.lockedItems.models.length
               h4#locked-description(data-i18n="play.locked")
               for item in itemGroups.lockedItems.models
-                .item(class=item.classes, data-item-id=item.id)
-                  img(src=item.getPortraitURL(), draggable="false")
+                if selectedHeroClass && item.classes.indexOf(selectedHeroClass) > -1
+                  .item(class=item.classes, data-item-id=item.id)
+                    img(draggable="false")
               .clearfix
 
     #item-details-view
diff --git a/app/views/play/menu/InventoryModal.coffee b/app/views/play/menu/InventoryModal.coffee
index a6293997f..a6ba6e20a 100644
--- a/app/views/play/menu/InventoryModal.coffee
+++ b/app/views/play/menu/InventoryModal.coffee
@@ -35,6 +35,7 @@ module.exports = class InventoryModal extends ModalView
     'click #close-modal': 'hide'
     'click .buy-gems-prompt-button': 'onBuyGemsPromptButtonClicked'
     'click': 'onClickedSomewhere'
+    'update #unequipped .nano': 'onScrollUnequipped'
 
   shortcuts:
     'esc': 'clearSelection'
@@ -44,6 +45,7 @@ module.exports = class InventoryModal extends ModalView
   #- Setup
 
   initialize: (options) ->
+    @onScrollUnequipped = _.throttle(_.bind(@onScrollUnequipped, @), 200)
     super(arguments...)
     @items = new CocoCollection([], {model: ThangType})
     # TODO: switch to item store loading system?
@@ -121,6 +123,7 @@ module.exports = class InventoryModal extends ModalView
     context.itemGroups = @itemGroups
     context.slots = @slots
     context.selectedHero = @selectedHero
+    context.selectedHeroClass = @selectedHero?.get('heroClass')
     context.equipment = _.clone @equipment
     context.equipment[slot] = @items.findWhere {original: itemOriginal} for slot, itemOriginal of context.equipment
     context.gems = me.gems()
@@ -524,6 +527,21 @@ module.exports = class InventoryModal extends ModalView
   onClickedSomewhere: (e) ->
     return if @destroyed
     @$el.find('.unlock-button').popover 'destroy'
+    
+    
+  #- Dynamic portrait loading
+
+  onScrollUnequipped: ->
+    # dynamically load visible items when the user scrolls enough to see them
+    nanoContent = @$el.find('#unequipped .nano-content')
+    items = nanoContent.find('.item:visible:not(.loaded)')
+    threshold = nanoContent.height() + 100
+    for itemEl in items
+      itemEl = $(itemEl)
+      if itemEl.position().top < threshold
+        itemEl.addClass('loaded')
+        item = @items.get(itemEl.data('item-id'))
+        itemEl.find('img').attr('src', item.getPortraitURL())
 
 
   #- Paper doll equipment updating
@@ -544,6 +562,7 @@ module.exports = class InventoryModal extends ModalView
     @$el.find('#hero-image-thumb').toggle not ('gloves' in slotsWithImages)
 
     @equipment = @options.equipment = equipment
+    @onScrollUnequipped()
 
   removeDollImages: ->
     @$el.find('.doll-image').remove()
diff --git a/app/views/play/modal/SubscribeModal.coffee b/app/views/play/modal/SubscribeModal.coffee
index 8b5381f42..157e49dda 100644
--- a/app/views/play/modal/SubscribeModal.coffee
+++ b/app/views/play/modal/SubscribeModal.coffee
@@ -53,10 +53,20 @@ module.exports = class SubscribeModal extends ModalView
     return @openModalView new AuthModal() if me.get('anonymous')
     application.tracker?.trackEvent 'Started subscription purchase', {}
     application.tracker?.trackPageView "subscription/start-purchase", ['Google Analytics']
-    stripeHandler.open({
+    options = {
       description: $.i18n.t('subscribe.stripe_description')
       amount: @product.amount
-    })
+    }
+
+    # SALE LOGIC
+    # overwrite amount with sale price
+    # maybe also put in another description with details about how long it lasts, etc
+#    options = {
+#      description: 'Subscription. Half price for three months!'
+#      amount: 499
+#    }
+
+    stripeHandler.open(options)
 
   onStripeReceivedToken: (e) ->
     @state = 'purchasing'
diff --git a/server/payments/subscription_handler.coffee b/server/payments/subscription_handler.coffee
index 2ab45ed48..63170bb33 100644
--- a/server/payments/subscription_handler.coffee
+++ b/server/payments/subscription_handler.coffee
@@ -68,6 +68,11 @@ class SubscriptionHandler extends Handler
 
   checkForExistingSubscription: (req, user, customer, done) ->
     couponID = user.get('stripe')?.couponID
+    
+    # SALE LOGIC
+    # overwrite couponID with another for everyone-sales
+    # couponID = 'hoc_bonanza' if not couponID
+    
     if subscription = customer.subscriptions?.data?[0]
 
       if subscription.cancel_at_period_end