Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URLs added here will be added as <link>s in order, and before the CSS in the editor. You can use the CSS from another Pen by using its URL and the proper URL extension.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Auto Save

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <div id="stage" class="stage" :class="{'menu-open': menuOpen, 'voices-open': voicesOpen}" :style="{ color: activeReminder.waveFrontColor, backgroundColor: stageBg }" v-cloak>
  <div class="menu__button" @click="toggleMenu">
    <div class="menu__dot"></div>
  </div>
  <div class="microphone" v-if="supportSpeechRecognition" :class="{'is-listening': isListening }" @click="startListenVoiceCommands">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
                <path d="M12 16c2.206 0 4-1.795 4-4v-6c0-2.206-1.794-4-4-4s-4 1.794-4 4v6c0 2.205 1.794 4 4 4z"></path>
                <path d="M19 12v-2c0-0.552-0.447-1-1-1s-1 0.448-1 1v2c0 2.757-2.243 5-5 5s-5-2.243-5-5v-2c0-0.552-0.447-1-1-1s-1 0.448-1 1v2c0 3.52 2.613 6.432 6 6.92v1.080h-3c-0.553 0-1 0.447-1 1s0.447 1 1 1h8c0.553 0 1-0.447 1-1s-0.447-1-1-1h-3v-1.080c3.387-0.488 6-3.4 6-6.92z"></path>
            </svg>
    <div class="voice-tooltip" v-show="isListening">
                <transition name="fade" mode="out-in">
                    <span :key="tooltipText">{{ tooltipText }}</span>
                </transition>
            </div>
  </div>
  <div class="voices-menu">
    <svg class="voices-menu__bg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50"><title>sphere</title><circle cx="25" cy="25" r="25"/></svg>
    <div class="voices-menu__button" @click="toggleVoicesMenu">
      <svg xmlns="http://www.w3.org/2000/svg" width="768" height="768" viewBox="0 0 768 768">
                    <path d="M523.5 448.5h108c4.5-21 9-42 9-64.5s-4.5-43.5-9-64.5h-108c3 21 4.5 42 4.5 64.5s-1.5 43.5-4.5 64.5zM466.5 625.5c58.5-19.5 109.5-61.5 139.5-114h-94.5c-10.5 40.5-25.5 78-45 114zM459 448.5c3-21 4.5-42 4.5-64.5s-1.5-43.5-4.5-64.5h-150c-3 21-4.5 42-4.5 64.5s1.5 43.5 4.5 64.5h150zM384 639c27-39 48-81 61.5-127.5h-123c13.5 46.5 34.5 88.5 61.5 127.5zM256.5 256.5c10.5-40.5 25.5-78 45-114-58.5 19.5-109.5 61.5-139.5 114h94.5zM162 511.5c30 52.5 81 94.5 139.5 114-19.5-36-34.5-73.5-45-114h-94.5zM136.5 448.5h108c-3-21-4.5-42-4.5-64.5s1.5-43.5 4.5-64.5h-108c-4.5 21-9 42-9 64.5s4.5 43.5 9 64.5zM384 129c-27 39-48 81-61.5 127.5h123c-13.5-46.5-34.5-88.5-61.5-127.5zM606 256.5c-30-52.5-81-94.5-139.5-114 19.5 36 34.5 73.5 45 114h94.5zM384 64.5c177 0 319.5 142.5 319.5 319.5s-142.5 319.5-319.5 319.5-319.5-142.5-319.5-319.5 142.5-319.5 319.5-319.5z"></path>
                </svg>
      <span>Select voice</span>
    </div>
    <div class="voices-menu__close" @click="toggleVoicesMenu">
      <svg xmlns="http://www.w3.org/2000/svg" width="768" height="768" viewBox="0 0 768 768">
                    <path d="M607.5 205.5l-178.5 178.5 178.5 178.5-45 45-178.5-178.5-178.5 178.5-45-45 178.5-178.5-178.5-178.5 45-45 178.5 178.5 178.5-178.5z"></path>
                </svg>
    </div>
    <div class="voices-list-wrapper">
      <ul class="voices-list">
        <li class="voices-list__item" :class="{'is-selected': selectedVoice.name === voice.name }" v-for="voice in voices" :key="voice.lang">
          <a href="#" class="voices-list__link" @click.prevent="voiceSelected(voice)">
            <span class="voices-list__icon">
                                <svg xmlns="http://www.w3.org/2000/svg" width="768" height="768" viewBox="0 0 768 768">
                                    <path d="M672 160q13.75 0 22.875 9.125t9.125 22.875q0 13.5-9.25 22.75l-384 384q-9.25 9.25-22.75 9.25t-22.75-9.25l-192-192q-9.25-9.25-9.25-22.75 0-13.75 9.125-22.875t22.875-9.125q13.5 0 22.75 9.25l169.25 169.5 361.25-361.5q9.25-9.25 22.75-9.25z"></path>
                                </svg>
                            </span>
            <div class="voices-list__content">
              <div>{{voice.name}}</div>
              <span>{{voice.lang}}</span>
              <span v-if="voice.default" class="voices-list__default">Default</span>
            </div>
          </a>
        </li>
      </ul>
    </div>
  </div>
  <div class="menu">
    <ul class="menu__list">
      <li class="menu__item" @mouseover="mouseOver('water')" @mouseout="mouseOut()" @touchstart="mouseOver('water')" @touchend="mouseOut()">
        <a href="#" @click.prevent="start('water')">
          <svg id="coffee-cup" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50">
                            <title>coffee-cup-01</title>
                            <path class="water-glass" d="M39.92,45H25V43.21H38.15L43.14,4l2,.2ZM25,45H10.08L4.89,4.15l2-.2,5,39.26H25Z"/>
                            <path class="water-glass__water" d="M39.09,6.88s-3.13,2-5.48,0c-4.92,2.65-7.72,0-7.72,0s-4.59,2.76-7.94,0c-4.47,3.09-7,0-7,0l3.91,33.76H35Z"/>
                        </svg>
          <span>Water break</span>
        </a>
      </li>
      <li class="menu__item" @mouseover="mouseOver('coffee')" @mouseout="mouseOut()" @touchstart="mouseOver('coffee')" @touchend="mouseOut()">
        <a href="#" @click.prevent="start('coffee')">
          <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50">
                            <title>coffee-cup</title>
                            <path class="coffee-cup" d="M49.42,21.07a9.69,9.69,0,0,0-2.17-6.55,10.16,10.16,0,0,0-7.08-3.12c-.14-2.47-.38-4-.38-4H36.58S42,39.54,20.43,39.56C-1.87,39.57,4.16,7.37,4.16,7.37H1.07S-4.29,43,20.43,43c9.31,0,14.35-5.06,17-11.37C40.47,31.4,49.43,29.84,49.42,21.07Zm-11,7.82a49,49,0,0,0,1.81-14.83,8.13,8.13,0,0,1,5.52,2.4,6.76,6.76,0,0,1,1.49,4.63C47.29,26.71,41.58,28.39,38.45,28.89Z"/>
                            <path class="coffee-cup__coffee" d="M7.07,11.94H33.73s3.72,23.65-13.3,23.65S7.07,11.94,7.07,11.94Z"/>
                        </svg>
          <span>Coffee break</span>
        </a>
      </li>
      <li class="menu__item" @mouseover="mouseOver('break')" @mouseout="mouseOut()" @touchstart="mouseOver('break')" @touchend="mouseOut()">
        <a href="#" @click.prevent="start('break')">
          <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50">
                            <title>clock</title>
                            <path class="clock" d="M24.62,47.08A21.88,21.88,0,1,1,46.49,25.21,21.9,21.9,0,0,1,24.62,47.08Zm0-41.75A19.88,19.88,0,1,0,44.49,25.21,19.9,19.9,0,0,0,24.62,5.33Z"/>
                            <path class="clock__short" d="M34.49,26.71H24.62a1.5,1.5,0,0,1,0-3h9.88a1.5,1.5,0,0,1,0,3Z"/>
                            <path class="clock__long" d="M24.62,26.71a1.5,1.5,0,0,1-1.5-1.5V9.54a1.5,1.5,0,0,1,3,0V25.21A1.5,1.5,0,0,1,24.62,26.71Z"/>
                        </svg>
          <span>Office Break</span>
        </a>
      </li>
      <li class="menu__item" @mouseover="mouseOver('beer')" @mouseout="mouseOut()" @touchstart="mouseOver('beer')" @touchend="mouseOut()">
        <a href="#" @click.prevent="start('beer')">
          <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50">
            <title>beer</title>
            <path class="beer-glass" d="M45.92,15.71c-1.63-1.88-6.55-1.15-9.2-.58-.15-2.82-.25-5.46-.26-7.76h-2c0,3.69.27,8.17.55,12.92.48,8.19,1.21,20.56-.59,21.86-3.17,2.29-29,2.49-31,.23C2,40.7,2.45,23.3,3.69,7.45l-1-.08-1-.08C1.08,15.1-.69,40.8,1.95,43.72c1.39,1.54,8.15,2.19,15.27,2.19,8,0,16.56-.83,18.38-2.14,1.3-.94,1.84-3.56,2-7.66,2-.05,6.17-.29,8.09-1.36.78-.44,1.3-1.49,1.62-3.32C48,27.21,47.61,17.67,45.92,15.71Zm-.4,13.59c-.27,3.16-.85,3.7-.84,3.7-1.4.78-5,1-7.1,1.11,0-3.71-.25-8.38-.58-13.93q-.09-1.53-.17-3c3.26-.71,6.88-.93,7.58-.13S46,24.13,45.52,29.3Z"/>
