diff --git a/TODO.otl b/TODO.otl
index d92e585..6462474 100755
--- a/TODO.otl
+++ b/TODO.otl
@@ -6,6 +6,15 @@
 		[_] BUG: no drag threshold on excludedElements (TouchSwipe)
 		| stalled...
 	[_] 80% general todo
+		[_] 75% bookmarks
+			[_] add next/prev bookmark actions
+			[_] bookmark indicators in page view
+			[X] #bookmark anchor
+			[X] bookmark indicators in navigator
+			[X] bookmark indicators in thumbnails
+			[X] bookmark persistence
+			[X] set bookmark from keyboard...
+			[X] set bookmark touch control
 		[_] magazine loader and data format...
 		| this is simple, just use a restyled magazine viewer...
 		[_] 0% populate an example issue
diff --git a/index.html b/index.html
index 437eb16..cc92dfc 100755
--- a/index.html
+++ b/index.html
@@ -88,6 +88,7 @@ $(document).ready(function(){
 	$('.button.cover').swipe({click: goToMagazineCover})
 	$('.button.next-article').swipe({click: nextArticle})
 	$('.button.prev-article').swipe({click: prevArticle})
+	$('.button.bookmark').swipe({click: function(){toggleBookmark()}})
 
 	loadState()
 	setupNavigator()
@@ -123,6 +124,7 @@ $(document).ready(function(){
 		
Issue Cover
 		Prev Article
 		Next Article
+		Bookmark
 	
 	
 		
@@ -197,6 +199,7 @@ $(document).ready(function(){
 						
 							Hide all layers
 						
+						
Toggle bookmark
 
 						Relative special anchors
 						These will get replaced by corresponding page numbers in the URL
diff --git a/keybindings.js b/keybindings.js
index 269475e..ed2acb8 100755
--- a/keybindings.js
+++ b/keybindings.js
@@ -74,6 +74,8 @@ var keybindings = {
 		32:		39,												//	Space
 		190:	39,												//	>
 
+		66:		toggleBookmark,									//	B
+
 		// combined navigation with actions..
 		38: function(){togglePageView()},						//	Up
 		40: function(){togglePageView()},						//	Down
diff --git a/magazine.css b/magazine.css
index 725de6b..6956876 100755
--- a/magazine.css
+++ b/magazine.css
@@ -65,6 +65,28 @@ body {
 	transition: all 0.2s ease;
 }
 
+.page .bookmark {
+	position: absolute;
+	font-size: 0px;
+	width: 50px;
+	height: 50px;
+
+	background: red;
+
+	/* XXX make this relative... */
+	margin-top: -50px;
+	margin-left: 750px;
+
+	z-index: 9999;
+	opacity: 0,5;
+
+	-webkit-transform: rotate(45deg);
+	-moz-transform: rotate(45deg);
+	-o-transform: rotate(45deg);
+	-ms-transform: rotate(45deg);
+	transform: rotate(45deg);
+}
+
 .page-view-mode .page {
 
 	/* XXX change to relative units... */
@@ -74,6 +96,9 @@ body {
 .page-view-mode .page .content {
 }
 
+.page-view-mode .page .bookmark {
+	display: none;
+}
 
 
 /************************************************** general layout ***/
diff --git a/magazine.js b/magazine.js
index ce3bd81..76b81b7 100755
--- a/magazine.js
+++ b/magazine.js
@@ -168,16 +168,20 @@ function swipeHandler(evt, phase, direction, distance, duration, fingers){
 		// prev page...
 		if(direction == 'right'){
 			// two+ fingers moves to closest article...
-			if(fingers >= 2){
+			if(fingers == 2){
 				prevArticle()
+			} else if(fingers >= 3){
+				prevBookmark()
 			} else {
 				setCurrentPage(Math.max(n-p, 0))
 			}
 		// next page...
 		} else if(direction == 'left'){
 			// two+ fingers moves to closest article...
-			if(fingers >= 2){
+			if(fingers == 2){
 				nextArticle()
+			} else if(fingers >= 3){
+				nextBookmark()
 			} else {
 				setCurrentPage(Math.min(n+p, pages.length-1))
 			}
@@ -457,6 +461,18 @@ function loadURLState(){
 		prevArticle()
 		return getPageNumber()
 
+	} else if(anchor == 'nextBookmark') {
+		nextBookmark()
+		return getPageNumber()
+
+	} else if(anchor == 'prevBookmark') {
+		prevBookmark()
+		return getPageNumber()
+
+	} else if(anchor == 'bookmark'){
+		toggleBookmark()
+		return getPageNumber()
+
 	// hide all visible layers on current page...
 	} else if(anchor == 'hideLayers') {
 		$('.current.page .shown')
@@ -514,7 +530,7 @@ function loadStorageState(){
 }
 function saveStorageState(){
 	$.jStorage.set('current_page', getPageNumber())
-	$.jStorage.set('bookmarks', getBookmarkList())
+	$.jStorage.set('bookmarks', buildBookmarkList())
 }
 
 
@@ -659,23 +675,63 @@ function makeBookmarkIndicator(n){
 			setCurrentPage(n)
 		})
 
+	return res
+}
+
+function clearBookmarkIndicators(){
+	$('.navigator .bar .bookmark').remove()
+}
+function removeBookmarkIndicator(n){
+	$('.navigator .bar .bookmark[page="'+n+'"]').remove()
+}
+
+// XXX move to actions...
+function loadBookmarks(lst){
+	clearBookmarks()
+	$(lst).each(function(i, e){toggleBookmark(e)})
+}
+function clearBookmarks(){
+	$('.magazine .page .bookmark').remove()
+	clearBookmarkIndicators()
+}
+
+function buildBookmarkList(){
+	var res = []
+	$('.magazine .page .bookmark').each(function(_, e){
+		res.push(getPageNumber($(e).parents('.page')))
+	})
+	return res
+}
+
+function toggleBookmark(n){
+	if(n == null){
+		n = getPageNumber()
+	} else if(typeof(n) != typeof(1)){
+		n = getPageNumber(n)
+	}
+	var res
+	var cur = getPageAt(n)
+
+	if(cur.children('.bookmark').length == 0){
+		var res = $('
')
+			.prependTo(cur)
+			.addClass('bookmark')
+			.click(function(){
+				toggleBookmark(n)
+			})
+
+		makeBookmarkIndicator(n)
+	} else {
+		cur.children('.bookmark').remove()
+		removeBookmarkIndicator(n)
+	}
+
 	// XXX should this be here???
 	saveState()
 
 	return res
 }
 
-function loadBookmarks(lst){
-	$(lst).each(function(i, e){makeBookmarkIndicator(e)})
-}
-function getBookmarkList(){
-	var res = []
-	$('.navigator .bar .bookmark').each(function(_, e){res.push(parseInt($(e).attr('page')))})
-	return res
-}
-function clearBookmarkIndicators(){
-	$('.navigator .bar .bookmark').remove()
-}
 
 // XXX move this to actions...
 function nextBookmark(){