
:root{--light-gray:rgba(230, 230, 230, 1.00);--medium-gray:rgba(202, 202, 202, 1.00);--dark-gray:rgba(138, 138, 138, 1.00);--black:rgba(10, 10, 10, 1.00);--black-color:var(--black);--white:rgba(254, 254, 254, 1.00);--white-color:var(--white);--primary:rgba(0, 140, 186, 1.00);--secondary:rgba(231, 231, 231, 1.00);--success:rgba(67, 172, 106, 1.00);--warning:rgba(240, 138, 36, 1.00);--alert:rgba(240, 65, 36, 1.00);--primary-contrast:rgba(255, 255, 255, 1.00);--secondary-contrast:rgba(51, 51, 51, 1.00);--success-contrast:rgba(254, 254, 254, 1.00);--warning-contrast:rgba(254, 254, 254, 1.00);--alert-contrast:rgba(254, 254, 254, 1.00);--primary-dark:rgba(0, 110, 156, 1.00);--secondary-dark:rgba(201, 201, 201, 1.00);--success-dark:rgba(37, 142, 76, 1.00);--warning-dark:rgba(210, 108, 6, 1.00);--alert-dark:rgba(210, 35, 6, 1.00);--header-color:rgba(34, 34, 34, 1.00);--subheader-color:rgba(138, 138, 138, 1.00);--small-color:rgba(202, 202, 202, 1.00);--text-color:rgba(34, 34, 34, 1.00);--link-color:rgba(0, 140, 186, 1.00);--link-color-hover:rgba(0, 102, 136, 1.00);--selection-background:var(--primary);--selection-text:var(--primary-contrast);--link-decoration:none;--link-decoration-hover:none;--overlay-color:rgba(0, 0, 0, 0.50);--radius:3px;--small-gutter:1.25rem;--medium-gutter:2rem;--large-gutter:2rem;--site-width:100%;}::selection{background:var(--selection-background);color:var(--selection-text)}.alt{--header-color:rgba(255, 255, 255, 1.00);--subheader-color:rgba(230, 230, 230, 1.00);--small-color:rgba(202, 202, 202, 1.00);--text-color:rgba(255, 255, 255, 1.00);--link-color:rgba(0, 140, 186, 1.00);--link-color-hover:rgba(0, 102, 136, 1.00);--link-decoration:none;--link-decoration-hover:none}.grid-container{max-width:var(--site-width)}.radius{border-radius:var(--radius)}body{font-size:calc(16rem/16)}h1,.h1{font-size:calc(24rem/16)}h2,.h2{font-size:calc(20rem/16)}h3,.h3{font-size:calc(19rem/16)}h4,.h4{font-size:calc(18rem/16)}h5,.h5{font-size:calc(17rem/16)}h6,.h6{font-size:calc(16rem/16)}small{font-size:40%}.button{font-size:calc(16rem/16)}.button.tiny{font-size:calc(10rem/16)}.button.small{font-size:calc(12rem/16)}.button.large{font-size:calc(20rem/16)}@media only screen and (min-width:40em){body{font-size:calc(16rem/16)}h1,.h1{font-size:calc(48rem/16)}h2,.h2{font-size:calc(40rem/16)}h3,.h3{font-size:calc(31rem/16)}h4,.h4{font-size:calc(25rem/16)}h5,.h5{font-size:calc(20rem/16)}h6,.h6{font-size:calc(16rem/16)}small{font-size:30%}}@media only screen and (min-width:64em){body{font-size:calc(16rem/16)}h1,.h1{font-size:calc(48rem/16)}h2,.h2{font-size:calc(40rem/16)}h3,.h3{font-size:calc(31rem/16)}h4,.h4{font-size:calc(25rem/16)}h5,.h5{font-size:calc(20rem/16)}h6,.h6{font-size:calc(16rem/16)}small{font-size:30%}}a{color:var(--link-color);text-decoration:var(--link-decoration)}a:hover,a:focus{color:var(--link-color-hover);text-decoration:var(--link-decoration-hover)}.menu a{color:var(--menu-link-color);background:var(--menu-bg-color)}.menu a:hover{color:var(--menu-link-color-hover)}h1,h2,h3,h4,h5,h6{color:var(--header-color)}small{color:var(--small-color)}.subheader{color:var(--subheader-color)}.text ul,.text ol{list-style-position:outside}.text>ul,.text>ol,.text .mez>div>ul,.text .mez>div>ol{margin-left:1.25rem}.text ul{list-style-type:disc}.text ul ul,.text ol ul{list-style-type:circle}.text ol{list-style-type:decimal}.text ol ol,.text ul ol{list-style-type:lower-alpha}.radius,.radius:before,.radius:after{border-radius:calc(3rem/16)}body{background-color:rgba(0, 0, 0, 0.00);}
/* ---------- shared ---------- */
.c2c_cover2cover {
	position: relative; /* .c2c-edge-nav and .c2c-book-outline are position:absolute
	                        children of THIS element, not of .c2c-live-stage - without
	                        an explicit position here they position relative to
	                        whatever ancestor further up the page happens to be
	                        positioned, escaping the widget's own box and getting
	                        cut off at the page edges instead of the container edges */
	box-sizing: border-box;
	max-width: 100%;
	/* Buttons sit HALF on the page edge (centered exactly on it, not pushed
	   fully outside) - deliberate, to read as different from a lightbox's
	   nav arrows. This still needs to reserve the OUTER half of the button
	   (17px = half of the 34px button) on each side so that half doesn't
	   get clipped - matters most in Fill Parent mode, where whatever wraps
	   this (e.g. Boxed In) clips exactly at the box it computes, with no
	   slack to spare. */
	padding: 0 17px;
}
.c2c_cover2cover * { box-sizing: border-box; }
.c2c_cover2cover:has(> .c2c-fill-wrap) {
	min-width: 0; /* Live mode only: without this, a flex/grid host can
	                 refuse to shrink the stack below its natural content
	                 width, overflowing the viewport when the spread opens
	                 to full stage width - the same flex/grid shrink issue
	                 this build hit twice before. */
}
.c2c_cover2cover:has(> .c2c-editor-grid) {
	/* Editor mode only, and the opposite problem: with no min-width, a
	   flex/grid host (confirmed - a real project's own "Page Turner Bed"
	   layout, not just our test project) can shrink an EMPTY dropzone
	   (no image assigned yet, so no intrinsic content to hold it open) all
	   the way down to a sliver a few pixels wide. This guarantees the
	   editor grid always has a usable minimum footprint regardless of
	   whatever stack it's dropped into. */
	min-width: 300px;
}

