<svg viewBox="0 0 200 453" width="200" height="453">
  <defs>
    <clipPath id="sign-window">
      <path fill="#39B573" d="M140,81.2c-27.6-14-52.4-14-80,0C55,73,52.5,65,47.5,56.8c35.3-18.7,69.7-18.7,105.1,0
        C147.5,65,145,73,140,81.2z" />
    </clipPath>
    <path id="sign-text-vacant-path" fill="none" d="M57.5,75c0,0,40-27,81,0" />
    <path id="sign-text-occupied-path" fill="none" d="M138.5,126.8c0,0-40.5,23-81,0" />
  </defs>
  <g>
    <circle fill="#A2AEBA" stroke="#6B7882" stroke-width="4" stroke-miterlimit="10" cx="100" cy="100" r="98" />
    <path fill="#CAD6E0" d="M186,100c0,0-19.2,10-86,10s-86-10-86-10c0-47.5,38.5-86,86-86S186,52.5,186,100z" />
    <circle fill="none" stroke="#FFFFFF" stroke-width="4" stroke-miterlimit="10" cx="100" cy="100" r="86" />
    <circle fill="#6B7882" stroke="#FFFFFF" stroke-width="4" stroke-miterlimit="10" cx="100" cy="100" r="12" />
    <path fill="#FFFFFF" d="M135.7,83.1c-24.4-11.2-46.9-11.2-71.3,0c-2,0.9-4.3-0.5-4.3-2.7V65h80v15.4
          C140,82.6,137.7,84.1,135.7,83.1z" />
    <path opacity="0.33" d="M150.8,59.9c0.6-1,1.2-2.1,1.8-3.1c-35.4-18.7-69.7-18.7-105.1,0c0.6,1,1.2,2.1,1.8,3.1
          C83.4,42.4,116.6,42.4,150.8,59.9z" />
    <g clip-path="url(#sign-window)">
      <g class="js-vacancy">
        <rect fill="#39B573" width="200" height="100" />
        <rect y="100" fill="#C6386E" width="200" height="100" />
        <text>
          <textPath xlink:href="#sign-text-vacant-path" startOffset="15%">
            <tspan fill="#FFFFFF" font-family="'Source Sans Pro'" font-weight="600" font-size="18px">VACANT</tspan>
          </textPath>
        </text>
        <text>
          <textPath xlink:href="#sign-text-occupied-path" startOffset="0">
            <tspan fill="#FFFFFF" font-family="'Source Sans Pro'" font-weight="600" font-size="18px">OCCUPIED</tspan>
          </textPath>
        </text>
      </g>
    </g>
  </g>
  <g class="js-lock">
    <path fill="#86919B" d="M2,350h196c0,54.1-43.9,98-98,98S2,404.1,2,350z" />
    <path fill="#CAD6E0" d="M198,350c0,0,3,10-98,10S2,350,2,350c0-54.1,43.9-98,98-98S198,295.9,198,350z" />
    <circle fill="#A2AEBA" cx="100" cy="350" r="86" />
    <circle fill="none" stroke="#6B7882" stroke-width="4" stroke-miterlimit="10" cx="100" cy="350" r="98" />
    <path class="js-latch-shadow" opacity="0.2" d="M56.9,304.7l17.2,8.6c3.1,1.6,6,3.6,8.4,6.1l49.1,49.1c2.5,2.5,4.5,5.3,6.1,8.4l8.6,17.2
          c1.9,3.8,1.2,8.4-1.9,11.5l-4,4c-3,3-7.6,3.8-11.5,1.9l-17.2-8.6c-3.1-1.6-6-3.6-8.4-6.1l-49.1-49.1c-2.5-2.5-4.5-5.3-6.1-8.4
          l-8.6-17.2c-1.9-3.8-1.2-8.4,1.9-11.5l4-4C48.4,303.6,53,302.8,56.9,304.7z" />
    <path class="js-latch" fill="#B8C3CC" stroke="#6B7882" stroke-width="4" stroke-miterlimit="10" d="M63.4,297.2l17.2,8.6
          c3.1,1.6,6,3.6,8.4,6.1l49.1,49.1c2.5,2.5,4.5,5.3,6.1,8.4l8.6,17.2c1.9,3.8,1.2,8.4-1.9,11.5l-4,4c-3,3-7.6,3.8-11.5,1.9
          l-17.2-8.6c-3.1-1.6-6-3.6-8.4-6.1l-49.1-49.1c-2.5-2.5-4.5-5.3-6.1-8.4l-8.6-17.2c-1.9-3.8-1.2-8.4,1.9-11.5l4-4
          C55,296,59.6,295.3,63.4,297.2z" />
  </g>
</svg>
/* Demo boilerplate stuff */

html {
  height: 100%;
}

body {
  min-height: 100%;
  margin: 0;
  
  display: flex;
  align-items: center;
  justify-content: center;
}

svg {
  max-height: 95vh;
}
// Select the elements we'll be using
var vacancy = document.querySelector('.js-vacancy');
var latch = document.querySelector('.js-latch');
var latchShadow = document.querySelector('.js-latch-shadow');
var lock = document.querySelector('.js-lock');

// Store common stuff to avoid repetition
var duration = 0.75;
TweenLite.defaultEase = Back.easeInOut;

// Create animation timeline
var timeline = new TimelineMax({
  paused: true,  // Wait to play
  reversed: true // Start reversed to simplify toggle
});

// Add tweens to the timeline (all occur simultaneously)
timeline.add([
  TweenMax.to(vacancy, duration, {
    rotation: 180,
    transformOrigin: '50% 50%'
  }),
  TweenMax.to(latch, duration, {
    rotation: 90,
    transformOrigin: '50% 50%'
  }),
  TweenMax.to(latchShadow, duration, {
    rotation: 90,
    transformOrigin: '50% 50%',
    x: +12
  })
]);

// Toggle on click
lock.addEventListener('click', function(){
  if (timeline.reversed()) {
    timeline.play();
  } else {
    timeline.reverse();
  }
});

External CSS

  1. https://fonts.googleapis.com/css?family=Source+Sans+Pro:600

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/gsap/latest/TweenMax.min.js