       # Infer `doStem` and `doFollow` flags from respective `classNames` entries.
       @doStem = @classNames.stem isnt ''
       @doFollow = @classNames.follow isnt ''
-      # `_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`.
-      @_state = 'asleep'
+      # 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.

      # Start the normal wakeup and update `_wakeCountdown`.
      else if event? and event.type is 'truemouseenter'
        triggerChanged = yes
        @_state = 'waking'
        @_wakeCountdown = setTimeout wake, delay
      yes


    # `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) ->
      # Don't toggle if asleep or sleeping.
      return no if @_state in ['asleep', 'sleeping']
      @_setState 'sleeping'
      clearTimeout @_wakeCountdown
      @_sleepCountdown = setTimeout =>
        @onHide()
        @$tip.stop().fadeOut @ms.duration.out, =>
          @_setState 'asleep'
          @afterHide()
      , @ms.delay.out
      yes