/* data-height-mode is a live/Preview-only concept - the editor canvas uses
   .c2c-editor-grid, an entirely different branch of the template, and should
   never be affected by which sizing mode is selected. These are scoped with
   :has(> .c2c-fill-wrap) so they only match when the live-mode wrapper is
   actually in the DOM (i.e. never in the editor), rather than matching
   .c2c_cover2cover directly regardless of which branch rendered. */
.c2c_cover2cover:has(> .c2c-editor-grid) {
	/* Always centered in the editor, regardless of Sizing Mode - Fixed mode
	   happened to center things as an accidental side effect of its own
	   width:fit-content rule below; Fill Width/Fill Parent had no such rule
	   and fell back to default left-aligned block behavior instead. */
	width: fit-content;
	margin: 0 auto;
}
.c2c_cover2cover[data-height-mode="fill"]:has(> .c2c-fill-wrap) {
	/* Defers entirely to whatever box the parent provides (e.g. Boxed In's
	   flex-item + aspect-ratio + max-width/max-height box) instead of
	   computing its own height from its own width like Fill Width mode
	   does. No aspect-ratio math happens at this level at all. */
	height: 100%;
	width: 100%;
}
.c2c-fill-wrap {
	/* Plain, unstyled block in Fill Width mode - transparent, no effect on
	   today's layout. Only becomes meaningful in Fill Parent mode below. */
	width: 100%;
}
.c2c_cover2cover[id="stacks_in_10_2"][data-height-mode="fill"] .c2c-fill-wrap {
	height: 100%;
	width: 100%;
	display: flex;
	align-items: center;
	justify-content: center;
	/* Seed value only - breaks a real circular-measurement deadlock with
	   hosts like Boxed In set to ratio-source:"content". Those hosts
	   determine THEIR OWN height by measuring this element's intrinsic
	   size; without this, .c2c-fill-wrap has none (height:100% of a host
	   that's still trying to derive its height FROM this element resolves
	   to 0, and every descendant is position:absolute/out of flow), so the
	   host computes 0 height, fitStage() then measures 0 and bails out
	   entirely (confirmed via console: "ResizeObserver loop completed with
	   undelivered notifications" - two elements each waiting on the
	   other's size, neither ever contributing a real number). This gives
	   the host something real and page-shaped to measure on first paint.
	   Once fitStage() sets explicit inline px width/height on
	   .c2c-live-stage below, those inline values win over this regardless -
	   this only matters before JS has run. Must match what fitStage()
	   actually sizes to, not a single page - fitStage's bookRatio is the
	   FULL two-page-spread ratio (pageWidth*2 / pageHeight) for any
	   multi-leaf book, since the stage always reserves room for a full
	   spread even when only one leaf (half of it) is showing at rest. Using
	   the single-page ratio here made this seed box roughly 2x taller than
	   the real stage, and centering the correctly-sized book inside a box
	   twice as tall pushed it visibly downward - confirmed live. The
	   data-single-leaf override below corrects this one case where the
	   stage genuinely is single-page width.
	   Scoped with [id="stacks_in_10_2"] (this rule used to be a bare .c2c_cover2cover
	   selector) - confirmed live that without instance scoping, every
	   Cover2Cover instance on a page emits this exact same selector text
	   with its OWN pageWidth/pageHeight baked into the aspect-ratio value,
	   and because the selectors are identical, whichever instance compiles
	   last in the page's stylesheet wins this property for EVERY
	   instance's .c2c-fill-wrap, not just its own - one book's seed ratio
	   silently overriding every other book on the same page. Using the
	   [id="..."] attribute-selector form instead of a bare #id selector
	   deliberately - #id jumps to the ID specificity tier, which outranks
	   the .c2c-live-stage/.c2c-editor-grid override rules below it and
	   broke them the first time this was tried (confirmed live: pages fell
	   out of their absolute-positioned stack into normal flow). [id="..."]
	   matches the same single element but stays in the class-level
	   specificity tier, so it doesn't disturb any existing cascade order. */
	aspect-ratio: calc(600 * 2) / 600;
}
/* Single-leaf books (front/back only, no interior spread) size their stage
   to ONE page, not a spread - see cover2cover.js stageRatio/stageWidthUnits.
   data-single-leaf is set synchronously by JS before first paint, same
   timing as data-height-mode, so this resolves correctly even on the very
   first style pass. Scoped with [id="stacks_in_10_2"] for the same cross-instance
   leak reason as the rule above (see that comment for why the
   attribute-selector form and not #id). */
