         left:   parseInt @$context.css('padding-left'), 10
         bottom: $context.innerHeight()
         right:  $context.innerWidth()
+
+    _setState: (state) ->
+      return no if state is @_state
+      @_state = state
+      @debugLog @_state
 
     # `sizeForTrigger` does a stealth render to find tip size by temporarily un-
     # hiding and making invisible. It will return saved data if possible before

    # `wakeByTrigger`. It also updates `_state` and returns a bool for success.
    # As long as the tip isn't truly visible, sleep is unneeded.
    sleepByTrigger: ($trigger) ->
      @_state = 'sleeping'
      # Don't toggle if asleep or sleeping.
      return no if @_state in ['asleep', 'sleeping']
      clearTimeout @_wakeCountdown
      @_sleepCountdown = setTimeout =>
        @onHide()
        @$tip.stop().fadeOut @ms.duration.out, =>
          @_state = 'asleep'
          @afterHide()
      , @ms.delay.out
      yes

      # Infer `doStem` and `doFollow` flags from respective `classNames` entries.
      @doStem = @classNames.stem isnt ''
      @doFollow = @classNames.follow isnt ''
      # Updated with `_setState`, `_state` toggles between: `awake`, `asleep`,
      # `waking`, `sleeping`. The use case behind these states is the tip will
      # remain visible and `awake` as long as there is a high enough frequency
      # of relevant mouse activity. This is achieved with a simple base
      # implementation around timers `_sleepCountdown` and `_wakeCountdown`.
      @_setState 'asleep'
      @_wakeCountdown = null
      @_sleepCountdown = null
      # `_$currentTrigger` helps manage trigger-related state.