<path class="beer-glass__beer" d="M5.9,12.92s-2.57,25.8,0,27.71,24.3,1,26.59,0S32,12.92,32,12.92Z"/>
          </svg>
          <span>Beer Break</span>
        </a>
      </li>
    </ul>
  </div>
  <div class="browser-support" v-if="!supportSpeechSynth">
    Your browser doesn't <strong>support</strong> speech synthesis.
  </div>
  <div class="time">
    <transition-group name="timer" tag="div">
      <div v-for="time in timer" class="timer__item" :key="time.id">
        {{ time.value }}
      </div>
    </transition-group>
  </div>
  <div class="waves" :style="waveStyles">
    <div class="wave wave--back" :style="{ color: activeReminder.waveBackColor }">
      <div class="water">
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 350 32" preserveAspectRatio="none"><title>wave2</title><path d="M350,17.32V32H0V17.32C116.56,65.94,175-39.51,350,17.32Z"/></svg>
      </div>
      <div class="water">
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 350 32" preserveAspectRatio="none"><title>wave2</title><path d="M350,17.32V32H0V17.32C116.56,65.94,175-39.51,350,17.32Z"/></svg>
      </div>
    </div>
    <div class="wave wave--front" :style="{ color: activeReminder.waveFrontColor }">
      <div class="water">
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 350 32" preserveAspectRatio="none"><title>wave2</title><path d="M350,17.32V32H0V17.32C116.56,65.94,175-39.51,350,17.32Z"/></svg>
      </div>
      <div class="water">
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 350 32" preserveAspectRatio="none"><title>wave2</title><path d="M350,17.32V32H0V17.32C116.56,65.94,175-39.51,350,17.32Z"/></svg>
      </div>
    </div>
  </div>
  <div class="content">
    <div class="percent">
      <transition name="percent-left" mode="out-in">
        <div :key="percentsLeft">{{ percentsLeft }}</div>
      </transition>
      <span>%</span>
    </div>
  </div>
  <button @click="reset">
            {{ percentsLeft > 0 ? activeReminder.buttonTxt : 'Reset' }}
        </button>