.c2c_cover2cover[id="stacks_in_10_2"][data-single-leaf="true"][data-height-mode="fill"] .c2c-fill-wrap {
	aspect-ratio: 600 / 600;
}
.c2c_cover2cover[data-height-mode="fill"] .c2c-live-stage {
	/* width/height are computed and set inline in px by cover2cover.js's
	   fitStage(), not derived here via aspect-ratio. Confirmed via direct
	   measurement that the CSS-only flex+aspect-ratio+max-width technique
	   (matching Boxed In's own approach) only ties width and height
	   together correctly when max-height is the binding constraint - when
	   a container is proportionally WIDER than the book (max-width binds
	   instead), the two dimensions stop tracking each other and the book
	   gets cropped rather than letterboxed. JS measurement doesn't have
	   that failure mode. This rule just prevents the base .c2c-live-stage
	   {width:100%} rule from flashing before fitStage() runs on first paint. */
	width: auto;
}
.c2c_cover2cover[data-height-mode="fixed"]:has(> .c2c-fill-wrap) {
	/* Non-responsive: hug the fixed-pixel stage (set inline by JS) instead
	   of stretching to whatever width the parent offers. max-width:100% is
	   intentionally NOT set here - "fixed" means genuinely fixed, even if
	   that means horizontal scroll on a narrow viewport, rather than
	   quietly becoming responsive again. */
	width: fit-content;
	margin: 0 auto;
}
.c2c_cover2cover[data-height-mode="fixed"] .c2c-fill-wrap {
	width: fit-content;
}
.c2c_cover2cover[data-height-mode="fixed"] .c2c-live-stage {
	/* width/height are set inline in px by cover2cover.js - this just
	   prevents the base .c2c-live-stage{width:100%} rule from fighting it
	   before JS runs on first paint. */
	width: auto;
}

