commit 8f287a7184a0fc045db62acd95351ebfb163d380 Author: Ian Gulliver Date: Mon Nov 17 20:59:03 2014 -0800 Initial commit. diff --git a/app.yaml b/app.yaml new file mode 100644 index 0000000..74c088a --- /dev/null +++ b/app.yaml @@ -0,0 +1,21 @@ +runtime: python27 +version: 1 +api_version: 1 +application: strife-drafter +threadsafe: true + +handlers: +- url: / + static_files: index.html + upload: index.html + secure: always + +- url: /static + static_dir: static + secure: always + +includes: +- cosmopolite + +inbound_services: +- channel_presence diff --git a/index.html b/index.html new file mode 100644 index 0000000..a9458a1 --- /dev/null +++ b/index.html @@ -0,0 +1,51 @@ + + + + + Strife Drafter + + + + + + + + + +
+ +
+
+ +
+
+
+ +
+
+ +
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+ + diff --git a/static/ban.png b/static/ban.png new file mode 100644 index 0000000..6f51b1b Binary files /dev/null and b/static/ban.png differ diff --git a/static/draft.js b/static/draft.js new file mode 100644 index 0000000..1c27c53 --- /dev/null +++ b/static/draft.js @@ -0,0 +1,532 @@ +var HEROES = [ + 'Ray', + 'Fetterstone', + 'Claudessa', + 'Caprice', + 'Lady Tinder', + 'Shank', + 'Vermillion', + 'Malady', + 'Bo', + 'Carter', + 'Ace', + 'Moxie', + 'Bastion', + 'Hale', + 'Minerva', + 'Rook', + 'Vex', + 'Trixie', + 'Blazer', + 'Harrower', + 'Gokong', + 'Jin She', + 'Nikolai', +]; + +var steps = [ + { + 'type': 'seating', + }, + { + 'type': 'countdown', + 'seconds': 10, + }, + { + 'type': 'ban', + 'side': 'glory', + 'seconds': 60, + 'slots': 1, + }, + { + 'type': 'ban', + 'side': 'valor', + 'seconds': 60, + 'slots': 1, + }, + { + 'type': 'pick', + 'side': 'glory', + 'seconds': 60, + 'slots': 1, + }, + { + 'type': 'pick', + 'side': 'valor', + 'seconds': 60, + 'slots': 2, + }, + { + 'type': 'pick', + 'side': 'glory', + 'seconds': 60, + 'slots': 2, + }, + { + 'type': 'pick', + 'side': 'valor', + 'seconds': 60, + 'slots': 2, + }, + { + 'type': 'pick', + 'side': 'glory', + 'seconds': 60, + 'slots': 2, + }, + { + 'type': 'pick', + 'side': 'valor', + 'seconds': 60, + 'slots': 1, + }, + { + 'type': 'end', + } +]; +var next_step = 0; +var client_last_step_time = 0; +var server_last_step_time = 0; + +var cosmo, game_id; +var sides = { + 'global': { + 'bans': [ + 'Gokong', + ], + }, + 'glory': { + 'bans': [], + 'picks': [], + 'team_name': '???', + 'extra_seconds': 60, + }, + 'valor': { + 'bans': [], + 'picks': [], + 'team_name': '???', + 'extra_seconds': 60, + }, +}; + +var getTime = function() { + return Math.floor(new Date().getTime() / 1000); +} + +var setTeamName = function() { + localStorage['strife-drafter:team_name'] = prompt( + 'Enter your team name, or Cancel to observe.') || ''; + return localStorage['strife-drafter:team_name']; +}; + +var onSideClick = function(sidename) { + if (!localStorage['strife-drafter:team_name']) { + while (confirm( + 'You must set a team name before participating in the draft.' + + 'Would you like to set a team name now?')) { + if (setTeamName()) { + break; + }; + } + if (!localStorage['strife-drafter:team_name']) { + return; + } + } + cosmo.sendMessage(game_id, { + 'type': 'sideclick', + 'side': sidename, + 'team_name': localStorage['strife-drafter:team_name'], + }); +}; + +var onHeroClick = function(heroname) { + if (!everyoneSeated()) { + alert('Everyone must be seated before picks & bans begin.'); + return; + } + cosmo.sendMessage(game_id, { + 'type': 'heroclick', + 'hero': heroname, + }); +}; + +var sideBySender = function(sender) { + for (var side in sides) { + if (sides[side].sender == sender) { + return side; + } + } + return null; +}; + +var everyoneSeated = function(sender) { + for (var side in sides) { + if (!sides[side].team_name) { + continue; + } + if (!sides[side].sender) { + return false; + } + } + return true; +}; + +var setGameTitle = function() { + var title = document.getElementById('game-title'); + var text = sides['glory'].team_name + ' vs. ' + sides['valor'].team_name; + title.textContent = text; +}; + +var onMessage = function(msg) { + var app_msg = msg.message; + + var sender_side = sideBySender(msg.sender); + + if (steps[next_step].seconds) { + var server_seconds = msg.created - server_last_step_time; + var allowed_seconds = steps[next_step].seconds; + if (steps[next_step].side) { + allowed_seconds += sides[steps[next_step].side].extra_seconds; + } + if (server_seconds > allowed_seconds) { + // Server timestamps rule, and this message is too late. + nextStep(msg); + } + } + + switch (app_msg.type) { + case 'sideclick': + if (!(app_msg.side in sides) || !sides[app_msg.side].team_name) { + console.log('sideclick invalid side:', msg); + return; + } + if (sides[app_msg.side].sender) { + console.log('sideclick duplicate side:', msg); + return; + } + if (sender_side) { + console.log('sideclick multiple sides per sender:', msg); + return; + } + sides[app_msg.side].sender = msg.sender; + sides[app_msg.side].team_name = app_msg.team_name; + setGameTitle(); + if (everyoneSeated()) { + nextStep(msg); + } + break; + + case 'heroclick': + if (!everyoneSeated()) { + console.log('heroclick before everyone seated:', msg); + return; + } + if (!sender_side) { + console.log('heroclick from unknown source:', msg); + return; + } + if (!steps[next_step]) { + console.log('heroclick on invalid step:', msg); + return; + } + if (steps[next_step].side != sender_side) { + console.log('heroclick from wrong side:', msg); + return; + } + if (HEROES.indexOf(app_msg.hero) == -1) { + console.log('heroclick for unknown hero:', msg); + return; + } + if (unavailableHeroes().indexOf(app_msg.hero) != -1) { + console.log('heroclick for unavailable hero:', msg); + return; + } + addHero(app_msg.hero); + if (!steps[next_step].slots_remaining) { + nextStep(msg); + } + break; + + case 'timeout': + // Work already done above. + break; + + default: + console.log('Unknown message type:', app_msg); + break; + } +}; + +var addHero = function(hero_name) { + var hero = buildHero(hero_name); + var step = steps[next_step]; + var side = sides[step.side]; + if (step.type == 'ban') { + side.bans.push(hero_name); + } else if (step.type == 'pick') { + side.picks.push(hero_name); + } + var container_index = step.slots - step.slots_remaining; + step.containers[container_index].appendChild(hero); + step.slots_remaining--; + updateHeroes(); +}; + +var nextStep = function(msg) { + var old_step = steps[next_step]; + + switch (old_step.type) { + case 'seating': + if (!sideBySender(cosmo.currentProfile())) { + document.body.className = 'observer'; + } + break; + + case 'countdown': + server_last_step_time += old_step.seconds; + client_last_step_time = getTime(); + document.getElementById('countdown').className = null; + break; + + case 'pick': + case 'ban': + for (var i = 0; i < old_step.containers.length; i++) { + var container = old_step.containers[i]; + container.className = container.className.split(' ')[0]; + } + + // Measure real time impact from server timestamps. + var server_seconds = msg.created - server_last_step_time; + server_seconds -= old_step.seconds; + if (server_seconds > 0) { + sides[old_step.side].extra_seconds -= server_seconds; + if (sides[old_step.side].extra_seconds < 0) { + sides[old_step.side].extra_seconds = 0; + var random_value = msg.random_value; + while (old_step.slots_remaining) { + var available = availableHeroes(); + var hero = available[random_value % available.length]; + console.log('Random hero choice:', hero); + addHero(hero); + random_value >>>= 8; + } + } + } + updateTimers(); + break; + } + + next_step++; + var new_step = steps[next_step]; + + switch (new_step.type) { + case 'countdown': + document.getElementById('countdown').className = 'active'; + break; + + case 'pick': + case 'ban': + new_step.slots_remaining = new_step.slots; + for (var i = 0; i < new_step.containers.length; i++) { + new_step.containers[i].className += ' next-step'; + } + break; + + case 'end': + document.getElementById('slide').className = 'active'; + break; + } + + if (msg) { + server_last_step_time = msg.created; + client_last_step_time = getTime(); + } +}; + +var unavailableHeroes = function() { + var ret = []; + for (var side in sides) { + ret.push.apply(ret, sides[side].bans); + ret.push.apply(ret, sides[side].picks); + } + return ret; +}; + +var availableHeroes = function() { + var unavailable = unavailableHeroes(); + var ret = []; + for (var i = 0; i < HEROES.length; i++) { + var hero = HEROES[i]; + if (unavailable.indexOf(hero) == -1) { + ret.push(hero); + } + } + return ret; +}; + +var updateHeroes = function() { + var unavailable = unavailableHeroes(); + for (var i = 0; i < unavailable.length; i++) { + var hero = unavailable[i]; + var container = document.getElementById('hero-' + hero); + container.className = 'hero-overlay hero-unavailable'; + } +}; + +var updateTimers = function() { + for (var side in sides) { + if (!sides[side].team_name) { + continue; + } + sides[side].extra_seconds_cont.textContent = sides[side].extra_seconds; + for (var i = next_step; i < steps.length; i++) { + var step = steps[i]; + if (step.side == side) { + sides[step.side].step_seconds_cont.textContent = step.seconds; + break; + } + } + } +}; + +var populateSides = function() { + for (var side in sides) { + if (!sides[side].team_name) { + continue; + } + sides[side].container = document.getElementById(side + '-cont'); + document.getElementById(side).addEventListener('click', + onSideClick.bind(null, side)); + sides[side].extra_seconds_cont = document.getElementById(side + '-extra'); + sides[side].step_seconds_cont = document.getElementById(side + '-step'); + } + + for (var i = 0; i < steps.length; i++) { + var step = steps[i]; + switch (step.type) { + case 'pick': + case 'ban': + step.containers = []; + for (var j = 0; j < step.slots; j++) { + var div = document.createElement('div'); + if (step.type == 'ban') { + div.className = 'heroban-cont'; + } else if (step.type == 'pick') { + div.className = 'hero-cont'; + } + sides[step.side].container.appendChild(div); + step.containers.push(div); + } + break; + } + } +}; + +var buildHero = function(hero) { + var container = document.createElement('div'); + container.className = 'hero-overlay'; + + var img = document.createElement('img'); + img.src = 'static/heroes/' + hero.toLowerCase().replace(' ', '') + '.png'; + img.className = 'hero-medium'; + + var text = document.createElement('div'); + text.className = 'text-overlay'; + text.appendChild(document.createTextNode(hero)); + + container.appendChild(img); + container.appendChild(text); + return container; +}; + +var tick = function() { + var step = steps[next_step]; + + if (!step.seconds) { + // Not a lot for a timer to do. + return; + } + + var side = step.side; + var client_allowed_seconds = steps[next_step].seconds; + if (side) { + client_allowed_seconds += sides[step.side].extra_seconds; + } + var client_actual_seconds = getTime() - client_last_step_time; + + var seconds_left = client_allowed_seconds - client_actual_seconds; + if (seconds_left < 0) { + cosmo.sendMessage(game_id, { + 'type': 'timeout', + }); + return; + } + + switch (step.type) { + case 'countdown': + document.getElementById('countdown').textContent = seconds_left; + break; + + case 'pick': + case 'ban': + var step_seconds = step.seconds; + var extra_seconds = sides[step.side].extra_seconds; + step_seconds -= client_actual_seconds; + if (step_seconds >= 0) { + sides[side].step_seconds_cont.textContent = step_seconds; + } else { + extra_seconds += step_seconds; + sides[side].extra_seconds_cont.textContent = extra_seconds; + } + break; + } +}; + +document.addEventListener('DOMContentLoaded', function() { + // Instantiate cosmo instance. + var callbacks = { + 'onMessage': onMessage, + }; + cosmo = new Cosmopolite(callbacks, null, 'strife-drafter'); + + // Determine or generate game ID + if (!window.location.hash) { + var binary_id = []; + for (var i = 0; i < 9; i++) { + binary_id.push(String.fromCharCode(Math.random() * 256)); + } + window.location.hash = + btoa(binary_id.join('')).replace('+', '-').replace('/', '_'); + } + + game_id = window.location.hash.slice(1); + + window.addEventListener('hashchange', function() { + window.location.reload(); + }); + + // Prompt for team name if necessary. + if (localStorage['strife-drafter:team_name'] == undefined) { + setTeamName(); + } + + // Start pulling event stream. + cosmo.subscribe(game_id, -1); + + // Add hero objects and callbacks. + var heroes_container = document.getElementById('heroes'); + + for (var i = 0; i < HEROES.length; i++) { + var hero = HEROES[i]; + var container = buildHero(hero); + container.id = 'hero-' + hero; + container.addEventListener('click', onHeroClick.bind(null, hero)); + heroes_container.appendChild(container); + } + + updateHeroes(); + populateSides(); + setGameTitle(); + updateTimers(); + setInterval(tick, 250); +}); diff --git a/static/fctv.svg b/static/fctv.svg new file mode 100644 index 0000000..9d9b5ab --- /dev/null +++ b/static/fctv.svg @@ -0,0 +1,3466 @@ + + + + + + + + + + +flamingcow.tv + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/static/heroes/ace.png b/static/heroes/ace.png new file mode 100644 index 0000000..95ecc39 Binary files /dev/null and b/static/heroes/ace.png differ diff --git a/static/heroes/bastion.png b/static/heroes/bastion.png new file mode 100644 index 0000000..e75d9b0 Binary files /dev/null and b/static/heroes/bastion.png differ diff --git a/static/heroes/blazer.png b/static/heroes/blazer.png new file mode 100644 index 0000000..0e4cec3 Binary files /dev/null and b/static/heroes/blazer.png differ diff --git a/static/heroes/bo.png b/static/heroes/bo.png new file mode 100644 index 0000000..060bb16 Binary files /dev/null and b/static/heroes/bo.png differ diff --git a/static/heroes/caprice.png b/static/heroes/caprice.png new file mode 100644 index 0000000..30dff6f Binary files /dev/null and b/static/heroes/caprice.png differ diff --git a/static/heroes/carter.png b/static/heroes/carter.png new file mode 100644 index 0000000..b1a7f55 Binary files /dev/null and b/static/heroes/carter.png differ diff --git a/static/heroes/claudessa.png b/static/heroes/claudessa.png new file mode 100644 index 0000000..7789bf9 Binary files /dev/null and b/static/heroes/claudessa.png differ diff --git a/static/heroes/fetterstone.png b/static/heroes/fetterstone.png new file mode 100644 index 0000000..61c960e Binary files /dev/null and b/static/heroes/fetterstone.png differ diff --git a/static/heroes/gokong.png b/static/heroes/gokong.png new file mode 100644 index 0000000..617ff87 Binary files /dev/null and b/static/heroes/gokong.png differ diff --git a/static/heroes/hale.png b/static/heroes/hale.png new file mode 100644 index 0000000..3810b84 Binary files /dev/null and b/static/heroes/hale.png differ diff --git a/static/heroes/harrower.png b/static/heroes/harrower.png new file mode 100644 index 0000000..23370f6 Binary files /dev/null and b/static/heroes/harrower.png differ diff --git a/static/heroes/jinshe.png b/static/heroes/jinshe.png new file mode 100644 index 0000000..6954a0a Binary files /dev/null and b/static/heroes/jinshe.png differ diff --git a/static/heroes/ladytinder.png b/static/heroes/ladytinder.png new file mode 100644 index 0000000..4a4c531 Binary files /dev/null and b/static/heroes/ladytinder.png differ diff --git a/static/heroes/malady.png b/static/heroes/malady.png new file mode 100644 index 0000000..8823764 Binary files /dev/null and b/static/heroes/malady.png differ diff --git a/static/heroes/minerva.png b/static/heroes/minerva.png new file mode 100644 index 0000000..b26c98f Binary files /dev/null and b/static/heroes/minerva.png differ diff --git a/static/heroes/moxie.png b/static/heroes/moxie.png new file mode 100644 index 0000000..87970b9 Binary files /dev/null and b/static/heroes/moxie.png differ diff --git a/static/heroes/nikolai.png b/static/heroes/nikolai.png new file mode 100644 index 0000000..df2fba2 Binary files /dev/null and b/static/heroes/nikolai.png differ diff --git a/static/heroes/ray.png b/static/heroes/ray.png new file mode 100644 index 0000000..e2042fd Binary files /dev/null and b/static/heroes/ray.png differ diff --git a/static/heroes/rook.png b/static/heroes/rook.png new file mode 100644 index 0000000..c1adfc1 Binary files /dev/null and b/static/heroes/rook.png differ diff --git a/static/heroes/shank.png b/static/heroes/shank.png new file mode 100644 index 0000000..5d6e4b0 Binary files /dev/null and b/static/heroes/shank.png differ diff --git a/static/heroes/trixie.png b/static/heroes/trixie.png new file mode 100644 index 0000000..1906f25 Binary files /dev/null and b/static/heroes/trixie.png differ diff --git a/static/heroes/vermillion.png b/static/heroes/vermillion.png new file mode 100644 index 0000000..8badca1 Binary files /dev/null and b/static/heroes/vermillion.png differ diff --git a/static/heroes/vex.png b/static/heroes/vex.png new file mode 100644 index 0000000..c6ff49a Binary files /dev/null and b/static/heroes/vex.png differ diff --git a/static/style.css b/static/style.css new file mode 100644 index 0000000..2810c8f --- /dev/null +++ b/static/style.css @@ -0,0 +1,227 @@ +@-webkit-keyframes flipIn { + 0% { + transform: rotateY(180deg); + } + 100% { + transform: rotateY(0); + } +} + +.observer { + cursor: none; +} + +.observer > * { + pointer-events: none; +} + +div.observer { + pointer-events: none; +} + +button { + display: inline-block; + padding: 6px 12px; + margin-bottom: 0; + font-family: Oswald, sans-serif; + font-size: 14px; + text-align: center; + white-space: nowrap; + vertical-align: middle; + cursor: pointer; + border: 1px solid transparent; + border-radius: 4px; + color: #fff; + background-color: #337ab7; + border-color: #2e6da4; +} + +button:hover { + color: #fff; + background-color: #286090; + border-color: #204d74; +} + +button:focus { + outline: 0; +} + +.hero-medium { + width: 96px; + height: 96px; + margin-top: 2px; + border-radius: 10px; +} + +.hero-overlay { + display: inline-block; + position: relative; + width: 96px; + height: 96px; + margin: 5px; + cursor: pointer; + transition: opacity 0.25s; +} + +.hero-overlay:hover { + opacity: 0.7; +} + +.hero-unavailable { + transition: transform 0.5s; + transform: rotateY(180deg); + backface-visibility: hidden; + cursor: default; +} + +.hero-unavailable:hover { + opacity: 0.3; +} + +.hero-cont { + background-color: grey; + width: 100px; + height: 100px; + margin-top: 5px; + margin-bottom: 5px; + border-radius: 10px; + transition: box-shadow 0.5s; +} + +.heroban-cont { + background: url("ban.png") no-repeat 0 0, grey; + background-position: 0px 0px; + background-size: 100% 100%; + width: 100px; + height: 100px; + margin-top: 5px; + margin-bottom: 5px; + border-radius: 10px; + transition: box-shadow 0.5s; +} + +.hero-cont .hero-overlay { + margin: 0; + cursor: default; + -webkit-animation-name: flipIn; + -webkit-animation-iteration-count: once; + -webkit-animation-timing-function: ease-in-out; + -webkit-animation-duration: 0.5s; + backface-visibility: hidden; +} + +.hero-cont .hero-overlay:hover { + opacity: 1.0; +} + +.heroban-cont .hero-overlay { + margin: 0; + opacity: 0.3; + cursor: default; + -webkit-animation-name: flipIn; + -webkit-animation-iteration-count: once; + -webkit-animation-timing-function: ease-in-out; + -webkit-animation-duration: 0.5s; + backface-visibility: hidden; +} + +.heroban-cont .hero-overlay:hover { + opacity: 0.3; +} + +.next-step { + box-shadow: 0 0 10px red; +} + +.text-overlay { + position: absolute; + bottom: 0px; + left: 0px; + width: 100%; + text-align: center; + color: #fff; + font-family: Oswald, sans-serif; + font-size: 15px; + text-shadow: 0 0 1px black; +} + +.container { + display: flex; + justify-content: center; +} + +.team-column { + flex-shrink: 0; + text-align: center; +} + +.hero-column { + text-align: center; + margin: 10px; + max-width: 800px; +} + +.title-container { + display: flex; +} + +.timer { + font-family: Audiowide, sans-serif; + min-width: 5em; +} + +#game-title { + font-family: Oswald, sans-serif; + font-size: 20px; + flex-grow: 1; +} + +#heroes { + position: relative; +} + +#countdown { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: -1; + font-size: 200px; + line-height: 200%; + color: black; + text-shadow: 0 0 15px white; + background-color: rgba(255, 255, 255, 0.5); + cursor: default; + opacity: 0.0; + transition: opacity 0.5s, z-index 0.5s; + font-family: Audiowide, sans-serif; +} + +#countdown.active { + z-index: 100; + opacity: 1.0; +} + +#slide { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: -1; + font-size: 200px; + line-height: 200%; + color: black; + cursor: default; + opacity: 0.0; + transition: opacity 2s, z-index 2s; + font-family: Oswald, sans-serif; + background: white url("fctv.svg") no-repeat top; + background-size: 100% 100%; +} + +#slide.active { + z-index: 100; + opacity: 1.0; +}