@toneflix/flipbook 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @toneflix/flipbook
2
2
 
3
- A photo book for any web page, no framework needed. Pages peel, fold and fall with real physics, photos are printed into textured paper, and phones read the book sideways.
3
+ Turn any set of photos into an album that bends, settles and feels like paper, on any web page, with no framework or from a single script tag. A page folds exactly where a finger bends it, photos sink into the paper's grain, and phones open the book sideways across two pages.
4
4
 
5
5
  ```bash
6
6
  npm install @toneflix/flipbook
@@ -1,8 +1,8 @@
1
- var Flipbook=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});let t=(e,t)=>({x:e.x-t.x,y:e.y-t.y}),n=(e,t)=>e.x*t.x+e.y*t.y,r=e=>Math.hypot(e.x,e.y);var i=class e{a;b;c;d;e;f;constructor(e=1,t=0,n=0,r=1,i=0,a=0){this.a=e,this.b=t,this.c=n,this.d=r,this.e=i,this.f=a}static translate(t,n){return new e(1,0,0,1,t,n)}static rotate(t){let n=Math.cos(t),r=Math.sin(t);return new e(n,r,-r,n,0,0)}static scale(t,n=t){return new e(t,0,0,n,0,0)}static reflect(t,r){let{x:i,y:a}=r,o=2*n(t,r);return new e(1-2*i*i,-2*i*a,-2*i*a,1-2*a*a,o*i,o*a)}after(t){let{a:n,b:r,c:i,d:a,e:o,f:s}=this;return new e(n*t.a+i*t.b,r*t.a+a*t.b,n*t.c+i*t.d,r*t.c+a*t.d,n*t.e+i*t.f+o,r*t.e+a*t.f+s)}invert(){let{a:t,b:n,c:r,d:i,e:a,f:o}=this,s=t*i-n*r;return new e(i/s,-n/s,-r/s,t/s,(r*o-i*a)/s,(n*a-t*o)/s)}apply(e){return{x:this.a*e.x+this.c*e.y+this.e,y:this.b*e.x+this.d*e.y+this.f}}toCss(){return`matrix(${this.a}, ${this.b}, ${this.c}, ${this.d}, ${this.e}, ${this.f})`}place(e,t){let n=this.apply({x:e/2,y:t/2}),r=this.a*this.d-this.b*this.c<0,i=r?Math.atan2(-this.b,-this.a):Math.atan2(this.b,this.a);return{left:n.x-e/2,top:n.y-t/2,width:e,height:t,angle:i,mirror:r}}},a=class e{width;height;origin;point;center;normal;progress;flat;folded;constructor(n,i,a,o){this.width=n,this.height=i,this.origin=a,this.point=e.attach(o,a,i);let s=t(a,this.point),c=r(s),l=[{x:0,y:0},{x:n,y:0},{x:n,y:i},{x:0,y:i}];this.center={x:(a.x+this.point.x)/2,y:(a.y+this.point.y)/2},this.progress=Math.min(1,c/Math.max(1,2*a.x)),c<.5?(this.normal={x:1,y:0},this.flat=l,this.folded=[]):(this.normal={x:s.x/c,y:s.y/c},this.flat=this.clip(l,-1),this.folded=this.clip(l,1))}static attach(e,n,i){let a=[{x:0,y:0},{x:0,y:i}],o=e;for(let e=0;e<3;e++)for(let e of a){let i=r(t(n,e)),a=t(o,e),s=r(a);s>i&&(o={x:e.x+a.x*i/s,y:e.y+a.y*i/s})}return o}static hinge(e,t,n){let r=Math.max(-1,Math.min(1,n*t.x/Math.max(1,e.x)));return-Math.acos(r)*180/Math.PI}get shade(){return Math.min(1,this.progress*8)*Math.min(1,(1-this.progress)*6)}reflect(e){let r=2*n(t(e,this.center),this.normal);return{x:e.x-r*this.normal.x,y:e.y-r*this.normal.y}}get reflection(){return i.reflect(this.center,this.normal)}get flap(){return this.folded.map(e=>this.reflect(e))}flapMatrix(e){let{x:t,y:n}=this.normal,r=e===1?-1:1,i=e*(1-2*t*t)*r,a=-2*t*n*r,o=-2*e*t*n,s=1-2*n*n,c=this.reflect({x:e===1?this.width:0,y:0});return`matrix(${i}, ${a}, ${o}, ${s}, ${e*c.x}, ${c.y})`}clip(e,r){let i=[],a=e=>r*n(t(e,this.center),this.normal)>=0;return e.forEach((o,s)=>{let c=e[(s+e.length-1)%e.length],l=r*n(t(c,this.center),this.normal),u=r*n(t(o,this.center),this.normal);if(a(o)!==a(c)){let e=l/(l-u);i.push({x:c.x+(o.x-c.x)*e,y:c.y+(o.y-c.y)*e})}a(o)&&i.push(o)}),i}};let o={fall:.0075,auto:.0055,peek:.02,flick:170,lift:.12},s={now:()=>performance.now(),request:e=>requestAnimationFrame(e),cancel:e=>cancelAnimationFrame(e)},c=()=>typeof matchMedia==`function`&&matchMedia(`(prefers-reduced-motion: reduce)`).matches;var l=class{listener;physics;mode=`idle`;origin={x:0,y:0};point={x:0,y:0};stiff=!1;size={width:1,height:1};position={x:0,y:0};velocity={x:0,y:0};target={x:0,y:0};omega=o.fall;lift=0;turned=!1;trail=[];handle=0;last=0;scheduler;reducedMotion;constructor(e,t={}){this.listener=e,this.physics={...o,...t.physics},this.scheduler=t.scheduler??s,this.reducedMotion=t.reducedMotion??c}get active(){return this.mode!==`idle`}get dragging(){return this.mode===`drag`}get peeking(){return this.mode===`peek`}get frame(){return{origin:this.origin,point:this.point,stiff:this.stiff}}grab(e,t,n,r){this.size=n,this.origin=e,this.stiff=r,this.mode=`drag`,this.trail=[],this.stop(),this.moveTo(t)}drag(e){this.mode===`drag`&&this.moveTo(e)}release(){if(this.mode!==`drag`)return!1;let e=this.speed(),t=this.point.x+e.x*this.physics.flick;return this.fall(t<0,e,this.physics.fall),this.turned}turn(e,t,n){this.size=t,this.origin=e,this.stiff=n,this.point={...e},this.fall(!0,{x:0,y:0},this.physics.auto)}peek(e,t,n,r){this.mode!==`drag`&&this.mode!==`fall`&&((this.mode===`idle`||this.origin.x!==e.x||this.origin.y!==e.y)&&(this.size=n,this.origin=e,this.stiff=r,this.point={...e},this.position={...this.point},this.velocity={x:0,y:0},this.lift=0),this.mode=`peek`,this.omega=this.physics.peek,this.target=t,this.turned=t.x<0,this.run())}unpeek(){this.mode===`peek`&&(this.mode=`fall`,this.target=this.turned?{x:-this.origin.x,y:this.origin.y}:{...this.origin},this.run())}finish(){if(this.mode===`idle`)return;let e=this.mode===`fall`?this.turned:this.point.x<0;this.stop(),this.mode=`idle`,this.listener.settle(e)}cancel(){this.stop(),this.mode=`idle`}moveTo(e){let t=this.stiff?{x:Math.max(-this.origin.x,Math.min(this.origin.x,e.x)),y:this.origin.y}:a.attach(e,this.origin,this.size.height),n=this.scheduler.now();this.point=t,this.trail.push({p:t,t:n}),this.trail=this.trail.filter(e=>n-e.t<100),this.listener.frame(this.frame)}speed(){if(this.trail.length<2)return{x:0,y:0};let e=this.trail[0],t=this.trail[this.trail.length-1],n=Math.max(1,t.t-e.t);return{x:(t.p.x-e.p.x)/n,y:(t.p.y-e.p.y)/n}}fall(e,t,n){this.reducedMotion()?(this.stop(),this.mode=`idle`,this.listener.settle(e)):(this.mode=`fall`,this.turned=e,this.omega=n,this.target=e?{x:-this.origin.x,y:this.origin.y}:{...this.origin},this.lift=this.stiff?0:this.size.height*this.physics.lift*(this.origin.y>this.size.height/2?-1:1),this.position={x:this.point.x,y:this.point.y-this.arc(this.point.x)},this.velocity=t,this.run())}arc(e){let t=Math.max(1,this.origin.x),n=Math.min(1,Math.abs(e)/t);return this.lift*(1-n*n)}run(){this.handle||=(this.last=this.scheduler.now(),this.scheduler.request(this.tick))}stop(){this.handle&&this.scheduler.cancel(this.handle),this.handle=0}tick=e=>{let n=Math.min(48,e-this.last),i=this.omega;this.last=e;for(let e=0;e<n;e+=4){let t=Math.min(4,n-e);for(let e of[`x`,`y`]){let n=i*i*(this.target[e]-this.position[e])-2*i*this.velocity[e];this.velocity[e]+=n*t,this.position[e]+=this.velocity[e]*t}}let o={x:this.position.x,y:this.position.y+(this.mode===`fall`?this.arc(this.position.x):0)};this.point=this.stiff?{x:o.x,y:this.origin.y}:a.attach(o,this.origin,this.size.height),this.listener.frame(this.frame);let s=r(t(this.target,this.position))<.5&&r(this.velocity)<.02;s&&this.mode===`fall`?(this.handle=0,this.mode=`idle`,this.listener.settle(this.turned)):this.handle=s?0:this.scheduler.request(this.tick)}};let u={single:{label:`Full bleed`,slots:1},framed:{label:`Framed`,slots:1},pair:{label:`Pair`,slots:2},grid:{label:`Grid`,slots:4},collage:{label:`Collage`,slots:3},text:{label:`Words`,slots:0}},d={classic:{label:`Classic`,cloth:`#5a1d22`,ink:`#e2c58f`,stage:[`#4a2a27`,`#22140f`,`#0d0807`]},linen:{label:`Linen`,cloth:`#e6dcc6`,ink:`#3d3226`,stage:[`#4a4134`,`#241f18`,`#0e0c09`]},midnight:{label:`Midnight`,cloth:`#141b2e`,ink:`#d5dbe8`,stage:[`#27324d`,`#121827`,`#07090f`]}},f={ivory:{label:`Ivory`,swatch:`#fbf8f1`},white:{label:`White`,swatch:`#ffffff`},kraft:{label:`Kraft`,swatch:`#d8c4a2`},charcoal:{label:`Charcoal`,swatch:`#2a2826`}},p={none:{label:`Plain`,description:`The photo printed straight onto the page`},hairline:{label:`Hairline`,description:`A fine printed rule around the photo`},double:{label:`Double rule`,description:`Two printed rules, like a classic album keyline`},mat:{label:`Gallery mat`,description:`A wide printed mat with a thin frame line`},corners:{label:`Photo corners`,description:`Printed album corners holding the photo`},deckle:{label:`Deckled edge`,description:`A vintage print with a scalloped border`},plate:{label:`Plate mark`,description:`The photo sits in a plate pressed into the paper`},feather:{label:`Soft edge`,description:`The photo fades into the paper at its edges`},oval:{label:`Oval`,description:`An oval cameo inside a fine printed ring`},botanical:{label:`Botanical`,description:`Line-drawn sprigs of leaves around a fine rule`},watercolor:{label:`Watercolour`,description:`A wash of soft colour printed around a mat`},arcs:{label:`Rainbow arcs`,description:`A printed border of little rainbow arcs around a mat`},gilt:{label:`Gilt`,description:`An engraved border printed in gold ink`},woodgrain:{label:`Woodgrain`,description:`A printed woodgrain border around a mat`}},m={watercolor:3,arcs:3,gilt:2.6,woodgrain:3};function h(e,t=`none`){return e.layout===`single`?`none`:e.frame??t}var g=class e{pageCount;faces;leaves;spread;stiffCovers;constructor(t,{spread:n,stiffCovers:r=!0}){this.pageCount=t;let i=Array.from({length:t},(e,t)=>({kind:`page`,index:t})),a=n&&t%2==1?[{kind:`blank`}]:[];this.spread=n,this.stiffCovers=r,this.faces=[{kind:`cover`},{kind:`title`},...i,...a,{kind:`colophon`},{kind:`back`}],this.leaves=n?e.pair(this.faces):this.faces.map(e=>({front:e,back:{kind:`blank`}}))}static pair(e){let t=[];for(let n=0;n<e.length;n+=2)t.push({front:e[n],back:e[n+1]});return t}get length(){return this.leaves.length}flippedForFace(e){return this.spread?Math.ceil(e/2):e}flippedForPage(e){return!e||e<1||e>this.pageCount?0:this.flippedForFace(e+1)}convert(e,t){return t.spread===this.spread?Math.min(e,this.length):this.spread?Math.ceil(e/2):Math.max(0,e*2-1)}isStiff(e){let{front:t,back:n}=this.leaves[e]??{};return this.stiffCovers&&(t?.kind===`cover`||t?.kind===`back`||n?.kind===`back`)}visible(e){return e<=0?[this.leaves[0].front]:e>=this.length?[this.spread?this.leaves[this.length-1].back:this.faces[this.faces.length-1]]:this.spread?[this.leaves[e-1].back,this.leaves[e].front]:[this.leaves[e].front]}stops(){if(!this.spread)return this.faces.map((e,t)=>({flipped:t,faces:[e]}));let e=[{flipped:0,faces:[this.faces[0]]}];for(let t=1;t<this.faces.length-1;t+=2)e.push({flipped:this.flippedForFace(t),faces:[this.faces[t],this.faces[t+1]]});return e.push({flipped:this.length,faces:[this.faces[this.faces.length-1]]}),e}label(t){if(t<=0)return`Cover`;if(t>=this.length)return`Back cover`;let n=e.pageNumbers(this.visible(t));return n.length===0?this.visible(t).some(e=>e.kind===`title`)?`Title page`:`The end`:n.length===1?`Page ${n[0]} of ${this.pageCount}`:`Pages ${n[0]}–${n[1]} of ${this.pageCount}`}static describe(t){let n=e.pageNumbers(t);return n.length?`page ${n.join(` and `)}`:t[0].kind===`back`?`the back cover`:t[0].kind===`cover`?`the cover`:`the title page`}static pageNumbers(e){return e.filter(e=>e.kind===`page`).map(e=>e.index+1)}};let _={edgeX:.15,edgeY:.08,peek:!0};var v=class{events;flipped;active=null;layout;width=0;height=0;grip;engine;press=null;grabStart={x:0,y:0};grabDir=1;grabReach=1;constructor(e,t,n={}){this.events=t,this.layout=e,this.flipped=Math.max(0,Math.min(e.length,n.flipped??0)),this.grip={..._,...n.grip},this.engine=new l({frame:e=>this.active&&this.events.frame(e,this.active),settle:e=>this.settle(e)},n)}get size(){return{width:this.width,height:this.height}}get atStart(){return this.flipped===0}get atEnd(){return this.flipped===this.layout.length}get settled(){return!this.active||this.active.peek}get label(){return this.layout.label(this.flipped)}configure({layout:e,width:t,height:n}){let r=e&&e!==this.layout,i=t!==void 0&&t!==this.width||n!==void 0&&n!==this.height;(r||i)&&(e&&r&&(this.flipped=e.convert(this.flipped,this.layout),this.layout=e),this.width=t??this.width,this.height=n??this.height,this.engine.cancel(),this.active=null,this.press=null,this.events.change())}go(e){let t=Math.max(0,Math.min(this.layout.length,e));if(t===this.flipped||this.width===0)return;if(this.engine.active&&!this.engine.peeking){this.engine.finish();return}if(this.engine.cancel(),this.events.flip(),Math.abs(t-this.flipped)!==1){this.active=null,this.flipped=t,this.events.change();return}let n=Math.min(t,this.flipped),r=this.layout.isStiff(n);this.begin({leaf:n,dir:t>this.flipped?1:-1,stiff:r,peek:!1}),this.engine.turn({x:this.width,y:r?this.height/2:this.height},this.size,r)}next(){this.go(this.flipped+1)}prev(){this.go(this.flipped-1)}hover(e){if(this.press||this.engine.dragging)return;let t=this.grip.peek?this.cornerAt(e):null;if(!t){this.engine.unpeek();return}let{width:n,height:r}=this,i=t.x>0?1:-1,a=i===1?this.flipped:this.flipped-1,o=this.layout.isStiff(a),s={x:n,y:o?r/2:t.y},c={x:i*(e.x-t.x),y:e.y-t.y},l=Math.hypot(c.x,c.y)||1,u=Math.max(n*.12,Math.min(n*.2,l*2)),d={x:n+c.x/l*u,y:o?s.y:t.y+c.y/l*u};(this.active?.leaf!==a||this.active.dir!==i)&&this.begin({leaf:a,dir:i,stiff:o,peek:!0}),this.engine.peek(s,d,this.size,o)}leave(){this.engine.unpeek()}down(e,t){this.press={at:e,id:t,grabbed:!1}}move(e,t){let n=this.press;if(!n||n.id!==t)return!1;let r=e.x-n.at.x,i=e.y-n.at.y;if(!n.grabbed){if(Math.hypot(r,i)<6||this.engine.active&&!this.engine.peeking)return!1;let e=(this.engine.peeking&&this.active?{...this.active,origin:this.engine.frame.origin,start:this.engine.frame.point}:null)??this.holdAt(n.at);if(!e)return!1;n.grabbed=!0,this.grabStart=e.start,this.grabDir=e.dir,this.grabReach=!this.layout.spread&&e.dir===-1?2:1,this.begin({leaf:e.leaf,dir:e.dir,stiff:e.stiff,peek:!1}),this.engine.grab(e.origin,e.start,this.size,e.stiff)}return this.engine.drag({x:this.grabStart.x+this.grabDir*this.grabReach*r,y:this.grabStart.y+i}),!0}up(e,t){let n=this.press;return!n||n.id!==t?null:(this.press=null,n.grabbed?(this.engine.release()&&this.events.flip(),`turn`):Math.abs(e.x-n.at.x)<8&&Math.abs(e.y-n.at.y)<8?`tap`:null)}cancel(){this.press=null,this.engine.dragging&&this.engine.release()}destroy(){this.engine.cancel()}begin(e){this.active=e,this.events.change()}settle(e){let t=this.active;if(!t)return;let n=t.dir===1?e:!e;this.flipped=n?t.leaf+1:t.leaf,this.active=null,this.events.change()}holdAt(e){let{width:t,height:n,layout:r}=this,i=r.spread?e.x>=0:e.x>=t*.3,a=i?this.flipped:this.flipped-1;if(a<0||a>=r.length)return null;let o=i?e:{x:r.spread?-e.x:t,y:e.y},s=o.x>t*(1-this.grip.edgeX),c=o.y<n*this.grip.edgeY,l=o.y>n*(1-this.grip.edgeY),u=r.isStiff(a),d={x:s||!(c||l)?t:Math.max(1,o.x),y:u?n/2:c?0:l?n:Math.max(0,Math.min(n,o.y))};return{leaf:a,dir:i?1:-1,origin:d,stiff:u,start:d}}cornerAt(e){let{width:t,height:n,layout:r,flipped:i}=this,a=Math.max(36,t*.12);return[...i<r.length?[{x:t,y:0},{x:t,y:n}]:[],...r.spread&&i>0?[{x:-t,y:0},{x:-t,y:n}]:[]].find(t=>Math.hypot(e.x-t.x,e.y-t.y)<a)??null}};let y={previous:`Previous page`,next:`Next page`,soundOn:`Turn page sound on`,soundOff:`Turn page sound off`,fullscreen:`Full screen`,exitFullscreen:`Exit full screen`,byline:e=>`by ${e}`,rotateTitle:`Turn your phone sideways`,rotateBody:`Photo books open across two pages, just like the real thing.`,rotateFullscreen:`Open full screen`,rotateSingle:`Read one page at a time`};function b(e,t={},...n){let r=document.createElement(e);for(let[e,n]of Object.entries(t))e===`style`?Object.assign(r.style,n):n!=null&&n!==!1&&r.setAttribute(e,n===!0?``:String(n));return x(r,n),r}function x(e,t){for(let n of t)n&&e.append(n)}function S(e){let t=document.createElement(`template`);return t.innerHTML=e.trim(),t.content.firstElementChild}async function C(e){try{!document.fullscreenElement&&e.requestFullscreen&&await e.requestFullscreen({navigationUI:`hide`})}catch{}try{let e=screen.orientation;if(e?.lock)return await e.lock(`landscape`),!0}catch{}return!1}function w(e){let t=matchMedia(`(orientation: portrait)`),n=matchMedia(`(pointer: coarse)`),r=()=>e({portrait:t.matches,touch:n.matches});return r(),t.addEventListener(`change`,r),n.addEventListener(`change`,r),window.addEventListener(`resize`,r),()=>{t.removeEventListener(`change`,r),n.removeEventListener(`change`,r),window.removeEventListener(`resize`,r)}}let T=[14,24,34,44,54,64,74].map((e,t)=>({x:e,angle:t%2?38:-38,length:26-t*2})),E=e=>S(`<svg viewBox="0 0 100 40" class="fb-print-frame-sprig is-${e}" fill="none" stroke="currentColor" stroke-linecap="round" aria-hidden="true">
1
+ var Flipbook=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});let t=(e,t)=>({x:e.x-t.x,y:e.y-t.y}),n=(e,t)=>e.x*t.x+e.y*t.y,r=e=>Math.hypot(e.x,e.y);var i=class e{a;b;c;d;e;f;constructor(e=1,t=0,n=0,r=1,i=0,a=0){this.a=e,this.b=t,this.c=n,this.d=r,this.e=i,this.f=a}static translate(t,n){return new e(1,0,0,1,t,n)}static rotate(t){let n=Math.cos(t),r=Math.sin(t);return new e(n,r,-r,n,0,0)}static scale(t,n=t){return new e(t,0,0,n,0,0)}static reflect(t,r){let{x:i,y:a}=r,o=2*n(t,r);return new e(1-2*i*i,-2*i*a,-2*i*a,1-2*a*a,o*i,o*a)}after(t){let{a:n,b:r,c:i,d:a,e:o,f:s}=this;return new e(n*t.a+i*t.b,r*t.a+a*t.b,n*t.c+i*t.d,r*t.c+a*t.d,n*t.e+i*t.f+o,r*t.e+a*t.f+s)}invert(){let{a:t,b:n,c:r,d:i,e:a,f:o}=this,s=t*i-n*r;return new e(i/s,-n/s,-r/s,t/s,(r*o-i*a)/s,(n*a-t*o)/s)}apply(e){return{x:this.a*e.x+this.c*e.y+this.e,y:this.b*e.x+this.d*e.y+this.f}}toCss(){return`matrix(${this.a}, ${this.b}, ${this.c}, ${this.d}, ${this.e}, ${this.f})`}place(e,t){let n=this.apply({x:e/2,y:t/2}),r=this.a*this.d-this.b*this.c<0,i=r?Math.atan2(-this.b,-this.a):Math.atan2(this.b,this.a);return{left:n.x-e/2,top:n.y-t/2,width:e,height:t,angle:i,mirror:r}}},a=class e{width;height;origin;point;center;normal;progress;flat;folded;constructor(n,i,a,o){this.width=n,this.height=i,this.origin=a,this.point=e.attach(o,a,i);let s=t(a,this.point),c=r(s),l=[{x:0,y:0},{x:n,y:0},{x:n,y:i},{x:0,y:i}];this.center={x:(a.x+this.point.x)/2,y:(a.y+this.point.y)/2},this.progress=Math.min(1,c/Math.max(1,2*a.x)),c<.5?(this.normal={x:1,y:0},this.flat=l,this.folded=[]):(this.normal={x:s.x/c,y:s.y/c},this.flat=this.clip(l,-1),this.folded=this.clip(l,1))}static attach(e,n,i){let a=[{x:0,y:0},{x:0,y:i}],o=e;for(let e=0;e<3;e++)for(let e of a){let i=r(t(n,e)),a=t(o,e),s=r(a);s>i&&(o={x:e.x+a.x*i/s,y:e.y+a.y*i/s})}return o}static hinge(e,t,n){let r=Math.max(-1,Math.min(1,n*t.x/Math.max(1,e.x)));return-Math.acos(r)*180/Math.PI}get shade(){return Math.min(1,this.progress*8)*Math.min(1,(1-this.progress)*6)}reflect(e){let r=2*n(t(e,this.center),this.normal);return{x:e.x-r*this.normal.x,y:e.y-r*this.normal.y}}get reflection(){return i.reflect(this.center,this.normal)}get flap(){return this.folded.map(e=>this.reflect(e))}flapMatrix(e){let{x:t,y:n}=this.normal,r=e===1?-1:1,i=e*(1-2*t*t)*r,a=-2*t*n*r,o=-2*e*t*n,s=1-2*n*n,c=this.reflect({x:e===1?this.width:0,y:0});return`matrix(${i}, ${a}, ${o}, ${s}, ${e*c.x}, ${c.y})`}clip(e,r){let i=[],a=e=>r*n(t(e,this.center),this.normal)>=0;return e.forEach((o,s)=>{let c=e[(s+e.length-1)%e.length],l=r*n(t(c,this.center),this.normal),u=r*n(t(o,this.center),this.normal);if(a(o)!==a(c)){let e=l/(l-u);i.push({x:c.x+(o.x-c.x)*e,y:c.y+(o.y-c.y)*e})}a(o)&&i.push(o)}),i}};let o={fall:.0075,auto:.0055,peek:.02,flick:170,lift:.12},s={now:()=>performance.now(),request:e=>requestAnimationFrame(e),cancel:e=>cancelAnimationFrame(e)},c=()=>typeof matchMedia==`function`&&matchMedia(`(prefers-reduced-motion: reduce)`).matches;var l=class{listener;physics;mode=`idle`;origin={x:0,y:0};point={x:0,y:0};stiff=!1;size={width:1,height:1};position={x:0,y:0};velocity={x:0,y:0};target={x:0,y:0};omega=o.fall;lift=0;turned=!1;trail=[];handle=0;last=0;scheduler;reducedMotion;constructor(e,t={}){this.listener=e,this.physics={...o,...t.physics},this.scheduler=t.scheduler??s,this.reducedMotion=t.reducedMotion??c}get active(){return this.mode!==`idle`}get dragging(){return this.mode===`drag`}get peeking(){return this.mode===`peek`}get frame(){return{origin:this.origin,point:this.point,stiff:this.stiff}}grab(e,t,n,r){this.size=n,this.origin=e,this.stiff=r,this.mode=`drag`,this.trail=[],this.stop(),this.moveTo(t)}drag(e){this.mode===`drag`&&this.moveTo(e)}release(){if(this.mode!==`drag`)return!1;let e=this.speed(),t=this.point.x+e.x*this.physics.flick;return this.fall(t<0,e,this.physics.fall),this.turned}turn(e,t,n){this.size=t,this.origin=e,this.stiff=n,this.point={...e},this.fall(!0,{x:0,y:0},this.physics.auto)}peek(e,t,n,r){this.mode!==`drag`&&this.mode!==`fall`&&((this.mode===`idle`||this.origin.x!==e.x||this.origin.y!==e.y)&&(this.size=n,this.origin=e,this.stiff=r,this.point={...e},this.position={...this.point},this.velocity={x:0,y:0},this.lift=0),this.mode=`peek`,this.omega=this.physics.peek,this.target=t,this.turned=t.x<0,this.run())}unpeek(){this.mode===`peek`&&(this.mode=`fall`,this.target=this.turned?{x:-this.origin.x,y:this.origin.y}:{...this.origin},this.run())}finish(){if(this.mode===`idle`)return;let e=this.mode===`fall`?this.turned:this.point.x<0;this.stop(),this.mode=`idle`,this.listener.settle(e)}cancel(){this.stop(),this.mode=`idle`}moveTo(e){let t=this.stiff?{x:Math.max(-this.origin.x,Math.min(this.origin.x,e.x)),y:this.origin.y}:a.attach(e,this.origin,this.size.height),n=this.scheduler.now();this.point=t,this.trail.push({p:t,t:n}),this.trail=this.trail.filter(e=>n-e.t<100),this.listener.frame(this.frame)}speed(){if(this.trail.length<2)return{x:0,y:0};let e=this.trail[0],t=this.trail[this.trail.length-1],n=Math.max(1,t.t-e.t);return{x:(t.p.x-e.p.x)/n,y:(t.p.y-e.p.y)/n}}fall(e,t,n){this.reducedMotion()?(this.stop(),this.mode=`idle`,this.listener.settle(e)):(this.mode=`fall`,this.turned=e,this.omega=n,this.target=e?{x:-this.origin.x,y:this.origin.y}:{...this.origin},this.lift=this.stiff?0:this.size.height*this.physics.lift*(this.origin.y>this.size.height/2?-1:1),this.position={x:this.point.x,y:this.point.y-this.arc(this.point.x)},this.velocity=t,this.run())}arc(e){let t=Math.max(1,this.origin.x),n=Math.min(1,Math.abs(e)/t);return this.lift*(1-n*n)}run(){this.handle||=(this.last=this.scheduler.now(),this.scheduler.request(this.tick))}stop(){this.handle&&this.scheduler.cancel(this.handle),this.handle=0}tick=e=>{let n=Math.min(48,e-this.last),i=this.omega;this.last=e;for(let e=0;e<n;e+=4){let t=Math.min(4,n-e);for(let e of[`x`,`y`]){let n=i*i*(this.target[e]-this.position[e])-2*i*this.velocity[e];this.velocity[e]+=n*t,this.position[e]+=this.velocity[e]*t}}let o={x:this.position.x,y:this.position.y+(this.mode===`fall`?this.arc(this.position.x):0)};this.point=this.stiff?{x:o.x,y:this.origin.y}:a.attach(o,this.origin,this.size.height),this.listener.frame(this.frame);let s=r(t(this.target,this.position))<.5&&r(this.velocity)<.02;s&&this.mode===`fall`?(this.handle=0,this.mode=`idle`,this.listener.settle(this.turned)):this.handle=s?0:this.scheduler.request(this.tick)}};let u={single:{label:`Full bleed`,slots:1},framed:{label:`Framed`,slots:1},pair:{label:`Pair`,slots:2},grid:{label:`Grid`,slots:4},collage:{label:`Collage`,slots:3},text:{label:`Words`,slots:0},triptych:{label:`Triptych`,slots:3},mosaic:{label:`Mosaic`,slots:3},strip:{label:`Film strip`,slots:3},contact:{label:`Contact sheet`,slots:6},scatter:{label:`Loose prints`,slots:3},story:{label:`Story`,slots:1}},d=(e,t,n,r=7,i=108,a=3)=>{let o=(i-a*(n-1))/n;return Array.from({length:n},(n,i)=>({x:e,y:r+i*(o+a),width:t,height:o}))},f={x:7,y:118,width:86,height:10},p={triptych:{slots:[7,36.67,66.33].map(e=>({x:e,y:14,width:26.67,height:94})),caption:{...f,y:114}},mosaic:{slots:[{x:7,y:7,width:51,height:108},...d(61,32,2)],caption:f},strip:{slots:d(7,86,3),caption:f},contact:{slots:d(7,41.5,3).flatMap((e,t)=>[e,d(51.5,41.5,3)[t]]),caption:f},scatter:{slots:[{x:9,y:9,width:54,height:41,rotate:-4},{x:38,y:43,width:54,height:41,rotate:3},{x:11,y:80,width:48,height:35,rotate:-2}],caption:{...f,x:63,y:92,width:30,height:28},loose:!0},story:{slots:[{x:7,y:7,width:86,height:66}],caption:{x:9,y:80,width:82,height:45},prose:!0}},m={classic:{label:`Classic`,cloth:`#5a1d22`,ink:`#e2c58f`,stage:[`#4a2a27`,`#22140f`,`#0d0807`]},linen:{label:`Linen`,cloth:`#e6dcc6`,ink:`#3d3226`,stage:[`#4a4134`,`#241f18`,`#0e0c09`]},midnight:{label:`Midnight`,cloth:`#141b2e`,ink:`#d5dbe8`,stage:[`#27324d`,`#121827`,`#07090f`]}},h={ivory:{label:`Ivory`,swatch:`#fbf8f1`},white:{label:`White`,swatch:`#ffffff`},kraft:{label:`Kraft`,swatch:`#d8c4a2`},charcoal:{label:`Charcoal`,swatch:`#2a2826`}},g={none:{label:`Plain`,description:`The photo printed straight onto the page`},hairline:{label:`Hairline`,description:`A fine printed rule around the photo`},double:{label:`Double rule`,description:`Two printed rules, like a classic album keyline`},mat:{label:`Gallery mat`,description:`A wide printed mat with a thin frame line`},corners:{label:`Photo corners`,description:`Printed album corners holding the photo`},deckle:{label:`Deckled edge`,description:`A vintage print with a scalloped border`},plate:{label:`Plate mark`,description:`The photo sits in a plate pressed into the paper`},feather:{label:`Soft edge`,description:`The photo fades into the paper at its edges`},oval:{label:`Oval`,description:`An oval cameo inside a fine printed ring`},botanical:{label:`Botanical`,description:`Line-drawn sprigs of leaves around a fine rule`},watercolor:{label:`Watercolour`,description:`A wash of soft colour printed around a mat`},arcs:{label:`Rainbow arcs`,description:`A printed border of little rainbow arcs around a mat`},gilt:{label:`Gilt`,description:`An engraved border printed in gold ink`},woodgrain:{label:`Woodgrain`,description:`A printed woodgrain border around a mat`}},_={watercolor:3,arcs:3,gilt:2.6,woodgrain:3};function v(e,t,n=`none`){return e.layout===`single`?`none`:t?.frame??y(e,n)}function y(e,t=`none`){return e.layout===`single`?`none`:e.frame??t}var b=class e{pageCount;faces;leaves;spread;stiffCovers;constructor(t,{spread:n,stiffCovers:r=!0}){this.pageCount=t;let i=Array.from({length:t},(e,t)=>({kind:`page`,index:t})),a=n&&t%2==1?[{kind:`blank`}]:[];this.spread=n,this.stiffCovers=r,this.faces=[{kind:`cover`},{kind:`title`},...i,...a,{kind:`colophon`},{kind:`back`}],this.leaves=n?e.pair(this.faces):this.faces.map(e=>({front:e,back:{kind:`blank`}}))}static pair(e){let t=[];for(let n=0;n<e.length;n+=2)t.push({front:e[n],back:e[n+1]});return t}get length(){return this.leaves.length}flippedForFace(e){return this.spread?Math.ceil(e/2):e}flippedForPage(e){return!e||e<1||e>this.pageCount?0:this.flippedForFace(e+1)}convert(e,t){return t.spread===this.spread?Math.min(e,this.length):this.spread?Math.ceil(e/2):Math.max(0,e*2-1)}isStiff(e){let{front:t,back:n}=this.leaves[e]??{};return this.stiffCovers&&(t?.kind===`cover`||t?.kind===`back`||n?.kind===`back`)}visible(e){return e<=0?[this.leaves[0].front]:e>=this.length?[this.spread?this.leaves[this.length-1].back:this.faces[this.faces.length-1]]:this.spread?[this.leaves[e-1].back,this.leaves[e].front]:[this.leaves[e].front]}stops(){if(!this.spread)return this.faces.map((e,t)=>({flipped:t,faces:[e]}));let e=[{flipped:0,faces:[this.faces[0]]}];for(let t=1;t<this.faces.length-1;t+=2)e.push({flipped:this.flippedForFace(t),faces:[this.faces[t],this.faces[t+1]]});return e.push({flipped:this.length,faces:[this.faces[this.faces.length-1]]}),e}label(t){if(t<=0)return`Cover`;if(t>=this.length)return`Back cover`;let n=e.pageNumbers(this.visible(t));return n.length===0?this.visible(t).some(e=>e.kind===`title`)?`Title page`:`The end`:n.length===1?`Page ${n[0]} of ${this.pageCount}`:`Pages ${n[0]}–${n[1]} of ${this.pageCount}`}static describe(t){let n=e.pageNumbers(t);return n.length?`page ${n.join(` and `)}`:t[0].kind===`back`?`the back cover`:t[0].kind===`cover`?`the cover`:`the title page`}static pageNumbers(e){return e.filter(e=>e.kind===`page`).map(e=>e.index+1)}};let x={edgeX:.15,edgeY:.08,peek:!0};var S=class{events;flipped;active=null;layout;width=0;height=0;grip;engine;press=null;grabStart={x:0,y:0};grabDir=1;grabReach=1;constructor(e,t,n={}){this.events=t,this.layout=e,this.flipped=Math.max(0,Math.min(e.length,n.flipped??0)),this.grip={...x,...n.grip},this.engine=new l({frame:e=>this.active&&this.events.frame(e,this.active),settle:e=>this.settle(e)},n)}get size(){return{width:this.width,height:this.height}}get atStart(){return this.flipped===0}get atEnd(){return this.flipped===this.layout.length}get settled(){return!this.active||this.active.peek}get label(){return this.layout.label(this.flipped)}configure({layout:e,width:t,height:n}){let r=e&&e!==this.layout,i=t!==void 0&&t!==this.width||n!==void 0&&n!==this.height;(r||i)&&(e&&r&&(this.flipped=e.convert(this.flipped,this.layout),this.layout=e),this.width=t??this.width,this.height=n??this.height,this.engine.cancel(),this.active=null,this.press=null,this.events.change())}go(e){let t=Math.max(0,Math.min(this.layout.length,e));if(t===this.flipped||this.width===0)return;if(this.engine.active&&!this.engine.peeking){this.engine.finish();return}if(this.engine.cancel(),this.events.flip(),Math.abs(t-this.flipped)!==1){this.active=null,this.flipped=t,this.events.change();return}let n=Math.min(t,this.flipped),r=this.layout.isStiff(n);this.begin({leaf:n,dir:t>this.flipped?1:-1,stiff:r,peek:!1}),this.engine.turn({x:this.width,y:r?this.height/2:this.height},this.size,r)}next(){this.go(this.flipped+1)}prev(){this.go(this.flipped-1)}hover(e){if(this.press||this.engine.dragging)return;let t=this.grip.peek?this.cornerAt(e):null;if(!t){this.engine.unpeek();return}let{width:n,height:r}=this,i=t.x>0?1:-1,a=i===1?this.flipped:this.flipped-1,o=this.layout.isStiff(a),s={x:n,y:o?r/2:t.y},c={x:i*(e.x-t.x),y:e.y-t.y},l=Math.hypot(c.x,c.y)||1,u=Math.max(n*.12,Math.min(n*.2,l*2)),d={x:n+c.x/l*u,y:o?s.y:t.y+c.y/l*u};(this.active?.leaf!==a||this.active.dir!==i)&&this.begin({leaf:a,dir:i,stiff:o,peek:!0}),this.engine.peek(s,d,this.size,o)}leave(){this.engine.unpeek()}down(e,t){this.press={at:e,id:t,grabbed:!1}}move(e,t){let n=this.press;if(!n||n.id!==t)return!1;let r=e.x-n.at.x,i=e.y-n.at.y;if(!n.grabbed){if(Math.hypot(r,i)<6||this.engine.active&&!this.engine.peeking)return!1;let e=(this.engine.peeking&&this.active?{...this.active,origin:this.engine.frame.origin,start:this.engine.frame.point}:null)??this.holdAt(n.at);if(!e)return!1;n.grabbed=!0,this.grabStart=e.start,this.grabDir=e.dir,this.grabReach=!this.layout.spread&&e.dir===-1?2:1,this.begin({leaf:e.leaf,dir:e.dir,stiff:e.stiff,peek:!1}),this.engine.grab(e.origin,e.start,this.size,e.stiff)}return this.engine.drag({x:this.grabStart.x+this.grabDir*this.grabReach*r,y:this.grabStart.y+i}),!0}up(e,t){let n=this.press;return!n||n.id!==t?null:(this.press=null,n.grabbed?(this.engine.release()&&this.events.flip(),`turn`):Math.abs(e.x-n.at.x)<8&&Math.abs(e.y-n.at.y)<8?`tap`:null)}cancel(){this.press=null,this.engine.dragging&&this.engine.release()}destroy(){this.engine.cancel()}begin(e){this.active=e,this.events.change()}settle(e){let t=this.active;if(!t)return;let n=t.dir===1?e:!e;this.flipped=n?t.leaf+1:t.leaf,this.active=null,this.events.change()}holdAt(e){let{width:t,height:n,layout:r}=this,i=r.spread?e.x>=0:e.x>=t*.3,a=i?this.flipped:this.flipped-1;if(a<0||a>=r.length)return null;let o=i?e:{x:r.spread?-e.x:t,y:e.y},s=o.x>t*(1-this.grip.edgeX),c=o.y<n*this.grip.edgeY,l=o.y>n*(1-this.grip.edgeY),u=r.isStiff(a),d={x:s||!(c||l)?t:Math.max(1,o.x),y:u?n/2:c?0:l?n:Math.max(0,Math.min(n,o.y))};return{leaf:a,dir:i?1:-1,origin:d,stiff:u,start:d}}cornerAt(e){let{width:t,height:n,layout:r,flipped:i}=this,a=Math.max(36,t*.12);return[...i<r.length?[{x:t,y:0},{x:t,y:n}]:[],...r.spread&&i>0?[{x:-t,y:0},{x:-t,y:n}]:[]].find(t=>Math.hypot(e.x-t.x,e.y-t.y)<a)??null}};let C={previous:`Previous page`,next:`Next page`,soundOn:`Turn page sound on`,soundOff:`Turn page sound off`,fullscreen:`Full screen`,exitFullscreen:`Exit full screen`,byline:e=>`by ${e}`,rotateTitle:`Turn your phone sideways`,rotateBody:`Photo books open across two pages, just like the real thing.`,rotateFullscreen:`Open full screen`,rotateSingle:`Read one page at a time`};function w(e,t={},...n){let r=document.createElement(e);for(let[e,n]of Object.entries(t))e===`style`?Object.assign(r.style,n):n!=null&&n!==!1&&r.setAttribute(e,n===!0?``:String(n));return T(r,n),r}function T(e,t){for(let n of t)n&&e.append(n)}function E(e){let t=document.createElement(`template`);return t.innerHTML=e.trim(),t.content.firstElementChild}async function D(e){try{!document.fullscreenElement&&e.requestFullscreen&&await e.requestFullscreen({navigationUI:`hide`})}catch{}try{let e=screen.orientation;if(e?.lock)return await e.lock(`landscape`),!0}catch{}return!1}function O(e){let t=matchMedia(`(orientation: portrait)`),n=matchMedia(`(pointer: coarse)`),r=()=>e({portrait:t.matches,touch:n.matches});return r(),t.addEventListener(`change`,r),n.addEventListener(`change`,r),window.addEventListener(`resize`,r),()=>{t.removeEventListener(`change`,r),n.removeEventListener(`change`,r),window.removeEventListener(`resize`,r)}}let k=[14,24,34,44,54,64,74].map((e,t)=>({x:e,angle:t%2?38:-38,length:26-t*2})),A=e=>E(`<svg viewBox="0 0 100 40" class="fb-print-frame-sprig is-${e}" fill="none" stroke="currentColor" stroke-linecap="round" aria-hidden="true">
2
2
  <path d="M4 20 Q 50 17, 92 20" stroke-width="1.2"/>
3
- ${T.map(({x:e,angle:t,length:n})=>`<g transform="translate(${e} 20) rotate(${t}) scale(${n/20})"><path d="M0 0 C 5 -5, 14 -5, 20 0 C 14 5, 5 5, 0 0 Z" stroke-width="1"/><path d="M2 0 L 16 0" stroke-width="0.6"/></g>`).join(``)}
4
- </svg>`),D=()=>S(`<svg viewBox="0 0 40 40" class="fb-ornament" aria-hidden="true">
3
+ ${k.map(({x:e,angle:t,length:n})=>`<g transform="translate(${e} 20) rotate(${t}) scale(${n/20})"><path d="M0 0 C 5 -5, 14 -5, 20 0 C 14 5, 5 5, 0 0 Z" stroke-width="1"/><path d="M2 0 L 16 0" stroke-width="0.6"/></g>`).join(``)}
4
+ </svg>`),j=()=>E(`<svg viewBox="0 0 40 40" class="fb-ornament" aria-hidden="true">
5
5
  <circle cx="20" cy="20" r="18.5" fill="none" stroke="currentColor" stroke-opacity="0.6"/>
6
6
  <path d="M20 9 L 27 20 L 20 31 L 13 20 Z" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linejoin="round"/>
7
7
  <circle cx="20" cy="20" r="2.2" fill="currentColor"/>
8
- </svg>`),O=(e,t)=>b(`img`,{src:e.src,alt:e.alt??``,draggable:`false`,decoding:`async`,width:e.width??void 0,height:e.height??void 0,class:t}),k=e=>b(`div`,{class:`fb-page-surface ${e?`is-${e}`:``}`,"aria-hidden":`true`},b(`div`,{class:`fb-page-surface-grain`}),e&&b(`div`,{class:`fb-page-surface-gutter`}),e&&b(`div`,{class:`fb-page-surface-sheen`})),A=(e,t,n=!0,r=!0)=>b(`p`,{class:`fb-serif ${n?`fb-italic`:``} ${r?`fb-center`:``}`,style:t},e);function j(e,t,n=`cover`,r=!0,i=1){let a=e?.width&&e.height?e.width/e.height:4/3,o=b(`div`,{class:`fb-print-frame-box`,style:{fontSize:`${i}cqw`}}),s=b(`div`,{class:`fb-print-frame fb-frame-${t} ${n===`contain`?`is-contained`:``}`});if(n===`contain`&&s.style.setProperty(`--ratio`,String(a)),m[t]&&s.append(b(`span`,{class:`fb-print-frame-band`,"aria-hidden":`true`})),s.append(e&&r?O(e,`fb-print-photo fb-print-frame-photo`):b(`div`,{class:`fb-print-frame-photo fb-placeholder`})),t===`corners`)for(let e of[`tl`,`tr`,`bl`,`br`])s.append(b(`span`,{class:`fb-print-frame-corner is-${e}`,"aria-hidden":`true`}));return t===`botanical`&&s.append(E(`tl`),E(`br`)),o.append(s),o}function M(e,t,n={}){let{layout:r,caption:i,photos:a}=e,{number:o,side:s,showImages:c=!0,onSlotClick:l,activeSlot:u}=n,d=h(e,t.frame),f=b(`div`,{class:`fb-paper fb-paper-${t.paper} fb-page`}),p=(e,t=``,n=!1)=>{let r=a[e]??null,i=b(`div`,{class:[`fb-slot`,t,n&&`is-framed`,l&&`is-editable`,l&&u===e&&`is-active`].filter(Boolean).join(` `),role:l?`button`:void 0,"aria-label":l?`Photo slot ${e+1}`:void 0});return l&&i.addEventListener(`click`,()=>l(e)),i.append(r?j(r,d,n?`contain`:`cover`,c):b(`div`,{class:`fb-slot-empty`},l?`Add a photo`:``)),i},m=(e,...t)=>b(`div`,{class:`fb-column`,style:e},...t),g=i?A(i,{fontSize:`3.8cqw`}):null;switch(r){case`single`:f.append(p(0,`fb-bleed`)),i&&f.append(b(`div`,{class:`fb-caption-over`},i));break;case`framed`:f.append(m({padding:`10cqw 9cqw 6cqw`},b(`div`,{class:`fb-grow`},p(0,`fb-fill`,!0)),A(i??``,{marginTop:`5cqw`,fontSize:`4.2cqw`,minHeight:`6cqw`,lineHeight:`1.35`})));break;case`pair`:f.append(m({padding:`7cqw`,gap:`4cqw`},p(0,`fb-grow`),p(1,`fb-grow`),g));break;case`grid`:f.append(m({padding:`7cqw`,gap:`3cqw`},b(`div`,{class:`fb-grid fb-grow`,style:{gap:`3cqw`}},...[0,1,2,3].map(e=>p(e))),g));break;case`collage`:f.append(m({padding:`7cqw`,gap:`3cqw`},p(0,`fb-grow-large`),b(`div`,{class:`fb-row fb-grow`,style:{gap:`3cqw`}},p(1,`fb-grow`),p(2,`fb-grow`)),g));break;case`text`:f.append(b(`div`,{class:`fb-column fb-center`,style:{alignItems:`center`,justifyContent:`center`,padding:`14cqw 12cqw`}},b(`span`,{class:`fb-serif`,style:{fontSize:`18cqw`,lineHeight:`0.6`,opacity:`0.3`},"aria-hidden":`true`},`“`),A(i||(l?`Write something in the caption box below.`:``),{marginTop:`4cqw`,fontSize:`6cqw`,lineHeight:`1.4`,textWrap:`balance`},!0,!1)))}return o!==void 0&&r!==`single`&&f.append(b(`span`,{class:`fb-page-number`,style:s===`left`?{left:`0`}:{right:`0`}},String(o))),f.append(k(s)),f}function N(e,t=!0){let n=b(`div`,{class:`fb-cover-panel`},e.kicker&&b(`p`,{class:`fb-kicker`},e.kicker),b(`h1`,{class:`fb-serif`,style:{marginTop:`5cqw`,fontSize:`9cqw`,fontWeight:`500`,lineHeight:`1.05`,textWrap:`balance`}},e.title));return e.cover?n.append(b(`div`,{class:`fb-cover-photo`},t?O(e.cover,`fb-photo`):b(`div`,{class:`fb-placeholder`}))):e.subtitle&&n.append(A(e.subtitle,{marginTop:`6cqw`,fontSize:`4cqw`,opacity:`0.8`},!0,!1)),b(`div`,{class:`fb-cover fb-cover-${e.theme??`classic`}`},b(`div`,{class:`fb-hinge is-left`}),n)}function P(e){return b(`div`,{class:`fb-cover fb-cover-${e.theme??`classic`}`},b(`div`,{class:`fb-hinge is-right`}),b(`div`,{class:`fb-imprint`},D(),e.imprint&&b(`p`,{class:`fb-kicker`,style:{marginTop:`2cqw`,fontSize:`2.4cqw`,opacity:`0.6`}},e.imprint)))}function F(e,t,n){let r=[e.author,e.year].filter(Boolean).join(` · `);return b(`div`,{class:`fb-paper fb-paper-${t.paper} fb-page fb-center`,style:{alignItems:`center`,justifyContent:`center`,padding:`12cqw`}},D(),b(`h2`,{class:`fb-serif`,style:{marginTop:`6cqw`,fontSize:`7.5cqw`,fontWeight:`400`,lineHeight:`1.1`,textWrap:`balance`}},e.title),e.subtitle&&A(e.subtitle,{marginTop:`4cqw`,fontSize:`4cqw`,lineHeight:`1.45`},!0,!1),b(`div`,{style:{marginTop:`7cqw`,height:`1px`,width:`20cqw`,background:`currentColor`,opacity:`0.3`}}),r&&b(`p`,{style:{marginTop:`5cqw`,fontSize:`2.6cqw`,letterSpacing:`0.2em`,textTransform:`uppercase`}},r),k(n))}function I(e,t,n){return b(`div`,{class:`fb-paper fb-paper-${t.paper} fb-page fb-center`,style:{alignItems:`center`,justifyContent:`flex-end`,padding:`12cqw`,opacity:`0.9`}},e.colophon&&A(e.colophon,{fontSize:`3.6cqw`},!0,!1),k(n))}function L(e,t){return b(`div`,{class:`fb-paper fb-paper-${e.paper} fb-page`},k(t))}function R(e,t,n,r=!0){let i={paper:t.paper??`ivory`,frame:t.frame??`none`};switch(e.kind){case`cover`:return N(t);case`back`:return P(t);case`title`:return F(t,i,n);case`colophon`:return I(t,i,n);case`blank`:return L(i,n);case`page`:return M(t.pages[e.index],i,{number:r?e.index+1:void 0,side:n})}}let z=null;function B(e=.18){try{z??=new AudioContext;let t=z.createBuffer(1,Math.floor(z.sampleRate*.45),z.sampleRate),n=t.getChannelData(0);for(let e=0;e<n.length;e++){let t=e/n.length,r=Math.sin(Math.PI*Math.min(1,t*2.2))*(1-t)**1.5;n[e]=(Math.random()*2-1)*r*(.6+.4*Math.sin(t*40))}let r=z.createBufferSource(),i=z.createBiquadFilter(),a=z.createGain();r.buffer=t,i.type=`bandpass`,i.frequency.value=2200,i.Q.value=.6,a.gain.value=e,r.connect(i).connect(a).connect(z.destination),r.start()}catch{}}let V=3/4,H=`flipbook:sound`,U={layout:`auto`,controls:!0,autoHide:3200,thumbnails:!0,soundButton:!0,sound:!1,fullscreenButton:!0,landscape:!0,keyboard:!0,stiffCovers:!0,shading:1,labels:y},W=[{name:`under`,z:2},{name:`bend`,z:4},{name:`shadow`,z:5},{name:`curl`,z:7}],G=(e,t=0,n=0)=>e.length?`polygon(${e.map(e=>`${(e.x+t).toFixed(2)}px ${(e.y+n).toFixed(2)}px`).join(`, `)})`:`polygon(0 0)`,K=e=>`<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="${e}" stroke-linecap="round" stroke-linejoin="round"/></svg>`,q={prev:K(`M15 6l-6 6 6 6`),next:K(`M9 6l6 6-6 6`),expand:K(`M4 9V4h5M20 9V4h-5M4 15v5h5M20 15v5h-5`),collapse:K(`M9 4v5H4M15 4v5h5M9 20v-5H4M15 20v-5h5`),soundOn:K(`M4 10v4h3l5 4V6L7 10H4zM16 9a4 4 0 0 1 0 6M18.5 6.5a8 8 0 0 1 0 11`),soundOff:K(`M4 10v4h3l5 4V6L7 10H4zM17 10l4 4M21 10l-4 4`),grid:`<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><rect x="3" y="5" width="8" height="14" rx="1"/><rect x="13" y="5" width="8" height="14" rx="1"/></svg>`,phone:`<svg viewBox="0 0 64 64" class="fb-rotate-hint" aria-hidden="true"><rect x="20" y="6" width="24" height="52" rx="4" fill="none" stroke="currentColor" stroke-width="2.5"/><circle cx="32" cy="51" r="2" fill="currentColor"/></svg>`},J=()=>{try{return localStorage.getItem(H)}catch{return null}};var Y=class e{container;root;reader;settings;layout;size={width:0,height:0};orientation={portrait:!1,touch:!1};portraitChoice=`ask`;soundOn;stripOpen=!1;chromeVisible=!0;hideTimer;lastPlace=``;rendering=!1;dirty=!1;faces=/* @__PURE__ */ new Map;overlays=/* @__PURE__ */ new Map;cleanups=[];els;constructor(t,n){this.container=t,this.settings=e.resolve(n),this.soundOn=this.settings.sound,this.layout=this.buildLayout(),this.reader=new v(this.layout,{frame:(e,t)=>this.paint(e,t),change:()=>this.render(),flip:()=>{this.soundOn&&B(),this.settings.onFlip?.()}},{flipped:this.layout.flippedForPage(this.settings.startPage),physics:n.physics,grip:n.grip}),this.root=b(`div`,{class:`fb-root`}),this.els=this.build(),t.append(this.root);let r=J();this.settings.soundButton&&r&&(this.soundOn=r===`on`),this.listen(),this.poke(),this.render()}update(t){let n=t.book&&t.book!==this.settings.book;this.settings=e.resolve({...this.settings,...t,labels:{...this.settings.labels,...t.labels}}),t.sound!==void 0&&(this.soundOn=t.sound),t.physics&&(this.reader.engine.physics={...this.reader.engine.physics,...t.physics}),t.grip&&(this.reader.grip={...this.reader.grip,...t.grip}),(n||t.stiffCovers!==void 0)&&this.clearFaces(),this.els.title.textContent=this.settings.book.title,this.poke(),this.render()}next(){this.reader.next()}prev(){this.reader.prev()}go(e){this.reader.go(e)}goToPage(e){this.reader.go(this.reader.layout.flippedForPage(e))}destroy(){this.reader.destroy(),clearTimeout(this.hideTimer),this.cleanups.forEach(e=>e()),this.root.remove()}static resolve(e){let t=Object.fromEntries(Object.entries(e).filter(([,e])=>e!==void 0));return{...U,...t,labels:{...y,...e.labels}}}get spread(){let{layout:e,landscape:t}=this.settings,n=t&&this.orientation.touch&&this.orientation.portrait,r=this.els?.stage.getBoundingClientRect(),i=!!r&&r.width>0&&r.width/r.height<.95;return e===`auto`?!(n&&this.portraitChoice===`single`)&&!i:e===`spread`}buildLayout(){return new g(this.settings.book.pages.length,{spread:this.spread,stiffCovers:this.settings.stiffCovers})}build(){let e=(e,t,n)=>{let r=b(`button`,{type:`button`,class:`fb-button`,"aria-label":e,title:e});return r.append(S(t)),r.addEventListener(`click`,n),r},t=b(`h1`,{class:`fb-title`},this.settings.book.title),n=b(`p`,{class:`fb-byline`}),r=e(``,q.soundOff,()=>this.toggleSound()),i=e(``,q.expand,()=>this.toggleFullscreen()),a=b(`div`,{class:`fb-bar-group`},r,i),o=b(`div`,{class:`fb-bar fb-bar-top`},b(`div`,{class:`fb-bar-group`},b(`div`,{class:`fb-heading`},t,n)),a),s=b(`div`,{class:`fb-book-shadow`}),c=b(`div`,{class:`fb-edge`}),l=b(`div`,{class:`fb-edge`}),u=b(`div`,{class:`fb-spine`}),d=b(`div`,{class:`fb-book`},s,c,l,u),f=b(`div`,{class:`fb-stage`},d),p=e(``,q.prev,()=>this.reader.prev()),m=e(``,q.next,()=>this.reader.next()),h=b(`button`,{type:`button`,class:`fb-pages-button`,"aria-live":`polite`}),g=b(`div`,{class:`fb-bar fb-bar-bottom`},p,h,m);h.addEventListener(`click`,()=>{this.settings.thumbnails&&(this.stripOpen=!this.stripOpen,this.render())});for(let{name:e,z:t}of W){let n=b(`div`,{class:`fb-light`}),r=b(`div`,{class:`fb-overlay`,style:{zIndex:String(t)}},n);this.overlays.set(e,{clip:r,light:n})}return this.root.append(o,f,g),{top:o,title:t,byline:n,topRight:a,sound:r,fullscreen:i,stage:f,book:d,shadow:s,leftEdge:c,rightEdge:l,spine:u,bottom:g,prev:p,pages:h,next:m,strip:null,rotate:null}}listen(){let{stage:e}=this.els,t=(e,t,n)=>{e.addEventListener(t,n),this.cleanups.push(()=>e.removeEventListener(t,n))},n=new ResizeObserver(()=>this.render());n.observe(e),this.cleanups.push(()=>n.disconnect()),this.cleanups.push(w(e=>{this.orientation=e,this.render()})),t(e,`pointerdown`,e=>{e.button===0&&this.reader.down(this.toBook(e),e.pointerId)}),t(e,`pointermove`,t=>{let n=this.toBook(t);this.poke(),t.pointerType===`mouse`&&this.reader.hover(n),this.reader.move(n,t.pointerId)&&!e.hasPointerCapture(t.pointerId)&&e.setPointerCapture(t.pointerId)}),t(e,`pointerup`,t=>{if(this.reader.up(this.toBook(t),t.pointerId)!==`tap`)return;let n=e.getBoundingClientRect(),r=t.clientX-n.left;r>n.width*2/3?this.reader.next():r<n.width/3&&this.reader.prev()}),t(e,`pointerleave`,()=>this.reader.leave()),t(e,`pointercancel`,()=>this.reader.cancel()),t(this.root,`keydown`,e=>this.settings.keyboard===!0&&this.onKey(e)),t(window,`keydown`,e=>this.settings.keyboard===`global`&&this.onKey(e)),t(document,`fullscreenchange`,()=>this.render())}onKey(e){e.target instanceof HTMLInputElement||e.target instanceof HTMLTextAreaElement||e.target instanceof HTMLSelectElement||([`ArrowRight`,`PageDown`,` `].includes(e.key)?(e.preventDefault(),this.reader.next()):[`ArrowLeft`,`PageUp`].includes(e.key)?(e.preventDefault(),this.reader.prev()):e.key===`Home`?this.reader.go(0):e.key===`End`?this.reader.go(this.reader.layout.length):e.key===`Escape`&&this.stripOpen&&(this.stripOpen=!1,this.render()))}toBook(e){let t=this.els.book.getBoundingClientRect();return{x:e.clientX-(t.left+(this.layout.spread?t.width/2:0)),y:e.clientY-t.top}}poke(){let{autoHide:e}=this.settings;clearTimeout(this.hideTimer),this.chromeVisible||(this.chromeVisible=!0,this.renderChrome()),e!==!1&&(this.hideTimer=setTimeout(()=>{this.chromeVisible=!1,this.renderChrome()},e))}toggleSound(){this.soundOn=!this.soundOn,this.soundOn&&B();try{localStorage.setItem(H,this.soundOn?`on`:`off`)}catch{}this.renderChrome()}async toggleFullscreen(){document.fullscreenElement?await document.exitFullscreen().catch(()=>{}):await C(this.root)}clearFaces(){this.faces.forEach(e=>e.remove()),this.faces.clear()}render(){if(this.rendering)this.dirty=!0;else{this.rendering=!0;do this.dirty=!1,this.renderOnce();while(this.dirty);this.rendering=!1}}renderOnce(){let{settings:t,reader:n,els:r}=this,{book:i,controls:a}=t,o=r.stage.getBoundingClientRect(),s=this.spread;(s!==this.layout.spread||i.pages.length!==this.layout.pageCount||t.stiffCovers!==this.layout.stiffCovers)&&(this.layout=this.buildLayout(),this.clearFaces());let c=s?2:1,l=!a||o.height<500?16:Math.min(150,o.height*.16),u=Math.max(0,o.width-(s?64:24)),d=Math.max(0,o.height-l),f=Math.floor(Math.min(d*V,u/c)),p=Math.floor(f/V);this.size={width:f,height:p},n.configure({layout:this.layout,width:f,height:p});let{flipped:m,active:h,settled:g,atStart:_,atEnd:v}=n,y=this.layout.leaves,b=0;s&&_&&g&&(b=-f/2),s&&v&&g&&(b=f/2),this.root.style.background=t.background??e.stageTint(i),this.root.tabIndex=t.keyboard===!0?0:-1,r.book.hidden=f<=0,Object.assign(r.book.style,{width:`${f*c}px`,height:`${p}px`,transform:`translateX(${b}px)`,cursor:n.engine.dragging?`grabbing`:`grab`,clipPath:s?``:`inset(-50% -50% -50% 0)`}),Object.assign(r.shadow.style,{left:s&&_&&g?`52%`:`2%`,right:s&&v&&g?`52%`:`2%`});let x=s&&!_&&!v,S=e=>Math.min(10,Math.max(0,e)*.8),C=x&&m>1?S(m-1):0,w=(x||s&&_)&&m<y.length-1?S(y.length-m-1):0;Object.assign(r.leftEdge.style,{display:C?``:`none`,left:`${-C}px`,width:`${C}px`}),Object.assign(r.rightEdge.style,{display:w?``:`none`,right:`${-w}px`,width:`${w}px`}),r.spine.style.left=`${s?f:0}px`,this.renderFaces(h,m,f,p),this.renderOverlays(h,f,p),this.renderChrome(),this.renderStrip(),this.renderRotatePrompt();let T=`${s}:${m}`;T!==this.lastPlace&&(this.lastPlace=T,t.onPageChange?.({flipped:m,label:n.label,faces:this.layout.visible(m)}))}renderFaces(e,t,n,r){let i=this.layout.leaves,a=e?.leaf??null,o=e?.dir??1,s=a===null?t:a+1,c=a===null?t-1:a-1,l=/* @__PURE__ */ new Set;for(let u=Math.max(0,t-2);u<=Math.min(i.length-1,t+1);u++)for(let t of[`front`,`back`]){let d=`${u}:${t}`,f=u===a?t===`front`==(o===1)?`turning`:`flap`:t===`front`?u===s?`right`:`spare`:u===c&&this.layout.spread?`left`:`spare`,p=f===`left`||f===`turning`&&o===-1&&!e?.stiff,m=this.faces.get(d);m||(m=b(`div`,{class:`fb-face`}),m.append(R(t===`front`?i[u].front:i[u].back,this.settings.book,t===`front`?`right`:`left`)),this.faces.set(d,m),this.els.spine.append(m)),l.add(d),Object.assign(m.style,{left:`${p?-n:0}px`,width:`${n}px`,height:`${r}px`,zIndex:String({right:1,left:1,turning:3,flap:6,spare:0}[f]),visibility:f===`spare`?`hidden`:`visible`}),m.setAttribute(`aria-hidden`,String(f!==`left`&&f!==`right`)),u!==a&&Object.assign(m.style,{transform:``,transformOrigin:``,clipPath:``})}for(let[e,t]of this.faces)l.has(e)||(t.remove(),this.faces.delete(e));e&&this.paint(this.reader.engine.frame,e)}renderOverlays(e,t,n){let r=!!e&&!e.stiff,i=e=>`${(t*e).toFixed(1)}px`,a={under:`linear-gradient(to right, rgb(0 0 0 / 0.42), rgb(0 0 0 / 0.2) ${i(.05)}, rgb(0 0 0 / 0.06) ${i(.16)}, transparent ${i(.3)})`,bend:`linear-gradient(to right, rgb(0 0 0 / 0.16), rgb(0 0 0 / 0.04) ${i(.05)}, transparent ${i(.1)})`,shadow:`rgb(0 0 0 / 0.55)`,curl:`linear-gradient(to right, rgb(0 0 0 / 0.3), rgb(0 0 0 / 0.1) ${i(.035)}, rgb(255 255 255 / 0.2) ${i(.11)}, rgb(255 255 255 / 0.06) ${i(.25)}, rgb(0 0 0 / 0.05) ${i(.6)}, rgb(0 0 0 / 0.12) ${i(1)})`};for(let[e,{clip:i,light:o}]of this.overlays){if(!r){i.remove();continue}let s=e===`shadow`;Object.assign(i.style,{left:`${-t}px`,top:`${-n}px`,width:`${t*2}px`,height:`${n*3}px`,filter:s?`blur(${Math.max(3,t*.012)}px)`:``}),Object.assign(o.style,s?{inset:`0`,background:a[e]}:{width:`${t*3}px`,height:`${n*4}px`,background:a[e]}),i.isConnected||this.els.spine.append(i)}r&&e&&this.paint(this.reader.engine.frame,e)}paint(e,t){let{width:n,height:r}=this.size,i=t.dir,o=this.faces.get(`${t.leaf}:front`),s=this.faces.get(`${t.leaf}:back`);if(e.stiff){let t=`perspective(${Math.max(1800,n*5)}px) rotateY(${a.hinge(e.origin,e.point,i)}deg)`;o&&Object.assign(o.style,{transformOrigin:`0 50%`,transform:t,clipPath:``}),s&&Object.assign(s.style,{transformOrigin:`0 50%`,transform:`${t} translateX(${n}px) rotateY(180deg)`,clipPath:``});return}let c=i===1?o:s,l=i===1?s:o,u=new a(n,r,e.origin,e.point),d=u.shade*this.settings.shading;c&&Object.assign(c.style,{transformOrigin:``,transform:``,clipPath:G(u.flat.map(e=>({x:i===1?e.x:n-e.x,y:e.y})))}),l&&Object.assign(l.style,{transformOrigin:`0 0`,transform:u.flapMatrix(i),clipPath:G(u.folded.map(e=>({x:i===1?n-e.x:e.x,y:e.y})))});let f=(e,t,a,o)=>{let s=this.overlays.get(e);if(!s)return;let c=G(t.map(e=>({x:i*e.x,y:e.y})),n,r);if(s.clip.style.opacity=String(o),e===`shadow`){s.light.style.clipPath=c;return}let l=Math.atan2(a*u.normal.y,i*a*u.normal.x);s.clip.style.clipPath=c,s.light.style.transform=`translate(${i*u.center.x+n}px, ${u.center.y+r}px) rotate(${l}rad) translateY(-50%)`};f(`under`,u.folded,1,d),f(`bend`,u.flat,-1,d),f(`shadow`,u.flap,-1,d*.6),f(`curl`,u.flap,-1,d)}renderChrome(){let{els:e,settings:t,reader:n}=this,{labels:r}=t,i=this.chromeVisible||this.stripOpen,a=document.fullscreenElement===this.root,o=(e,t,n)=>{e.setAttribute(`aria-label`,t),e.title=t,n&&e.replaceChildren(S(n))};e.top.hidden=!t.controls,e.bottom.hidden=!t.controls,e.top.classList.toggle(`is-hidden`,!i),e.bottom.classList.toggle(`is-hidden`,!i),e.title.textContent=t.book.title,e.byline.textContent=t.book.author?r.byline(t.book.author):``,e.byline.hidden=!t.book.author,e.sound.hidden=!t.soundButton,e.fullscreen.hidden=!t.fullscreenButton,o(e.sound,this.soundOn?r.soundOff:r.soundOn,this.soundOn?q.soundOn:q.soundOff),o(e.fullscreen,a?r.exitFullscreen:r.fullscreen,a?q.collapse:q.expand),o(e.prev,r.previous),o(e.next,r.next),e.prev.disabled=n.atStart,e.next.disabled=n.atEnd,e.pages.replaceChildren(...t.thumbnails?[S(q.grid)]:[],n.label),e.pages.setAttribute(`aria-expanded`,String(this.stripOpen))}renderStrip(){let e=this.stripOpen&&this.settings.thumbnails,{book:t}=this.settings;if(!e){this.els.strip?.remove(),this.els.strip=null;return}let n=b(`div`,{class:`fb-strip-list`});for(let e of this.layout.stops()){let r=b(`button`,{type:`button`,class:`fb-strip-stop`,"aria-current":String(e.flipped===this.reader.flipped),"aria-label":`Go to ${g.describe(e.faces)}`});for(let n of e.faces)r.append(b(`div`,{class:`fb-strip-face`},R(n,t,void 0,!1)));r.addEventListener(`click`,()=>{this.stripOpen=!1,this.reader.go(e.flipped),this.render()}),n.append(r)}let r=b(`div`,{class:`fb-strip`},n);this.els.strip?.remove(),this.els.strip=r,this.els.bottom.before(r),n.querySelector(`[aria-current='true']`)?.scrollIntoView({inline:`center`,block:`nearest`})}renderRotatePrompt(){let{landscape:e,layout:t,labels:n}=this.settings;if(!(e&&t!==`single`&&this.orientation.touch&&this.orientation.portrait&&this.portraitChoice===`ask`)){this.els.rotate?.remove(),this.els.rotate=null;return}if(this.els.rotate)return;let r=b(`button`,{type:`button`,class:`fb-rotate-primary`},n.rotateFullscreen),i=b(`button`,{type:`button`,class:`fb-rotate-secondary`},n.rotateSingle);r.addEventListener(`click`,()=>C(this.root)),i.addEventListener(`click`,()=>{this.portraitChoice=`single`,this.render()}),this.els.rotate=b(`div`,{class:`fb-rotate`},S(q.phone),b(`div`,{},b(`p`,{class:`fb-rotate-title`},n.rotateTitle),b(`p`,{class:`fb-rotate-body`},n.rotateBody)),r,i),this.root.append(this.els.rotate)}static stageTint(e){let[t,n,r]=d[e.theme??`classic`].stage;return`radial-gradient(ellipse at 50% 40%, ${t} 0%, ${n} 55%, ${r} 100%)`}};return e.Affine=i,e.BANDED_FRAMES=m,e.BookLayout=g,e.COVER_THEMES=d,e.DEFAULT_GRIP=_,e.DEFAULT_LABELS=y,e.DEFAULT_PHYSICS=o,e.FRAME_STYLES=p,e.Flipbook=Y,e.FlipbookReader=v,e.Fold=a,e.PAGE_LAYOUTS=u,e.PAPER_COLORS=f,e.PageTurn=l,e.dot=n,e.enterLandscape=C,e.frameOf=h,e.length=r,e.playPageTurn=B,e.printedPhoto=j,e.renderBackCover=P,e.renderBlank=L,e.renderColophon=I,e.renderCover=N,e.renderFace=R,e.renderPage=M,e.renderTitlePage=F,e.sub=t,e.watchOrientation=w,e})({});
8
+ </svg>`),M=(e,t)=>w(`img`,{src:e.src,alt:e.alt??``,draggable:`false`,decoding:`async`,width:e.width??void 0,height:e.height??void 0,class:t}),N=({x:e,y:t,width:n,height:r,rotate:i})=>({left:`${e}cqw`,top:`${t}cqw`,width:`${n}cqw`,height:`${r}cqw`,...i?{transform:`rotate(${i}deg)`}:{}}),P=e=>w(`div`,{class:`fb-page-surface ${e?`is-${e}`:``}`,"aria-hidden":`true`},w(`div`,{class:`fb-page-surface-grain`}),e&&w(`div`,{class:`fb-page-surface-gutter`}),e&&w(`div`,{class:`fb-page-surface-sheen`})),F=(e,t,n=!0,r=!0)=>w(`p`,{class:`fb-serif ${n?`fb-italic`:``} ${r?`fb-center`:``}`,style:t},e);function I(e,t,n=`cover`,r=!0,i=1){let a=e?.width&&e.height?e.width/e.height:4/3,o=w(`div`,{class:`fb-print-frame-box`,style:{fontSize:`${i}cqw`}}),s=w(`div`,{class:`fb-print-frame fb-frame-${t} ${n===`contain`?`is-contained`:``}`});if(n===`contain`&&s.style.setProperty(`--ratio`,String(a)),_[t]&&s.append(w(`span`,{class:`fb-print-frame-band`,"aria-hidden":`true`})),s.append(e&&r?M(e,`fb-print-photo fb-print-frame-photo`):w(`div`,{class:`fb-print-frame-photo fb-placeholder`})),t===`corners`)for(let e of[`tl`,`tr`,`bl`,`br`])s.append(w(`span`,{class:`fb-print-frame-corner is-${e}`,"aria-hidden":`true`}));return t===`botanical`&&s.append(A(`tl`),A(`br`)),o.append(s),o}function L(e,t,n={}){let{layout:r,caption:i,photos:a}=e,{number:o,side:s,showImages:c=!0,onSlotClick:l,activeSlot:u}=n,d=p[r],f=w(`div`,{class:`fb-paper fb-paper-${t.paper} fb-page`}),m=(n,r=``,i=!1,o)=>{let s=a[n]??null,d=v(e,s,t.frame),f=w(`div`,{class:[`fb-slot`,r,i&&`is-framed`,l&&`is-editable`,l&&u===n&&`is-active`].filter(Boolean).join(` `),role:l?`button`:void 0,"aria-label":l?`Photo slot ${n+1}`:void 0,style:o});return l&&f.addEventListener(`click`,()=>l(n)),f.append(s?I(s,d,i?`contain`:`cover`,c):w(`div`,{class:`fb-slot-empty`},l?`Add a photo`:``)),f},h=(e,...t)=>w(`div`,{class:`fb-column`,style:e},...t),g=i?F(i,{fontSize:`3.8cqw`}):null;switch(r){case`single`:f.append(m(0,`fb-bleed`)),i&&f.append(w(`div`,{class:`fb-caption-over`},i));break;case`framed`:f.append(h({padding:`10cqw 9cqw 6cqw`},w(`div`,{class:`fb-grow`},m(0,`fb-fill`,!0)),F(i??``,{marginTop:`5cqw`,fontSize:`4.2cqw`,minHeight:`6cqw`,lineHeight:`1.35`})));break;case`pair`:f.append(h({padding:`7cqw`,gap:`4cqw`},m(0,`fb-grow`),m(1,`fb-grow`),g));break;case`grid`:f.append(h({padding:`7cqw`,gap:`3cqw`},w(`div`,{class:`fb-grid fb-grow`,style:{gap:`3cqw`}},...[0,1,2,3].map(e=>m(e))),g));break;case`collage`:f.append(h({padding:`7cqw`,gap:`3cqw`},m(0,`fb-grow-large`),w(`div`,{class:`fb-row fb-grow`,style:{gap:`3cqw`}},m(1,`fb-grow`),m(2,`fb-grow`)),g));break;case`text`:f.append(w(`div`,{class:`fb-column fb-center`,style:{alignItems:`center`,justifyContent:`center`,padding:`14cqw 12cqw`}},w(`span`,{class:`fb-serif`,style:{fontSize:`18cqw`,lineHeight:`0.6`,opacity:`0.3`},"aria-hidden":`true`},`“`),F(i||(l?`Write something in the caption box below.`:``),{marginTop:`4cqw`,fontSize:`6cqw`,lineHeight:`1.4`,textWrap:`balance`},!0,!1)))}return d&&(f.append(...d.slots.map((e,t)=>m(t,`fb-placed ${d.loose?`is-loose`:``}`,!1,N(e)))),i&&f.append(w(`p`,{class:`fb-placed-caption fb-serif ${d.prose?`is-prose`:`fb-italic`}`,style:N(d.caption)},i))),o!==void 0&&r!==`single`&&f.append(w(`span`,{class:`fb-page-number`,style:s===`left`?{left:`0`}:{right:`0`}},String(o))),f.append(P(s)),f}function R(e,t=!0){let n=w(`div`,{class:`fb-cover-panel`},e.kicker&&w(`p`,{class:`fb-kicker`},e.kicker),w(`h1`,{class:`fb-serif`,style:{marginTop:`5cqw`,fontSize:`9cqw`,fontWeight:`500`,lineHeight:`1.05`,textWrap:`balance`}},e.title));return e.cover?n.append(w(`div`,{class:`fb-cover-photo`},t?M(e.cover,`fb-photo`):w(`div`,{class:`fb-placeholder`}))):e.subtitle&&n.append(F(e.subtitle,{marginTop:`6cqw`,fontSize:`4cqw`,opacity:`0.8`},!0,!1)),w(`div`,{class:`fb-cover fb-cover-${e.theme??`classic`}`},w(`div`,{class:`fb-hinge is-left`}),n)}function z(e){return w(`div`,{class:`fb-cover fb-cover-${e.theme??`classic`}`},w(`div`,{class:`fb-hinge is-right`}),w(`div`,{class:`fb-imprint`},j(),e.imprint&&w(`p`,{class:`fb-kicker`,style:{marginTop:`2cqw`,fontSize:`2.4cqw`,opacity:`0.6`}},e.imprint)))}function B(e,t,n){let r=[e.author,e.year].filter(Boolean).join(` · `);return w(`div`,{class:`fb-paper fb-paper-${t.paper} fb-page fb-center`,style:{alignItems:`center`,justifyContent:`center`,padding:`12cqw`}},j(),w(`h2`,{class:`fb-serif`,style:{marginTop:`6cqw`,fontSize:`7.5cqw`,fontWeight:`400`,lineHeight:`1.1`,textWrap:`balance`}},e.title),e.subtitle&&F(e.subtitle,{marginTop:`4cqw`,fontSize:`4cqw`,lineHeight:`1.45`},!0,!1),w(`div`,{style:{marginTop:`7cqw`,height:`1px`,width:`20cqw`,background:`currentColor`,opacity:`0.3`}}),r&&w(`p`,{style:{marginTop:`5cqw`,fontSize:`2.6cqw`,letterSpacing:`0.2em`,textTransform:`uppercase`}},r),P(n))}function V(e,t,n){return w(`div`,{class:`fb-paper fb-paper-${t.paper} fb-page fb-center`,style:{alignItems:`center`,justifyContent:`flex-end`,padding:`12cqw`,opacity:`0.9`}},e.colophon&&F(e.colophon,{fontSize:`3.6cqw`},!0,!1),P(n))}function H(e,t){return w(`div`,{class:`fb-paper fb-paper-${e.paper} fb-page`},P(t))}function U(e,t,n,r=!0){let i={paper:t.paper??`ivory`,frame:t.frame??`none`};switch(e.kind){case`cover`:return R(t);case`back`:return z(t);case`title`:return B(t,i,n);case`colophon`:return V(t,i,n);case`blank`:return H(i,n);case`page`:return L(t.pages[e.index],i,{number:r?e.index+1:void 0,side:n})}}let W=null;function G(e=.18){try{W??=new AudioContext;let t=W.createBuffer(1,Math.floor(W.sampleRate*.45),W.sampleRate),n=t.getChannelData(0);for(let e=0;e<n.length;e++){let t=e/n.length,r=Math.sin(Math.PI*Math.min(1,t*2.2))*(1-t)**1.5;n[e]=(Math.random()*2-1)*r*(.6+.4*Math.sin(t*40))}let r=W.createBufferSource(),i=W.createBiquadFilter(),a=W.createGain();r.buffer=t,i.type=`bandpass`,i.frequency.value=2200,i.Q.value=.6,a.gain.value=e,r.connect(i).connect(a).connect(W.destination),r.start()}catch{}}let K=3/4,q=`flipbook:sound`,J={layout:`auto`,controls:!0,autoHide:3200,thumbnails:!0,soundButton:!0,sound:!1,fullscreenButton:!0,landscape:!0,keyboard:!0,stiffCovers:!0,shading:1,labels:C},Y=[{name:`under`,z:2},{name:`bend`,z:4},{name:`shadow`,z:5},{name:`curl`,z:7}],X=(e,t=0,n=0)=>e.length?`polygon(${e.map(e=>`${(e.x+t).toFixed(2)}px ${(e.y+n).toFixed(2)}px`).join(`, `)})`:`polygon(0 0)`,Z=e=>`<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="${e}" stroke-linecap="round" stroke-linejoin="round"/></svg>`,Q={prev:Z(`M15 6l-6 6 6 6`),next:Z(`M9 6l6 6-6 6`),expand:Z(`M4 9V4h5M20 9V4h-5M4 15v5h5M20 15v5h-5`),collapse:Z(`M9 4v5H4M15 4v5h5M9 20v-5H4M15 20v-5h5`),soundOn:Z(`M4 10v4h3l5 4V6L7 10H4zM16 9a4 4 0 0 1 0 6M18.5 6.5a8 8 0 0 1 0 11`),soundOff:Z(`M4 10v4h3l5 4V6L7 10H4zM17 10l4 4M21 10l-4 4`),grid:`<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><rect x="3" y="5" width="8" height="14" rx="1"/><rect x="13" y="5" width="8" height="14" rx="1"/></svg>`,phone:`<svg viewBox="0 0 64 64" class="fb-rotate-hint" aria-hidden="true"><rect x="20" y="6" width="24" height="52" rx="4" fill="none" stroke="currentColor" stroke-width="2.5"/><circle cx="32" cy="51" r="2" fill="currentColor"/></svg>`},$=()=>{try{return localStorage.getItem(q)}catch{return null}};var ee=class e{container;root;reader;settings;layout;size={width:0,height:0};orientation={portrait:!1,touch:!1};portraitChoice=`ask`;soundOn;stripOpen=!1;chromeVisible=!0;hideTimer;lastPlace=``;rendering=!1;dirty=!1;faces=/* @__PURE__ */ new Map;overlays=/* @__PURE__ */ new Map;cleanups=[];els;constructor(t,n){this.container=t,this.settings=e.resolve(n),this.soundOn=this.settings.sound,this.layout=this.buildLayout(),this.reader=new S(this.layout,{frame:(e,t)=>this.paint(e,t),change:()=>this.render(),flip:()=>{this.soundOn&&G(),this.settings.onFlip?.()}},{flipped:this.layout.flippedForPage(this.settings.startPage),physics:n.physics,grip:n.grip}),this.root=w(`div`,{class:`fb-root`}),this.els=this.build(),t.append(this.root);let r=$();this.settings.soundButton&&r&&(this.soundOn=r===`on`),this.listen(),this.poke(),this.render()}update(t){let n=t.book&&t.book!==this.settings.book;this.settings=e.resolve({...this.settings,...t,labels:{...this.settings.labels,...t.labels}}),t.sound!==void 0&&(this.soundOn=t.sound),t.physics&&(this.reader.engine.physics={...this.reader.engine.physics,...t.physics}),t.grip&&(this.reader.grip={...this.reader.grip,...t.grip}),(n||t.stiffCovers!==void 0)&&this.clearFaces(),this.els.title.textContent=this.settings.book.title,this.poke(),this.render()}next(){this.reader.next()}prev(){this.reader.prev()}go(e){this.reader.go(e)}goToPage(e){this.reader.go(this.reader.layout.flippedForPage(e))}destroy(){this.reader.destroy(),clearTimeout(this.hideTimer),this.cleanups.forEach(e=>e()),this.root.remove()}static resolve(e){let t=Object.fromEntries(Object.entries(e).filter(([,e])=>e!==void 0));return{...J,...t,labels:{...C,...e.labels}}}get spread(){let{layout:e,landscape:t}=this.settings,n=t&&this.orientation.touch&&this.orientation.portrait,r=this.els?.stage.getBoundingClientRect(),i=!!r&&r.width>0&&r.width/r.height<.95;return e===`auto`?!(n&&this.portraitChoice===`single`)&&!i:e===`spread`}buildLayout(){return new b(this.settings.book.pages.length,{spread:this.spread,stiffCovers:this.settings.stiffCovers})}build(){let e=(e,t,n)=>{let r=w(`button`,{type:`button`,class:`fb-button`,"aria-label":e,title:e});return r.append(E(t)),r.addEventListener(`click`,n),r},t=w(`h1`,{class:`fb-title`},this.settings.book.title),n=w(`p`,{class:`fb-byline`}),r=e(``,Q.soundOff,()=>this.toggleSound()),i=e(``,Q.expand,()=>this.toggleFullscreen()),a=w(`div`,{class:`fb-bar-group`},r,i),o=w(`div`,{class:`fb-bar fb-bar-top`},w(`div`,{class:`fb-bar-group`},w(`div`,{class:`fb-heading`},t,n)),a),s=w(`div`,{class:`fb-book-shadow`}),c=w(`div`,{class:`fb-edge`}),l=w(`div`,{class:`fb-edge`}),u=w(`div`,{class:`fb-spine`}),d=w(`div`,{class:`fb-book`},s,c,l,u),f=w(`div`,{class:`fb-stage`},d),p=e(``,Q.prev,()=>this.reader.prev()),m=e(``,Q.next,()=>this.reader.next()),h=w(`button`,{type:`button`,class:`fb-pages-button`,"aria-live":`polite`}),g=w(`div`,{class:`fb-bar fb-bar-bottom`},p,h,m);h.addEventListener(`click`,()=>{this.settings.thumbnails&&(this.stripOpen=!this.stripOpen,this.render())});for(let{name:e,z:t}of Y){let n=w(`div`,{class:`fb-light`}),r=w(`div`,{class:`fb-overlay`,style:{zIndex:String(t)}},n);this.overlays.set(e,{clip:r,light:n})}return this.root.append(o,f,g),{top:o,title:t,byline:n,topRight:a,sound:r,fullscreen:i,stage:f,book:d,shadow:s,leftEdge:c,rightEdge:l,spine:u,bottom:g,prev:p,pages:h,next:m,strip:null,rotate:null}}listen(){let{stage:e}=this.els,t=(e,t,n)=>{e.addEventListener(t,n),this.cleanups.push(()=>e.removeEventListener(t,n))},n=new ResizeObserver(()=>this.render());n.observe(e),this.cleanups.push(()=>n.disconnect()),this.cleanups.push(O(e=>{this.orientation=e,this.render()})),t(e,`pointerdown`,e=>{e.button===0&&this.reader.down(this.toBook(e),e.pointerId)}),t(e,`pointermove`,t=>{let n=this.toBook(t);this.poke(),t.pointerType===`mouse`&&this.reader.hover(n),this.reader.move(n,t.pointerId)&&!e.hasPointerCapture(t.pointerId)&&e.setPointerCapture(t.pointerId)}),t(e,`pointerup`,t=>{if(this.reader.up(this.toBook(t),t.pointerId)!==`tap`)return;let n=e.getBoundingClientRect(),r=t.clientX-n.left;r>n.width*2/3?this.reader.next():r<n.width/3&&this.reader.prev()}),t(e,`pointerleave`,()=>this.reader.leave()),t(e,`pointercancel`,()=>this.reader.cancel()),t(this.root,`keydown`,e=>this.settings.keyboard===!0&&this.onKey(e)),t(window,`keydown`,e=>this.settings.keyboard===`global`&&this.onKey(e)),t(document,`fullscreenchange`,()=>this.render())}onKey(e){e.target instanceof HTMLInputElement||e.target instanceof HTMLTextAreaElement||e.target instanceof HTMLSelectElement||([`ArrowRight`,`PageDown`,` `].includes(e.key)?(e.preventDefault(),this.reader.next()):[`ArrowLeft`,`PageUp`].includes(e.key)?(e.preventDefault(),this.reader.prev()):e.key===`Home`?this.reader.go(0):e.key===`End`?this.reader.go(this.reader.layout.length):e.key===`Escape`&&this.stripOpen&&(this.stripOpen=!1,this.render()))}toBook(e){let t=this.els.book.getBoundingClientRect();return{x:e.clientX-(t.left+(this.layout.spread?t.width/2:0)),y:e.clientY-t.top}}poke(){let{autoHide:e}=this.settings;clearTimeout(this.hideTimer),this.chromeVisible||(this.chromeVisible=!0,this.renderChrome()),e!==!1&&(this.hideTimer=setTimeout(()=>{this.chromeVisible=!1,this.renderChrome()},e))}toggleSound(){this.soundOn=!this.soundOn,this.soundOn&&G();try{localStorage.setItem(q,this.soundOn?`on`:`off`)}catch{}this.renderChrome()}async toggleFullscreen(){document.fullscreenElement?await document.exitFullscreen().catch(()=>{}):await D(this.root)}clearFaces(){this.faces.forEach(e=>e.remove()),this.faces.clear()}render(){if(this.rendering)this.dirty=!0;else{this.rendering=!0;do this.dirty=!1,this.renderOnce();while(this.dirty);this.rendering=!1}}renderOnce(){let{settings:t,reader:n,els:r}=this,{book:i,controls:a}=t,o=r.stage.getBoundingClientRect(),s=this.spread;(s!==this.layout.spread||i.pages.length!==this.layout.pageCount||t.stiffCovers!==this.layout.stiffCovers)&&(this.layout=this.buildLayout(),this.clearFaces());let c=s?2:1,l=!a||o.height<500?16:Math.min(150,o.height*.16),u=Math.max(0,o.width-(s?64:24)),d=Math.max(0,o.height-l),f=Math.floor(Math.min(d*K,u/c)),p=Math.floor(f/K);this.size={width:f,height:p},n.configure({layout:this.layout,width:f,height:p});let{flipped:m,active:h,settled:g,atStart:_,atEnd:v}=n,y=this.layout.leaves,b=0;s&&_&&g&&(b=-f/2),s&&v&&g&&(b=f/2),this.root.style.background=t.background??e.stageTint(i),this.root.tabIndex=t.keyboard===!0?0:-1,r.book.hidden=f<=0,Object.assign(r.book.style,{width:`${f*c}px`,height:`${p}px`,transform:`translateX(${b}px)`,cursor:n.engine.dragging?`grabbing`:`grab`,clipPath:s?``:`inset(-50% -50% -50% 0)`}),Object.assign(r.shadow.style,{left:s&&_&&g?`52%`:`2%`,right:s&&v&&g?`52%`:`2%`});let x=s&&!_&&!v,S=e=>Math.min(10,Math.max(0,e)*.8),C=x&&m>1?S(m-1):0,w=(x||s&&_)&&m<y.length-1?S(y.length-m-1):0;Object.assign(r.leftEdge.style,{display:C?``:`none`,left:`${-C}px`,width:`${C}px`}),Object.assign(r.rightEdge.style,{display:w?``:`none`,right:`${-w}px`,width:`${w}px`}),r.spine.style.left=`${s?f:0}px`,this.renderFaces(h,m,f,p),this.renderOverlays(h,f,p),this.renderChrome(),this.renderStrip(),this.renderRotatePrompt();let T=`${s}:${m}`;T!==this.lastPlace&&(this.lastPlace=T,t.onPageChange?.({flipped:m,label:n.label,faces:this.layout.visible(m)}))}renderFaces(e,t,n,r){let i=this.layout.leaves,a=e?.leaf??null,o=e?.dir??1,s=a===null?t:a+1,c=a===null?t-1:a-1,l=/* @__PURE__ */ new Set;for(let u=Math.max(0,t-2);u<=Math.min(i.length-1,t+1);u++)for(let t of[`front`,`back`]){let d=`${u}:${t}`,f=u===a?t===`front`==(o===1)?`turning`:`flap`:t===`front`?u===s?`right`:`spare`:u===c&&this.layout.spread?`left`:`spare`,p=f===`left`||f===`turning`&&o===-1&&!e?.stiff,m=this.faces.get(d);m||(m=w(`div`,{class:`fb-face`}),m.append(U(t===`front`?i[u].front:i[u].back,this.settings.book,t===`front`?`right`:`left`)),this.faces.set(d,m),this.els.spine.append(m)),l.add(d),Object.assign(m.style,{left:`${p?-n:0}px`,width:`${n}px`,height:`${r}px`,zIndex:String({right:1,left:1,turning:3,flap:6,spare:0}[f]),visibility:f===`spare`?`hidden`:`visible`}),m.setAttribute(`aria-hidden`,String(f!==`left`&&f!==`right`)),u!==a&&Object.assign(m.style,{transform:``,transformOrigin:``,clipPath:``})}for(let[e,t]of this.faces)l.has(e)||(t.remove(),this.faces.delete(e));e&&this.paint(this.reader.engine.frame,e)}renderOverlays(e,t,n){let r=!!e&&!e.stiff,i=e=>`${(t*e).toFixed(1)}px`,a={under:`linear-gradient(to right, rgb(0 0 0 / 0.42), rgb(0 0 0 / 0.2) ${i(.05)}, rgb(0 0 0 / 0.06) ${i(.16)}, transparent ${i(.3)})`,bend:`linear-gradient(to right, rgb(0 0 0 / 0.16), rgb(0 0 0 / 0.04) ${i(.05)}, transparent ${i(.1)})`,shadow:`rgb(0 0 0 / 0.55)`,curl:`linear-gradient(to right, rgb(0 0 0 / 0.3), rgb(0 0 0 / 0.1) ${i(.035)}, rgb(255 255 255 / 0.2) ${i(.11)}, rgb(255 255 255 / 0.06) ${i(.25)}, rgb(0 0 0 / 0.05) ${i(.6)}, rgb(0 0 0 / 0.12) ${i(1)})`};for(let[e,{clip:i,light:o}]of this.overlays){if(!r){i.remove();continue}let s=e===`shadow`;Object.assign(i.style,{left:`${-t}px`,top:`${-n}px`,width:`${t*2}px`,height:`${n*3}px`,filter:s?`blur(${Math.max(3,t*.012)}px)`:``}),Object.assign(o.style,s?{inset:`0`,background:a[e]}:{width:`${t*3}px`,height:`${n*4}px`,background:a[e]}),i.isConnected||this.els.spine.append(i)}r&&e&&this.paint(this.reader.engine.frame,e)}paint(e,t){let{width:n,height:r}=this.size,i=t.dir,o=this.faces.get(`${t.leaf}:front`),s=this.faces.get(`${t.leaf}:back`);if(e.stiff){let t=`perspective(${Math.max(1800,n*5)}px) rotateY(${a.hinge(e.origin,e.point,i)}deg)`;o&&Object.assign(o.style,{transformOrigin:`0 50%`,transform:t,clipPath:``}),s&&Object.assign(s.style,{transformOrigin:`0 50%`,transform:`${t} translateX(${n}px) rotateY(180deg)`,clipPath:``});return}let c=i===1?o:s,l=i===1?s:o,u=new a(n,r,e.origin,e.point),d=u.shade*this.settings.shading;c&&Object.assign(c.style,{transformOrigin:``,transform:``,clipPath:X(u.flat.map(e=>({x:i===1?e.x:n-e.x,y:e.y})))}),l&&Object.assign(l.style,{transformOrigin:`0 0`,transform:u.flapMatrix(i),clipPath:X(u.folded.map(e=>({x:i===1?n-e.x:e.x,y:e.y})))});let f=(e,t,a,o)=>{let s=this.overlays.get(e);if(!s)return;let c=X(t.map(e=>({x:i*e.x,y:e.y})),n,r);if(s.clip.style.opacity=String(o),e===`shadow`){s.light.style.clipPath=c;return}let l=Math.atan2(a*u.normal.y,i*a*u.normal.x);s.clip.style.clipPath=c,s.light.style.transform=`translate(${i*u.center.x+n}px, ${u.center.y+r}px) rotate(${l}rad) translateY(-50%)`};f(`under`,u.folded,1,d),f(`bend`,u.flat,-1,d),f(`shadow`,u.flap,-1,d*.6),f(`curl`,u.flap,-1,d)}renderChrome(){let{els:e,settings:t,reader:n}=this,{labels:r}=t,i=this.chromeVisible||this.stripOpen,a=document.fullscreenElement===this.root,o=(e,t,n)=>{e.setAttribute(`aria-label`,t),e.title=t,n&&e.replaceChildren(E(n))};e.top.hidden=!t.controls,e.bottom.hidden=!t.controls,e.top.classList.toggle(`is-hidden`,!i),e.bottom.classList.toggle(`is-hidden`,!i),e.title.textContent=t.book.title,e.byline.textContent=t.book.author?r.byline(t.book.author):``,e.byline.hidden=!t.book.author,e.sound.hidden=!t.soundButton,e.fullscreen.hidden=!t.fullscreenButton,o(e.sound,this.soundOn?r.soundOff:r.soundOn,this.soundOn?Q.soundOn:Q.soundOff),o(e.fullscreen,a?r.exitFullscreen:r.fullscreen,a?Q.collapse:Q.expand),o(e.prev,r.previous),o(e.next,r.next),e.prev.disabled=n.atStart,e.next.disabled=n.atEnd,e.pages.replaceChildren(...t.thumbnails?[E(Q.grid)]:[],n.label),e.pages.setAttribute(`aria-expanded`,String(this.stripOpen))}renderStrip(){let e=this.stripOpen&&this.settings.thumbnails,{book:t}=this.settings;if(!e){this.els.strip?.remove(),this.els.strip=null;return}let n=w(`div`,{class:`fb-strip-list`});for(let e of this.layout.stops()){let r=w(`button`,{type:`button`,class:`fb-strip-stop`,"aria-current":String(e.flipped===this.reader.flipped),"aria-label":`Go to ${b.describe(e.faces)}`});for(let n of e.faces)r.append(w(`div`,{class:`fb-strip-face`},U(n,t,void 0,!1)));r.addEventListener(`click`,()=>{this.stripOpen=!1,this.reader.go(e.flipped),this.render()}),n.append(r)}let r=w(`div`,{class:`fb-strip`},n);this.els.strip?.remove(),this.els.strip=r,this.els.bottom.before(r),n.querySelector(`[aria-current='true']`)?.scrollIntoView({inline:`center`,block:`nearest`})}renderRotatePrompt(){let{landscape:e,layout:t,labels:n}=this.settings;if(!(e&&t!==`single`&&this.orientation.touch&&this.orientation.portrait&&this.portraitChoice===`ask`)){this.els.rotate?.remove(),this.els.rotate=null;return}if(this.els.rotate)return;let r=w(`button`,{type:`button`,class:`fb-rotate-primary`},n.rotateFullscreen),i=w(`button`,{type:`button`,class:`fb-rotate-secondary`},n.rotateSingle);r.addEventListener(`click`,()=>D(this.root)),i.addEventListener(`click`,()=>{this.portraitChoice=`single`,this.render()}),this.els.rotate=w(`div`,{class:`fb-rotate`},E(Q.phone),w(`div`,{},w(`p`,{class:`fb-rotate-title`},n.rotateTitle),w(`p`,{class:`fb-rotate-body`},n.rotateBody)),r,i),this.root.append(this.els.rotate)}static stageTint(e){let[t,n,r]=m[e.theme??`classic`].stage;return`radial-gradient(ellipse at 50% 40%, ${t} 0%, ${n} 55%, ${r} 100%)`}};return e.Affine=i,e.BANDED_FRAMES=_,e.BookLayout=b,e.COVER_THEMES=m,e.DEFAULT_GRIP=x,e.DEFAULT_LABELS=C,e.DEFAULT_PHYSICS=o,e.FRAME_STYLES=g,e.Flipbook=ee,e.FlipbookReader=S,e.Fold=a,e.PAGE_LAYOUTS=u,e.PAPER_COLORS=h,e.PLACED_LAYOUTS=p,e.PageTurn=l,e.dot=n,e.enterLandscape=D,e.frameOf=y,e.length=r,e.photoFrame=v,e.playPageTurn=G,e.printedPhoto=I,e.renderBackCover=z,e.renderBlank=H,e.renderColophon=V,e.renderCover=R,e.renderFace=U,e.renderPage=L,e.renderTitlePage=B,e.sub=t,e.watchOrientation=O,e})({});
package/dist/index.cjs CHANGED
@@ -86,6 +86,13 @@ const image = (photo, className) => h("img", {
86
86
  height: photo.height ?? void 0,
87
87
  class: className
88
88
  });
89
+ const boxStyle = ({ x, y, width, height, rotate }) => ({
90
+ left: `${x}cqw`,
91
+ top: `${y}cqw`,
92
+ width: `${width}cqw`,
93
+ height: `${height}cqw`,
94
+ ...rotate ? { transform: `rotate(${rotate}deg)` } : {}
95
+ });
89
96
  /** Light and grain over a whole page, with the curve into the spine on a spread. */
90
97
  const surface = (side) => h("div", {
91
98
  class: `fb-page-surface ${side ? `is-${side}` : ""}`,
@@ -126,10 +133,11 @@ function printedPhoto(photo, frame, fit = "cover", show = true, scale = 1) {
126
133
  function renderPage(page, look, options = {}) {
127
134
  const { layout, caption, photos } = page;
128
135
  const { number, side, showImages = true, onSlotClick, activeSlot } = options;
129
- const frame = (0, _toneflix_flipbook_core.frameOf)(page, look.frame);
136
+ const placed = _toneflix_flipbook_core.PLACED_LAYOUTS[layout];
130
137
  const root = h("div", { class: `fb-paper fb-paper-${look.paper} fb-page` });
131
- const slot = (index, className = "", framed = false) => {
138
+ const slot = (index, className = "", framed = false, style) => {
132
139
  const photo = photos[index] ?? null;
140
+ const frame = (0, _toneflix_flipbook_core.photoFrame)(page, photo, look.frame);
133
141
  const el = h("div", {
134
142
  class: [
135
143
  "fb-slot",
@@ -139,7 +147,8 @@ function renderPage(page, look, options = {}) {
139
147
  onSlotClick && activeSlot === index && "is-active"
140
148
  ].filter(Boolean).join(" "),
141
149
  role: onSlotClick ? "button" : void 0,
142
- "aria-label": onSlotClick ? `Photo slot ${index + 1}` : void 0
150
+ "aria-label": onSlotClick ? `Photo slot ${index + 1}` : void 0,
151
+ style
143
152
  });
144
153
  if (onSlotClick) el.addEventListener("click", () => onSlotClick(index));
145
154
  el.append(photo ? printedPhoto(photo, frame, framed ? "contain" : "cover", showImages) : h("div", { class: "fb-slot-empty" }, onSlotClick ? "Add a photo" : ""));
@@ -214,6 +223,13 @@ function renderPage(page, look, options = {}) {
214
223
  textWrap: "balance"
215
224
  }, true, false)));
216
225
  }
226
+ if (placed) {
227
+ root.append(...placed.slots.map((box, i) => slot(i, `fb-placed ${placed.loose ? "is-loose" : ""}`, false, boxStyle(box))));
228
+ if (caption) root.append(h("p", {
229
+ class: `fb-placed-caption fb-serif ${placed.prose ? "is-prose" : "fb-italic"}`,
230
+ style: boxStyle(placed.caption)
231
+ }, caption));
232
+ }
217
233
  if (number !== void 0 && layout !== "single") root.append(h("span", {
218
234
  class: "fb-page-number",
219
235
  style: side === "left" ? { left: "0" } : { right: "0" }
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { BANDED_FRAMES, BookLayout, COVER_THEMES, DEFAULT_LABELS, FlipbookReader, Fold, frameOf } from "@toneflix/flipbook-core";
1
+ import { BANDED_FRAMES, BookLayout, COVER_THEMES, DEFAULT_LABELS, FlipbookReader, Fold, PLACED_LAYOUTS, photoFrame } from "@toneflix/flipbook-core";
2
2
  export * from "@toneflix/flipbook-core";
3
3
  // src/dom.ts
4
4
  /** Creates an element. Strings become text, so book content is never parsed as HTML. */
@@ -86,6 +86,13 @@ const image = (photo, className) => h("img", {
86
86
  height: photo.height ?? void 0,
87
87
  class: className
88
88
  });
89
+ const boxStyle = ({ x, y, width, height, rotate }) => ({
90
+ left: `${x}cqw`,
91
+ top: `${y}cqw`,
92
+ width: `${width}cqw`,
93
+ height: `${height}cqw`,
94
+ ...rotate ? { transform: `rotate(${rotate}deg)` } : {}
95
+ });
89
96
  /** Light and grain over a whole page, with the curve into the spine on a spread. */
90
97
  const surface = (side) => h("div", {
91
98
  class: `fb-page-surface ${side ? `is-${side}` : ""}`,
@@ -126,10 +133,11 @@ function printedPhoto(photo, frame, fit = "cover", show = true, scale = 1) {
126
133
  function renderPage(page, look, options = {}) {
127
134
  const { layout, caption, photos } = page;
128
135
  const { number, side, showImages = true, onSlotClick, activeSlot } = options;
129
- const frame = frameOf(page, look.frame);
136
+ const placed = PLACED_LAYOUTS[layout];
130
137
  const root = h("div", { class: `fb-paper fb-paper-${look.paper} fb-page` });
131
- const slot = (index, className = "", framed = false) => {
138
+ const slot = (index, className = "", framed = false, style) => {
132
139
  const photo = photos[index] ?? null;
140
+ const frame = photoFrame(page, photo, look.frame);
133
141
  const el = h("div", {
134
142
  class: [
135
143
  "fb-slot",
@@ -139,7 +147,8 @@ function renderPage(page, look, options = {}) {
139
147
  onSlotClick && activeSlot === index && "is-active"
140
148
  ].filter(Boolean).join(" "),
141
149
  role: onSlotClick ? "button" : void 0,
142
- "aria-label": onSlotClick ? `Photo slot ${index + 1}` : void 0
150
+ "aria-label": onSlotClick ? `Photo slot ${index + 1}` : void 0,
151
+ style
143
152
  });
144
153
  if (onSlotClick) el.addEventListener("click", () => onSlotClick(index));
145
154
  el.append(photo ? printedPhoto(photo, frame, framed ? "contain" : "cover", showImages) : h("div", { class: "fb-slot-empty" }, onSlotClick ? "Add a photo" : ""));
@@ -214,6 +223,13 @@ function renderPage(page, look, options = {}) {
214
223
  textWrap: "balance"
215
224
  }, true, false)));
216
225
  }
226
+ if (placed) {
227
+ root.append(...placed.slots.map((box, i) => slot(i, `fb-placed ${placed.loose ? "is-loose" : ""}`, false, boxStyle(box))));
228
+ if (caption) root.append(h("p", {
229
+ class: `fb-placed-caption fb-serif ${placed.prose ? "is-prose" : "fb-italic"}`,
230
+ style: boxStyle(placed.caption)
231
+ }, caption));
232
+ }
217
233
  if (number !== void 0 && layout !== "single") root.append(h("span", {
218
234
  class: "fb-page-number",
219
235
  style: side === "left" ? { left: "0" } : { right: "0" }
package/dist/style.css CHANGED
@@ -840,3 +840,30 @@
840
840
  position: absolute;
841
841
  inset: 0;
842
842
  }
843
+ .fb-slot.fb-placed {
844
+ position: absolute;
845
+ }
846
+ .fb-slot.fb-placed.is-loose {
847
+ overflow: visible;
848
+ box-shadow:
849
+ 0 0.4cqw 0.8cqw rgb(0 0 0 / 0.18),
850
+ 0 1.6cqw 3.2cqw -1cqw rgb(0 0 0 / 0.25);
851
+ }
852
+ .fb-page .fb-placed-caption {
853
+ position: absolute;
854
+ display: flex;
855
+ margin: 0;
856
+ align-items: center;
857
+ justify-content: center;
858
+ overflow: hidden;
859
+ font-size: 3.8cqw;
860
+ line-height: 1.35;
861
+ text-align: center;
862
+ }
863
+ .fb-page .fb-placed-caption.is-prose {
864
+ display: block;
865
+ font-size: 4.4cqw;
866
+ line-height: 1.55;
867
+ text-align: left;
868
+ text-wrap: pretty;
869
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@toneflix/flipbook",
3
- "version": "0.1.0",
4
- "description": "A photo book for any web page, no framework needed: peel-and-fold page turns, printed photos, frames and paper textures.",
3
+ "version": "0.2.0",
4
+ "description": "Bind photos into a page-turning album on any web page: fingertip page turns, prints set into paper, frames and layouts. No framework needed.",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "repository": {
@@ -42,7 +42,7 @@
42
42
  "dist"
43
43
  ],
44
44
  "dependencies": {
45
- "@toneflix/flipbook-core": "^0.1.0"
45
+ "@toneflix/flipbook-core": "^0.2.0"
46
46
  },
47
47
  "devDependencies": {
48
48
  "tsdown": "^0.23.5",