/* ---------- editor grid (side-by-side dropzones per pair, one pair per row) ---------- */
/* Restructured: c2c_page now owns BOTH faces of a leaf directly (frontImage +
   backImage, two named image controls in its own plist/template), instead of
   being one flat dropzone that had to be paired with a sibling instance from
   outside. That eliminates the entire problem this file used to fight -
   guessing how deep Stacks nests its own per-instance wrapper chrome. Front
   and back are now just two divs inside markup we wrote ourselves
   (c2c_page.html), so this is plain, ordinary CSS with no dependency on
   Stacks' internal structure at all. */
.c2c-editor-grid .c2c-leaf {
	display: flex;
	width: 280px;
	max-width: 100%;
	min-width: 240px; /* defense in depth alongside .c2c_cover2cover's own
	                      min-width above - this sits several DOM levels
	                      further down (past Stacks' own repeater wrapper),
	                      so protecting here too covers a host layout that
	                      shrinks something in between rather than
	                      .c2c_cover2cover itself. */
	border: 2px solid #999;
	border-radius: 4px;
	overflow: visible; /* was hidden - clipped Stacks' own native empty-%image%
	                       placeholder (icon + two lines of text), which needs
	                       more vertical room than a thumbnail does. Safe to
	                       open up: actual thumbnails are still bounded by
	                       object-fit:contain on the img below, so nothing
	                       populated can spill past this box regardless. */
	margin: 0 0 16px;
}
/* c2c-leaf-inner exists for the live-stage 3D split below (position:absolute
   and transform-style:preserve-3d must live on separate elements - confirmed
   via live devtools toggling, a real WebKit collision, not a styling choice).
   In the editor grid there's no 3D anything, so this wrapper should behave
   as if it isn't there at all, leaving the existing flex layout untouched. */
.c2c-editor-grid .c2c-leaf-inner {
	display: contents;
}
[id="stacks_in_10_2"] .c2c-editor-grid .c2c-face-slot {
	/* Scoped with [id="stacks_in_10_2"] purely to keep this rule's specificity ahead
	   of the also-now-scoped base .c2c-face-slot rule below - this override
	   has no %id=-templated value of its own, so it wasn't part of the
	   cross-instance leak, but it still needs to keep winning the cascade
	   against the base rule now that the base rule picked up a scope. */
	flex: 1 1 50%;
	min-width: 0;
	aspect-ratio: auto; /* override the shared square aspect-ratio, which was fighting the flex centering below */
	min-height: 160px; /* was a fixed height:120px with overflow:hidden - too
	                       short for Stacks' native "Drop an image here" empty
	                       state (icon + two lines of text), which was getting
	                       clipped top and bottom. min-height instead of height
	                       lets it grow to fit that content; thumbnails once
	                       assigned still render at a consistent size via
	                       object-fit:contain below, not by this box shrinking. */
	overflow: visible; /* was hidden, same reason as .c2c-leaf above */
	display: flex;
	align-items: center;
	justify-content: center;
}
.c2c-editor-grid .c2c-face-front {
	border-right: 1px solid #ccc;
}
.c2c-editor-grid .c2c-face-slot img {
	max-width: 100%;
	max-height: 160px;
	object-fit: contain;
	display: block;
	margin: auto;
}
/* .c2c-dropzone-placeholder removed - that div doesn't exist anymore. It was
   c2c_page's own %[if "" == ""]% conditional label, tied to
   the named image controls. c2c_face has no named control to check emptiness
   against, so the empty state you see now is entirely Stacks' own built-in
   %image% placeholder UI, not something this stylesheet generates or
   controls the markup of. */