</div>
              
            
!

CSS

              
                @import url('https://fonts.googleapis.com/css?family=Roboto:100,400');

$blue-dark:        #1E384C;
$blue:             #2C7FBE;
$blue-light:       #32BAFA;
$green:            #02C39A;

$stage-bg:           $blue-dark;

*, *::after, *::before {
    box-sizing: border-box;
}
html, body {
    height: 100%;
    min-height: 100%;
}
body {
    margin: 0;  
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: 'Roboto', sans-serif;
    background: linear-gradient(to bottom right, #c8c897, #6590A2);
}
[v-cloak] { display:none; }
a {
    -webkit-tap-highlight-color: rgba(0,0,0,0);
    user-select: none;
}

::-webkit-scrollbar { 
    display: none; 
}

.stage {
    position: relative;
    overflow: hidden;
    width: 100%;
    height: 100%;
    background: #fff;
    box-shadow: 0 10px 20px rgba(0,0,0,0.2);
    background: $stage-bg;
    transition: background-color .3s; 

    @media (min-width: 500px) {
        border-radius: 5px;
        max-height: 550px;
        max-width: 350px;
    }

    &.menu-open {
        .microphone {
            transform: translate3d(-1em,0,0);
            opacity: 0;
        }
        .voices-menu__button {
            z-index: 40;
            transform: translate3d(0,0,0);
            opacity: 1;
        }
        .menu {
            z-index: 25;
        }
        .time {
            transform: translate3d(0,-200%,0);
            transition: .5s opacity, .5s transform;
            opacity: 0;
        }
        button {
            transform: translate3d(0,200%,0);
            transition-delay: 0s;
            opacity: 0;
        }
        .percent {
            transition: .4s opacity, .4s transform;
            transform: translate3d(0,50%,0);
            opacity: 0;
        }

        .menu__item {
            opacity: 1;
            transform: translate3d(0,0,0);
            
            &:nth-child(1) {
                transition-delay: .2s;
            }
            &:nth-child(2) {
                transition-delay: .3s;
            }
            &:nth-child(3) {
                transition-delay: .4s;
            }
            &:nth-child(4) {
                transition-delay: .5s;
            }
        }
    }

    &.voices-open {
        .voices-menu {
            z-index: 35;
        }
        .voices-menu__bg {
            transform: scale(6);
        }
        
        .voices-menu__close {
            opacity: 1;
            transform: translate3d(0,0,0) rotate(0);
        }

        .voices-list-wrapper {
            opacity: 1;
        }
        .voices-list__item {
            opacity: 1;
            transform: translate(0,0);
            transition: opacity .15s, transform .2s;
        }
        
        @for $i from 1 through 10 {
            .voices-list__item:nth-child(#{$i}) {
                transition-delay: 75ms * $i;
            }
        }
    }
}

.microphone {
    z-index: 30;
    position: absolute;
    top: -.5em;
    left: -.8em;
    width: 70px;
    height: 70px;
    display: flex;
    justify-content: center;
    align-items: center;
    cursor: pointer;

    color: rgba(#fff, .5);
    transition: opacity .3s, transform .3s, color .2s;

    &:hover {
        color: rgba(#fff, .8);
    }
    
    svg {
        z-index: 2;
        position: relative;
        font-size: 2em;
        width: 1em;
        height: 1em;
    }
    &:before,
    &:after {
        content: '';
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        border-radius: 50%;
        opacity: 0;
    }
    &:after {
        z-index: 1;
        background: rgba(#fff, .1);
        transition: opacity .3s;
    }

    &:before {
        z-index: 2;
        border: 3px solid rgba(#fff, .1);
        opacity: 0;
    }

    &.is-listening {
        color: rgba(#D82E2E, 1);
        &:before {
            animation: pulseAway 1s infinite;
        }
        &:after {
            opacity: 1;
            animation: pulse 1.5s linear infinite;
        }
    }

    .voice-tooltip {
        position: absolute;
        top: 110%;
        left: 25px;
        padding: .4em .6em;
        color: rgba(#fff, .8);
        
        font-size: .8em;
        font-weight: 300;
        text-transform: uppercase;
        white-space: nowrap;

        background: rgba(#fff, .1);
        border-radius: 3px;

        &:before {
            content: '';
            position: absolute;
            bottom: 100%;
            left: 5px;
            width: 0;
            height: 0;
            border-style: solid;
            border-width: 0 5px 5px 5px;
            border-color: transparent transparent rgba(#fff, .1) transparent;
        }
    }
}

.fade-enter-active,
.fade-leave-active {
  transition: all .15s ease;
}
.fade-enter, .fade-leave-to {
  opacity: 0;
}

.voices-menu {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;

    @media (min-width: 500px) {
        border-radius: 5px;
        overflow: hidden;
    }
    
    &__bg {
        position: absolute;
        top: -15em;
        left: -15em;
        transform-origin: 50% 50%;
        width: 20em;
        height: 20em;
        color: #222;
        transform: scale(0.2);
        transition: transform .3s;
    }

    &__button {
        position: absolute;
        top: 0;
        left: 0;
        padding: .8em .6em;
        color: rgba(#fff, .5);
        opacity: 0;
        cursor: pointer;
        transform: translate3d(1em,0,0);
        transition: opacity .3s, transform .3s, color .2s;

        &:hover {
            color: rgba(#fff, .8);
        }

        > * {
            vertical-align: middle;
            font-weight: 300;
            letter-spacing: 1px;
        }
        svg {
            width: 1.8em;
            height: 1.8em;
        }
    }

    &__close {
        position: absolute;
        top: 0;
        right: 0;
        padding: 10px 10px;
        font-size: 2em;
        font-weight: 300;
        color: rgba(#fff, .5);
        opacity: 0;
        cursor: pointer;
        transform: translate3d(1em,0,0) rotate(45deg);
        transition: opacity .3s, transform .3s, color .2s;

        svg {
            width: 1em;
            height: 1em;
        }

        &:hover {
            color: rgba(#fff, .8);
        }
    }
}
.voices-list-wrapper {
    position: absolute;
    top: 60px;
    left: 0;
    bottom: 0;
    right: 0;
    overflow-y: auto;
    opacity: 0;
}
.voices-list {
    margin: 0;
    padding: 0;

    &__item {
        display: block;
        opacity: 0;
        transform: translate(0,1em);

        &.is-selected {
            .voices-list__icon {
                opacity: 1;
                transform: translate3d(0,0,0) rotate(0);
            }
        }
    }

    &__icon {
        position: relative;
        margin-right: 20px;
        color: $green;
        opacity: 0;
        transform: translate3d(-1em,0,0) rotate(-30deg);
        transition: opacity .2s, transform .2s;

        svg {
            width: 1.2em;
            height: 1.2em;
        }
    }

    &__link {
        display: flex;
        padding: .5em 1.1em;
        font-size: 1.3em;
        font-weight: 300;
        color: rgba(#fff, .8);
        text-decoration: none;

        &:hover {
            background: rgba(#fff, .05);
        }

        span {
            display: inline-block;
            vertical-align: middle;
        }
    }

    &__content {
        line-height: 1;
        span {
            font-size: .5em;
        }
    }

    &__default {
        color: $green;
    }
}

.menu {
    z-index: 10;
    position: absolute;
    width: 100%;
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: center;

    &__button {
        z-index: 30;
        position: absolute;
        top: 0;
        right: 0;
        display: inline-block;
        padding: 1.5em 1em;
        cursor: pointer;

        &:hover {
            .menu__dot,
            .menu__dot:before,
            .menu__dot:after {
                background: rgba(#fff, .8);
            }
        }
    }
    &__dot {
        position: relative;
        border-radius: 50%;
        width: 6px;
        height: 6px;
        background: rgba(#fff, .5);
        transition: background .2s;
        
        &:before,
        &:after {
            position: absolute;
            content: '';
            border-radius: 50%;
            width: 6px;
            height: 6px;
            background: rgba(#fff, .5);
            transition: background .2s;
        }
        &:before {
            top: 10px;
        }
        &:after {
            bottom: 10px;
        }
    }

    &__list {
        list-style: none;
        padding: 0;
        margin: 0;
        width: 100%;
    }

    &__item {
        overflow: hidden;
        opacity: 0;
        transform: translate3d(0,100%,0);
        transition: .4s transform, .4s opacity;

        a {
            font-size: 1.8em;
            font-weight: 300;
            display: block;
            color: rgba(#fff, .5);
            text-transform: uppercase;
            text-decoration: none;
            padding: .5em 1.5em;

            span {
                display: inline-block;
                vertical-align: middle;
                transition: transform .3s;
            }

            &:hover,
            &:focus {
                svg {
                    transform: scale(1.2);
                }

                .water-glass__water {
                    fill: $blue-light;
                    transform: scale(1,.8);
                }
                .coffee-cup__coffee {
                    fill: #BF9E87;
                    transform: scale(1,.8);
                }
                .beer-glass__beer {
                    fill: #E18E02;
                    transform: scale(1,.8);
                }
                .clock__short {
                    fill: #02C39A;
                    transform-origin: 0% 50%;
                    transform: rotate(20deg);
                    transition: transform 1s, color .2s;
                }
                .clock__long {
                    fill: #02C39A;
                    transition: transform 1s, color .2s;
                    transform-origin: 50% 95%;
                    transform: rotate(360deg);
                }
            }
        }

        svg {
            display: inline-block;
            vertical-align: middle;
            width: 1em;
            height: 1em;
            margin-right: 1em;
            transition: transform .3s;

            path {
                fill: #fff;
                transition: all .3s;
                transform-origin: 100% 100%;
            }
        }

    }
}

.browser-support {
    color: #fff;
    font-size: .8rem;
    text-align: center;
    padding: .5rem;
}

.content {
    z-index: 20;
    position: absolute;
    bottom: 0;
    left: 0;
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
}

.time {
    overflow: hidden;
    padding: 1em;    
    font-size: 1.1em;
    text-align: center;
    transition: .5s .2s opacity, .5s transform .2s;
}

.timer__item {
  transition: all 1s;
  margin-right: 10px;
  color: rgba(#fff, .8);

  &:first-child,
  &:nth-child(3) {
      color: rgba(#fff,.2);
  }
}
.timer-enter, .timer-leave-to {
  opacity: 0;
  transform: translate3d(0,-100%,0);
}
.timer-leave-to {
    transition-duration: .5s;
}
.timer-leave-active {
    transform: translate3d(0,0,0);
}

.percent {
    z-index: 2;
    position: relative;
    font-size: 7em;
    font-weight: 100;
    color: rgba(#fff, 0.7);
    transition: .4s .2s opacity, .4s .2s transform;

    > div {
        display: inline-block;
    }
    > span {
        margin-left: -.4em;
        font-size: .5em;
    }
}
.percent-left-enter-active, .percent-left-leave-active {
  transition: transform .1s ease;
}
.percent-left-enter, .percent-left-leave-to {
  transform: scale(1.05);
}

button {
    z-index: 20;
    position: absolute;
    display: block;
    width: 70%;
    margin: auto;
    left: 0;
    right: 0;
    bottom: 1.5em;
    padding: .6em;

    color: rgba(#fff, 0.8);
    font-size: 1.1em;
    font-weight: 300;
    letter-spacing: 1px;    
    text-transform: uppercase;

    background: transparent;
    border: 1px solid rgba(#fff, 0.8);
    border-radius: 2em;
    outline: none;
    transition: .2s background, .4s .3s transform, .4s .3s opacity;
    cursor: pointer;

    &:hover {
        background: #fff;
        color: currentColor;
    }
}
.waves {
    position: absolute;
    bottom: 0;
    left: 0;
    width: 100%;
    height: 100%;
    overflow: hidden;

    transition: .4s transform ease;
    transform-origin: bottom center;

    @media (min-width: 500px) {
        border-radius: 5px;
    }
}
.wave {
    position: absolute;
    bottom: 0;
    left: 0;
    width: 100%;
    height: 100%;
    animation: wave 1s linear infinite;

    &--front {
        z-index: 2;
        color: $blue-light;
    }

    &--back {
        z-index: 1;
        color: $blue;
        animation-direction: reverse;
    }
}

.water {
    position: absolute;
    bottom: 0;
    left: 0;
    width: 100%;
    height: 80%;
    background: currentColor;

    svg {
        position: absolute;
        width: 100%;
        left: 0;
        right: 0;
        bottom: 99.9%;
    }
}
.water:first-of-type {
    transform: translate(-100%,0);
}

svg {
    fill: currentColor;
}

@keyframes wave{
    0% {
        transform: translate3d(0,0,0);
    }
    50% {
        transform: translate3d(50%,.5em,0);
    }
    100% {
        transform: translate3d(100%,0,0);
    }
}

@keyframes pulse{
    0% {
        transform: scale(1);
    }
    50% {
        transform: scale(1.1);
    }
    100% {
        transform: scale(1);
    }
}

@keyframes pulseAway {
    0% {
        opacity: 0;
        transform: scale(.5);
    }
    50% {
        opacity: 1;
    }
    100% {
        transform: scale(1.4);
    }
}
              
            
!

JS

              
                var SpeechRecognition = SpeechRecognition || window.webkitSpeechRecognition || undefined;
var numbers = Array.apply(null, Array(101)).map(function (_, i) {return i;});

if(SpeechRecognition) {
  var SpeechGrammarList = SpeechGrammarList || window.webkitSpeechGrammarList || undefined;
  var SpeechRecognitionEvent = SpeechRecognitionEvent || window.webkitSpeechRecognitionEvent || undefined;
  
  var commands = ['reset', 'timer', ...numbers];
  var grammar = '#JSGF V1.0; grammar colors; public <color> = ' + commands.join(' | ') + ' ;'

  var speechRecognitionList = new SpeechGrammarList();
      speechRecognitionList.addFromString(grammar, 1);
      
  var recognition = new SpeechRecognition();
      recognition.grammars = speechRecognitionList;
      //recognition.continuous = false;
      recognition.lang = 'en-US';
      recognition.interimResults = true;
      recognition.maxAlternatives = 1;
}

var speechSynth = new SpeechSynthesisUtterance();

const padDigits = (number, digits) => {
    return Array(Math.max(digits - String(number).length + 1, 0)).join(0) + number;
}

const calculatePercentsLeft = (value, from) => {
    return Math.floor(Math.ceil(value/1000) / (from * 60) * 100)
}

const calculateScaleFactor = (percent) => {
    return 1-(100-percent)/100;
}

function guid() {
  function s4() {
    return Math.floor((1 + Math.random()) * 0x10000)
      .toString(16)
      .substring(1);
  }
  return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
    s4() + '-' + s4() + s4() + s4();
}

const settings = {
  water: {
    warningMsg: 'Remember to drink',
    timeIsUpMsg: 'Time\'s up. You really need to drink now',
    buttonTxt: 'Drink',
    waveFrontColor: '#32BAFA',
    waveBackColor: '#2C7FBE',
    stageBg: '#1E384C',
    durationInMinutes: 1
  },
  coffee: {
    warningMsg: `It's almost coffee time.`,
    timeIsUpMsg: 'Time\'s up. Let\'s take a coffee break!',
    buttonTxt: 'Drink coffee',
    waveFrontColor: '#b39374',
    waveBackColor: '#7a6057',
    stageBg: '#392a2c',
    durationInMinutes: 1
  },
  break: {
    warningMsg: 'It is time to rest your eyes soon!',
    timeIsUpMsg: 'Time\'s up. Now, it\'s really time to rest your eyes!',
    buttonTxt: 'Take a break',
    waveFrontColor: '#02C39A',
    waveBackColor: '#028090',
    stageBg: '#012F35',
    durationInMinutes: 1
  },
  beer: {
    warningMsg: `I know this sounds scary, but it's almost time for another beer`,
    timeIsUpMsg: `It's been a while since the last beer!`,
    buttonTxt: 'Have a beer',
    waveFrontColor: '#F1B10F',
    waveBackColor: '#FFFFFF',
    stageBg: '#5A3900',
    durationInMinutes: 60
  }
};

new Vue({
  el: '#stage',
  data() {
    return {
        color: '',
        percents: [100],
        percentsLeft: 100,
        secondsLeft: 0,
        waveStyles: '',
        duration: 1,
        timer: [],
        voicesOpen: false,
        voices: [],
        selectedVoice: {},
        countdownObj: {},
        activeReminder: settings.water,
        menuOpen: false,
        isListening: false,
        tooltipText: 'Say eg. "reset"',
        stageBg: settings.water.stageBg
    }
  },
  mounted() {
    this.resetTimer();
    this.voices = speechSynthesis.getVoices();

    if(this.voices.length === 0) {
      speechSynthesis.onvoiceschanged = () => {
        this.voices = speechSynthesis.getVoices();
      };
    }
  },
  computed: {
    supportSpeechSynth() {
      return 'speechSynthesis' in window; 
    },
    supportSpeechRecognition() {
      return SpeechRecognition;
    }
  },
  watch: {
    percentsLeft: function(val, oldVal) {
      if (val === oldVal) {
        return;
      }
      this.percents.splice(0, 1);
      this.percents.push(val);
    }
  },
  methods: {
    setActiveReminder(reminder) {
      this.activeReminder = settings[reminder];
      this.stageBg = this.activeReminder.stageBg;
    },
    toggleMenu() {
      this.menuOpen = !this.menuOpen;
      if(this.menuOpen) {
        this.pauseTimer();
        this.waveStyles = `transform: translate3d(0,100%,0); transition-delay: .25s;`;
      }else {
        this.continueTimer();
      }
    },
    toggleVoicesMenu() {
      this.voicesOpen = !this.voicesOpen;
    },
    voiceSelected(voice) {
      this.selectedVoice = voice;
      speechSynth.voice = voice;
    },
    start(reminder) {
      this.setActiveReminder(reminder);
      this.percents = [100];
      this.timer = [];
      this.menuOpen = false;
      this.resetTimer();
    },
    resetTimer() {
      let durationInSeconds = 60 * this.activeReminder.durationInMinutes;
      this.startTimer(durationInSeconds);
    },
    startTimer(secondsLeft) {
      let now = new Date();

      // later on, this timer may be stopped
      if(this.countdown) {
        window.clearInterval(this.countdown);
      }
      
      this.countdown = countdown(ts => {
        this.secondsLeft= Math.ceil(ts.value/1000);
        this.percentsLeft = calculatePercentsLeft(ts.value,this.activeReminder.durationInMinutes);
        this.waveStyles = `transform: scale(1,${calculateScaleFactor(this.percentsLeft)})`;
        this.updateCountdown(ts);
        if(this.percentsLeft == 10) {
          this.giveWarning();
        }
        if(this.percentsLeft <= 0){
          this.timeIsUpMessage();
          this.pauseTimer();
          this.timer = [];
          setTimeout(() => {
            this.startListenVoiceCommands();
          }, 1500);
          
        }
      }, now.getTime() + (secondsLeft * 1000));
    },
    updateCountdown(ts) {
      if(this.timer.length > 2) {
        this.timer.splice(2);
      }

      const newTime = {
        id: guid(),
        value: `${padDigits(ts.minutes, 2)}:${padDigits(ts.seconds, 2)}`
      };

      this.timer.unshift(newTime);
    },
    pauseTimer() {
      window.clearInterval(this.countdown);
    },
    continueTimer() {
      if(this.secondsLeft > 0) {
        this.startTimer(this.secondsLeft-1);
      }
    },
    giveWarning() {
      speechSynth.text = this.activeReminder.warningMsg;
      window.speechSynthesis.speak(speechSynth);
    },
    timeIsUpMessage() {
      speechSynth.text = this.activeReminder.timeIsUpMsg;
      window.speechSynthesis.speak(speechSynth);
    },
    timerResetMessage() {
      speechSynth.text = `Timer reset. Time left ${this.activeReminder.durationInMinutes} ${this.activeReminder.durationInMinutes > 1 ? 'minutes': 'minute'}`;
      window.speechSynthesis.speak(speechSynth);
    },
    reset() {
      this.resetTimer();
      this.timerResetMessage();
    },
    startListenVoiceCommands() {
      if(this.isListening || !this.supportSpeechRecognition) return;

      this.isListening = true;
      recognition.start();
      recognition.onresult = (event) => {
        let last = event.results.length - 1;
        let transcript = event.results[last][0].transcript;
        let splittedTranscript = transcript.split(' ');
        let isFinal = event.results[last].isFinal;

        this.tooltipText = transcript;

        if(transcript == "reset") {
          this.resetTimer();
          this.timerResetMessage();
        }
        if(
          splittedTranscript.length >= 3 &&
          splittedTranscript[0] == 'timer' &&
          isFinal &&
          numbers.includes(Number(splittedTranscript[1])) && 
          (splittedTranscript[2] == 'minute' || splittedTranscript[2] == 'minutes')
        ) {
          this.activeReminder.durationInMinutes = numbers[splittedTranscript[1]];
          this.resetTimer();
          this.timerResetMessage();
        }
        

      }
      recognition.onend = () => {
        this.isListening = false;
        this.tooltipText == '';
        recognition.stop();
      }
      recognition.onsoundend = () => {
        this.isListening = false;
        recognition.stop();
      }
    },
    mouseOver(type) {
      this.stageBg = settings[type].stageBg;
    },
    mouseOut() {
      this.stageBg = this.activeReminder.stageBg;
    }
  }
});

              
            
!
999px

Console