[id="stacks_in_10_2"] .c2c-face-slot {
	/* Scoped with [id="stacks_in_10_2"] (this rule used to be a bare .c2c-face-slot
	   selector) - same cross-instance aspect-ratio leak as the fill-wrap
	   rules above: c2c-face-slot elements belong to the nested c2c_page
	   stack, not this file, but this rule's aspect-ratio is templated with
	   THIS Cover2Cover instance's own pageWidth/pageHeight, so it has to be
	   scoped to only this instance's own descendants or it leaks its ratio
	   onto every other book's pages on the same page. Using the
	   attribute-selector form [id="..."] rather than #id - #id jumps to a
	   higher specificity tier that outranks the .c2c-live-stage/
	   .c2c-editor-grid overrides just below, which broke live rendering
	   (pages fell out of their absolute-positioned stack into normal flow)
	   the first time this was scoped with #id. [id="..."] matches the same
	   element but stays at class-level specificity, so those overrides keep
	   winning exactly as before. */
	position: relative;
	width: 100%;
	aspect-ratio: 600 / 600;
	background: var(--c2c-empty-bg, #ddd);
}

/* frontImage/backImage are gone - front/back are now c2c_face child stacks
   whose entire content is the native %image% variable, which wraps its
   <img> in a .centered_image div (confirmed via live DOM inspection -
   different from the old named image control's bare <img>). Making the
   <img> below position:absolute pulls it out of flow, so .centered_image
   is left with no content to size against and collapses to 0x0 - if it
   clips overflow (it's Stacks' own default wrapper, not ours), that
   zero-size box clips the correctly-positioned image to nothing even
   though DOM inspection shows a valid src and correct inline visibility.
   Confirmed as the live-stage blank-render cause this session. Fix:
   give .centered_image the same absolute-fill box as the image itself,
   so there's a real, non-zero box before overflow can clip anything. */
.c2c-live-stage .c2c-face-slot .centered_image {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	overflow: visible;
}
.c2c-live-stage .c2c-face-slot img {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
	border-radius: 4px;
	/* Matches Pagelit's actual split exactly: overflow:hidden lives on the
	   rotating container (.page there, .c2c-face-slot here), backface-
	   visibility:hidden lives on the descendant image (.pglt-image there,
	   this <img> here) - never both on the same element. */
	backface-visibility: hidden;
	-webkit-backface-visibility: hidden;
}

/* ---------- live stage ---------- */
.c2c-live-stage {
	position: relative;
	width: 100%;
	margin: 0 auto;
}
/* Confirmed via live devtools toggling: position:absolute and 3D transform
   properties (transform-style:preserve-3d, and by extension the rotation
   that goes with it) colliding on the SAME element is what was causing
   nothing to paint at rest - toggling either one off made the image appear
   immediately. The fix is splitting them across two elements: .c2c-leaf does
   ONLY absolute positioning (no 3D properties at all), .c2c-leaf-inner does
   ONLY the 3D rotation (no absolute positioning), sized to fill its parent. */
[id="stacks_in_10_2"] .c2c-live-stage .c2c-leaf {
	/* Scoped with [id="stacks_in_10_2"] (this rule used to be a bare .c2c-live-stage
	   .c2c-leaf selector) - same cross-instance aspect-ratio leak as above,
	   and the attribute-selector form for the same reason: #id would
	   outrank .c2c_cover2cover[data-single-leaf="true"] .c2c-live-stage
	   .c2c-leaf below, which needs to keep overriding this rule's width
	   for single-leaf books. */
	position: absolute;
	top: 0;
	width: 50%;
	height: 100%;
	aspect-ratio: 600 / 600;
	z-index: 5;
	/* Matches Pagelit's actual working structure exactly (their .anim rule):
	   position:absolute AND transform-style:preserve-3d on the SAME element
	   is fine - that combination was never the real bug. The real fix,
	   confirmed by reading Pagelit's shipped CSS, is that perspective must
	   live on the DIRECT parent of the element that actually gets the
	   rotate transform (their .anim-inner.pglt-move, one level above
	   .page) - not two levels up on the stage. See perspective below. */
	transform-style: preserve-3d;
	-webkit-transform-style: preserve-3d;
	perspective: 1800px;
	-webkit-perspective: 1800px;
}
/* Single-leaf book (front/back only, no interior spread possible): the
   stage itself is already sized to one page's width (see cover2cover.js
   stageRatio/stageWidthUnits), so the leaf must fill 100% of it instead of
   the 50% that's correct when the stage is a full two-page spread. */
.c2c_cover2cover[data-single-leaf="true"] .c2c-live-stage .c2c-leaf {
	width: 100%;
}
.c2c-live-stage .c2c-leaf-inner {
	position: relative;
	width: 100%;
	height: 100%;
	transform-style: preserve-3d;
	-webkit-transform-style: preserve-3d;
}
[id="stacks_in_10_2"] .c2c-live-stage .c2c-face-slot {
	/* Scoped with [id="stacks_in_10_2"] for the same reason as .c2c-editor-grid
	   .c2c-face-slot above - keeps this override ahead of the now-scoped
	   base .c2c-face-slot rule. This is the rule that actually stacks each
	   page absolutely and rotates it into view; losing this cascade fight
	   is what broke live rendering last time. */
	position: absolute;
	top: 0; left: 0;
	width: 100%;
	height: 100%;
	padding-top: 0;
	max-width: none;
	min-width: 0;
	border: none;
	border-radius: 4px;
	background: var(--c2c-empty-bg, #ddd);
	overflow: hidden;
	box-shadow: 0 2px 10px rgba(0,0,0,0.2);
	will-change: transform;
}
/* Faces get permanent, fixed rotations here and are never touched by JS
   again - matching Flipper's actual working CSS exactly (its
   .augmentFlipFace.augmentFlipFront/.augmentFlipBack rules do the same:
   fixed rotateY per face, always, in the stylesheet). JS only ever rotates
   the LEAF itself between 0deg/180deg to decide which fixed-rotation face
   nets forward. translateZ(0) forces a real GPU layer per face. */
.c2c-live-stage .c2c-face-front {
	transform: rotateY(0deg) translateZ(0);
}
.c2c-live-stage .c2c-face-back {
	transform: rotateY(180deg) translateZ(0);
}
.c2c-live-stage .c2c-face-slot::before { content: none; }

.c2c-book-outline {
	position: absolute;
	top: 0;
	bottom: 0; /* was height:100% - percentage height on an absolutely
	              positioned child of an auto-height parent is genuinely
	              ambiguous in the CSS spec and gets resolved inconsistently
	              (confirmed: measured 914px against a 782px parent). top+
	              bottom stretch is unambiguous in every browser, no
	              percentage resolution involved. */
	background: transparent;
	box-shadow: 0 4px 18px rgba(0,0,0,0.2);
	border-radius: 4px;
	pointer-events: none;
	z-index: 1;
}

.c2c-edge-nav {
	position: absolute;
	top: 50%;
	width: 34px;
	height: 34px;
	margin-top: -17px;
	border-radius: 50%;
	background: var(--c2c-nav-color, rgba(20,20,20,0.55));
	display: flex;
	align-items: center;
	justify-content: center;
	cursor: pointer;
	z-index: 20;
	transition: opacity 0.15s ease, filter 0.15s ease;
	user-select: none;
}
.c2c-edge-nav svg { width: 14px; height: 14px; fill: #fff; }
/* brightness filter instead of a second hardcoded color - works regardless
   of whichever color the Nav Button Color picker is set to */
.c2c-edge-nav:hover { filter: brightness(1.3); }
.c2c-edge-nav.c2c-hidden { opacity: 0; pointer-events: none; }