@font-face{font-family:Jost;src:url(assets/fonts/jost-latin-400-normal.woff2);font-weight:400;font-display:swap}@font-face{font-family:Jost;src:url(assets/fonts/jost-latin-600-normal.woff2);font-weight:600;font-display:swap}@font-face{font-family:CardSerif;src:url(assets/fonts/cormorant-garamond-latin-600-normal.woff2);font-weight:600;font-display:swap}@font-face{font-family:CardScript;src:url(assets/fonts/great-vibes-latin-400-normal.woff2);font-display:swap}
:root{--brand:#35b2b6;--brand-dark:#0d6a6d;--soft:#eaf6f6;--primary:#35b2b6;--on-primary:#10151b;--ink:#10151b;--muted:#4b5563;--line:#e5e7eb;--page:#f5f0eb;--surface:#fff;--subtle:#faf7f4;--danger:#b91c1c;--ui:Roboto,system-ui,sans-serif;--radius:8px;--shadow:0 8px 28px -12px #0f151b28;--motion:240ms}
[data-brand=orwo]{--brand:#06acda;--brand-dark:#05647e;--soft:#e4f7fc;--primary:#10151b;--on-primary:#fff;--page:#f5f0eb;--subtle:#faf7f4;--ui:Roboto,system-ui,sans-serif}
*{box-sizing:border-box}body{margin:0;color:var(--ink);font:15px/1.45 var(--ui);background:var(--surface)}button,input,select,textarea{font:inherit;color:inherit}button,a,input,select,textarea{-webkit-tap-highlight-color:transparent}button{cursor:pointer}button:disabled{opacity:.45;cursor:not-allowed}button:focus-visible,a:focus-visible,select:focus-visible,input:focus-visible,textarea:focus-visible{outline:3px solid var(--brand-dark);outline-offset:3px}button{border:0;background:none}a{color:var(--brand-dark)}h1,h2,h3,p{margin:0}h1{font-size:34px;line-height:1.18;font-weight:600;letter-spacing:-.035em}h2{font-size:24px;line-height:1.25;letter-spacing:-.02em}h3{font-size:17px;font-weight:600}small,.small{font-size:13px}.muted{color:var(--muted)}.eyebrow{font-size:11px;letter-spacing:.12em;text-transform:uppercase;font-weight:600;color:var(--brand-dark)}.icon{width:20px;height:20px;flex-shrink:0;vertical-align:middle}.btn{min-height:44px;padding:10px 18px;border-radius:6px;display:inline-flex;gap:8px;align-items:center;justify-content:center;font-weight:600;white-space:normal;border:1.5px solid transparent;text-decoration:none}.btn.primary{background:var(--primary);color:var(--on-primary)}.btn.primary:hover{filter:brightness(.91)}.btn.secondary{border-color:var(--line);background:white}.btn.secondary:hover{border-color:var(--brand-dark);background:var(--soft)}.btn.quiet{padding:10px 12px;color:var(--muted)}.btn.quiet:hover{background:#f3f4f6}.btn.full{width:100%}.icon-btn{width:44px;height:44px;display:inline-grid;place-items:center;border-radius:6px;border:1px solid var(--line);background:white}.icon-btn:hover{background:var(--soft)}.chip{min-height:44px;padding:8px 15px;border-radius:999px;white-space:nowrap;border:1px solid var(--line);background:white;font-size:13px}.chip[aria-pressed=true]{background:var(--soft);border-color:var(--brand-dark);color:var(--brand-dark);font-weight:600}.field{width:100%;height:44px;border:1.5px solid #b8bec5;border-radius:6px;background:white;padding:0 13px;min-width:0}textarea.field{height:118px;padding-top:12px;resize:vertical}.field:focus{border-color:var(--brand-dark)}label.label{font-size:13px;font-weight:600;display:block;margin:0 0 7px}.row{display:flex;align-items:center;gap:10px}.between{justify-content:space-between}.stack{display:grid;gap:16px}.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0,0,0,0)}
#reviewer{background:#f3f4f6;border-bottom:1px solid var(--line);min-height:38px;padding:3px 28px;display:flex;align-items:center;justify-content:space-between;gap:8px;font-size:11px;color:#4b5563}.review-tools{display:flex;gap:8px;align-items:center}.review-tools select{border:1px solid #d1d5db;border-radius:4px;background:white;padding:3px 8px;font-size:12px;height:29px}.proto-label{letter-spacing:.07em;text-transform:uppercase}.review-notice{margin-left:15px;letter-spacing:0;text-transform:none}.review-tools button{font-size:11px;text-decoration:underline;min-height:30px}#header{min-height:78px;display:flex;align-items:center;justify-content:space-between;padding:12px 4vw;gap:24px;border-bottom:1px solid var(--line);background:white}.brand-logo{width:145px;height:34px;object-fit:contain;object-position:left center}.brand-logo.orwo{width:76px;height:45px}.brand-button{display:flex;align-items:center;min-height:44px;padding:0}.steps{display:flex;align-items:center;gap:22px;color:var(--muted);font-size:13px}.step{display:flex;align-items:center;gap:8px}.step b{border:1px solid #c2c8cb;border-radius:50%;width:26px;height:26px;display:grid;place-items:center;font-size:12px;font-weight:500}.step.active{color:var(--brand-dark);font-weight:600}.step.active b,.step.done b{background:var(--primary);border-color:var(--primary);color:white}.step-line{width:34px;height:1px;background:var(--line)}.header-actions{display:flex;align-items:center;gap:10px}.lang-btn{min-height:44px;padding:8px 12px;border-radius:999px;border:1px solid var(--line);font-size:13px}.saved{font-size:12px;color:var(--muted);display:flex;align-items:center;gap:5px}.saved .icon{width:16px;height:16px}
.gallery{background:var(--page);min-height:calc(100vh - 116px);padding:38px 4vw 40px}.gallery-top{display:flex;justify-content:space-between;gap:30px;align-items:center;max-width:1360px;margin:auto}.gallery-top h1{margin:8px 0 10px}.gallery-top p{max-width:570px;color:var(--muted)}.upload-hero{width:350px;flex-shrink:0;display:flex;align-items:center;gap:15px;border:1px dashed #91b1ad;border-radius:12px;padding:16px;background:#ffffffb3}.upload-hero p{font-size:12px;line-height:1.4;margin-top:4px}.upload-hero .btn{margin-top:10px;padding:6px 10px;min-height:38px;font-size:13px}.upload-hero .upload-symbol{width:57px;height:66px;border-radius:6px;background:var(--soft);display:grid;place-items:center;flex-shrink:0;color:var(--brand-dark);overflow:hidden}.upload-symbol img{width:100%;height:100%;object-fit:cover}.format-grid{max-width:1360px;margin:28px auto;display:grid;grid-template-columns:repeat(4,1fr);gap:12px}.format-card{position:relative;text-align:left;display:flex;align-items:center;gap:13px;padding:16px;background:white;border:1.5px solid transparent;border-radius:8px;box-shadow:0 1px 2px #10151b05;min-height:100px}.format-card.selected{border-color:var(--brand-dark);background:var(--soft)}.format-card .format-title{font-size:15px;font-weight:600;display:block}.format-card small{display:block;color:var(--muted);font-size:12px;margin:3px 0}.format-card strong{font-size:14px}.format-card .check{position:absolute;right:10px;top:8px;color:var(--brand-dark);width:16px;height:16px}.format-glyph{width:45px;height:39px;display:grid;place-items:center;flex-shrink:0}.format-glyph span{display:block;border:1.5px solid var(--brand-dark);background:white;position:relative;box-shadow:3px 3px 0 #b9d3d0}.format-glyph span.folded:before{content:'';position:absolute;width:14%;inset:0 auto 0 0;background:var(--soft);border-right:1px solid var(--brand-dark)}.gallery-controls{max-width:1360px;margin:0 auto 20px;display:flex;gap:16px;align-items:center;justify-content:space-between}.filters{display:flex;gap:7px;flex-wrap:wrap}.search{max-width:270px;flex:1;min-width:200px;position:relative}.search .icon{position:absolute;left:12px;top:12px;color:var(--muted);width:18px}.search input{padding-left:39px;border-color:var(--line)}.grid-head{max-width:1360px;margin:0 auto 16px;font-size:13px;color:var(--muted);display:flex;justify-content:space-between;gap:20px}.design-grid{max-width:1360px;margin:auto;display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:22px}.design-tile{position:relative;background:white;border:1px solid #e3e3df;border-radius:10px;overflow:hidden;transition:transform var(--motion),box-shadow var(--motion)}.design-tile:hover{transform:translateY(-3px);box-shadow:var(--shadow)}.tile-image{display:flex;width:100%;height:215px;align-items:center;justify-content:center;background:#fff;padding:25px 15px}.tile-image img{max-width:100%;max-height:100%;object-fit:contain;filter:drop-shadow(0 8px 5px #10151b15)}.tile-footer{padding:14px 16px;border-top:1px solid #f0f1f2;display:flex;align-items:center;justify-content:space-between;gap:10px}.tile-footer h3{font-size:15px;margin-bottom:3px}.tile-footer small{font-size:12px;color:var(--muted)}.tile-go{width:36px;height:36px;display:grid;place-items:center;color:var(--brand-dark);border-radius:50%;background:var(--soft);flex-shrink:0}.tile-action{position:absolute;inset:0;width:100%;height:100%;border-radius:10px}.tile-action:focus-visible{outline-offset:-4px}.gallery-bottom{text-align:center;padding:26px}.gallery-bottom .btn{background:white;min-width:200px}.empty-state{grid-column:1/-1;text-align:center;padding:60px 20px;background:white;border-radius:12px}.empty-state p{margin:12px 0}.resume{max-width:1360px;margin:0 auto 20px;padding:14px 18px;background:white;border:1px solid var(--brand-dark);border-radius:8px;display:flex;align-items:center;justify-content:space-between;gap:15px}.resume p{font-size:13px;color:var(--muted)}
.editor-top{display:flex;align-items:center;justify-content:space-between;gap:15px;padding:13px 28px;border-bottom:1px solid var(--line);background:white}.editor-top h1{font-size:20px;letter-spacing:-.02em}.editor-top .project-name{display:flex;align-items:center;gap:14px}.editor-top .field{width:auto;max-width:245px;font-size:13px}.edit-layout{display:grid;grid-template-columns:310px minmax(0,1fr);min-height:calc(100vh - 266px)}.sidebar{border-right:1px solid var(--line);background:white;display:flex;flex-direction:column;min-width:0}.tabs{padding:16px 18px 0;display:flex;gap:5px;border-bottom:1px solid var(--line)}.tab{flex:1;min-height:48px;border-bottom:3px solid transparent;display:flex;gap:8px;align-items:center;justify-content:center;font-size:14px;color:var(--muted)}.tab[aria-selected=true]{border-color:var(--brand-dark);color:var(--brand-dark);font-weight:600}.panel{padding:22px 20px;display:grid;gap:20px;align-content:start}.panel h3{margin-bottom:6px}.panel p{color:var(--muted);font-size:13px}.panel .section{border-top:1px solid var(--line);padding-top:18px}.photo-tray{display:grid;grid-template-columns:repeat(3,1fr);gap:7px;margin-top:12px}.photo-thumb{aspect-ratio:1;border-radius:6px;overflow:hidden;padding:0;border:2px solid transparent;position:relative;background:#f3f4f6}.photo-thumb img{width:100%;height:100%;object-fit:cover}.photo-thumb[aria-pressed=true]{border-color:var(--brand-dark)}.photo-thumb small{position:absolute;bottom:0;left:0;right:0;background:#fffef2ed;color:#4b5563;font-size:10px;padding:2px}.range-row{display:grid;gap:8px}.range-head{display:flex;justify-content:space-between;font-size:13px}.range-head output{color:var(--muted)}input[type=range]{width:100%;accent-color:var(--brand-dark);height:25px}.crop-grid{display:grid;gap:13px}.swatches{display:flex;gap:8px;flex-wrap:wrap}.swatch{width:32px;height:32px;border:3px solid white;outline:1px solid #c3c9c7;border-radius:50%}.swatch[aria-pressed=true]{outline:2px solid var(--brand-dark)}.text-fields{display:grid;gap:6px}.text-field-btn{text-align:left;padding:12px;border:1px solid var(--line);border-radius:6px;min-height:44px;font-size:13px}.text-field-btn[aria-pressed=true]{border-color:var(--brand-dark);background:var(--soft)}.help-inline{font-size:12px!important;color:var(--muted);padding:12px;border-radius:6px;background:#f6f7f8}.sample-toggle{font-size:13px;color:var(--brand-dark);text-decoration:underline;min-height:44px;text-align:left;padding:0}.reference{padding:14px;background:var(--subtle);border:1px solid var(--line);border-radius:8px;display:flex;gap:12px;align-items:center;text-align:left;min-width:0}.reference img{width:66px;height:55px;object-fit:contain}.reference span{font-size:12px}.workspace{background:#f3f4f6;position:relative;display:flex;flex-direction:column;align-items:center;min-width:0;padding:22px 30px 14px}.workspace-toolbar{display:flex;justify-content:space-between;align-items:center;width:100%;gap:15px}.segmented{background:white;border:1px solid var(--line);border-radius:8px;padding:3px;display:flex}.segmented button{padding:8px 14px;min-height:38px;border-radius:5px;font-size:13px;display:flex;gap:7px;align-items:center}.segmented button[aria-pressed=true]{background:var(--ink);color:white}.workspace-tools{display:flex;gap:7px}.stage{width:100%;flex:1;min-height:360px;display:flex;align-items:center;justify-content:center;padding:30px 10px;perspective:1800px}.paper-wrap{position:relative;width:100%;max-width:570px;aspect-ratio:var(--ratio);transition:transform 400ms ease;filter:drop-shadow(0 20px 15px #1f242920)}.paper-wrap.portrait{max-width:300px}.paper-wrap.wide{max-width:640px}.paper-wrap svg{display:block;width:100%;height:100%;background:white}.paper-wrap [data-slot],.paper-wrap [data-text]{cursor:pointer}.paper-wrap [data-slot]:focus,.paper-wrap [data-text]:focus{outline:none;stroke:var(--brand-dark);stroke-width:4px}.canvas-hint{text-align:center;font-size:12px;color:var(--muted);margin-bottom:18px;max-width:480px}.side-tabs{display:flex;gap:12px;align-items:flex-start;justify-content:center;width:100%;padding:8px 0 10px}.side-tab{display:flex;flex-direction:column;align-items:center;gap:7px;font-size:11px;color:var(--muted);border-bottom:2px solid transparent;padding:5px 7px 10px;min-width:64px}.side-tab[aria-pressed=true]{color:var(--brand-dark);border-color:var(--brand-dark)}.side-tab svg{width:56px;height:40px;object-fit:contain;background:white;border:1px solid var(--line);box-shadow:0 1px 3px #10151b08}.side-tab.portrait svg{width:30px;height:42px}.editor-footer{position:sticky;bottom:0;z-index:10;background:white;border-top:1px solid var(--line);padding:13px 28px;display:flex;align-items:center;justify-content:space-between;gap:18px;box-shadow:0 -5px 15px #10151b04}.order-summary strong{display:block;font-size:15px}.order-summary small{display:block;font-size:12px;color:var(--muted);margin-top:3px}.price-group{display:flex;align-items:center;gap:22px}.price{text-align:right}.price strong{font-size:22px;letter-spacing:-.025em}.price small{display:block;font-size:11px;color:var(--muted)}.check-row{display:flex;gap:9px;align-items:flex-start;font-size:13px}.check-row input{margin-top:3px;accent-color:var(--brand-dark);width:17px;height:17px;flex-shrink:0}.photo-warning{color:#805500!important;background:#fff9e8;padding:10px;border-radius:6px}.danger{color:var(--danger)}.text-counter{font-size:11px;color:var(--muted);text-align:right;margin-top:4px}
.preview-object{position:relative;transform-style:preserve-3d;width:100%;height:100%;transform:rotateY(var(--turn,0deg));transition:transform 700ms cubic-bezier(.2,.85,.25,1)}.preview-panel{position:absolute;inset:0;transform-style:preserve-3d}.preview-panel.cover{transform-origin:left;transform:translateZ(1px) rotateY(var(--fold,0deg));transition:transform 700ms ease}.preview-face{position:absolute;inset:0;backface-visibility:hidden;-webkit-backface-visibility:hidden;box-shadow:0 1px 3px #10151b20}.preview-face.reverse{transform:rotateY(180deg)}.preview-face svg{width:100%;height:100%}.paper-wrap.opened{transform:scale(.64) translateX(30%)}.paper-wrap.preview-flat{transform:rotateX(5deg) rotateY(-9deg)}
.review-page{max-width:1250px;margin:auto;padding:28px 4vw 60px}.review-heading{margin:22px 0 28px}.review-heading p{color:var(--muted);margin-top:10px}.review-columns{display:grid;grid-template-columns:minmax(0,1fr) 330px;gap:34px;align-items:start}.review-pages{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:24px}.review-card{background:var(--subtle);border:1px solid var(--line);padding:22px;border-radius:10px;min-width:0}.review-card svg{display:block;width:100%;max-height:250px;background:white;filter:drop-shadow(0 5px 5px #10151b17)}.review-card .row{margin-top:15px}.review-card p{font-size:13px}.review-card button{font-size:12px;color:var(--brand-dark);text-decoration:underline;min-height:44px}.summary-box{border:1px solid var(--line);border-radius:12px;padding:22px;display:grid;gap:18px;position:sticky;top:20px}.summary-line{display:flex;justify-content:space-between;gap:15px;font-size:13px}.summary-line.total{padding-top:18px;border-top:1px solid var(--line);font-size:18px;font-weight:600}.quantity{display:flex;align-items:center;gap:16px}.quantity button{width:36px;height:36px;border:1px solid var(--line);border-radius:5px}.notice{padding:12px;border-radius:6px;font-size:12px;background:var(--soft);color:var(--brand-dark)}.issues{display:grid;gap:8px}.issue{font-size:12px;color:#805500;background:#fff9e8;padding:11px;border-radius:6px;display:flex;gap:8px;align-items:center;text-align:left}.issue .icon{width:18px}.done-page{text-align:center;padding:55px 20px;max-width:760px;margin:auto}.done-icon{width:70px;height:70px;border-radius:50%;background:var(--soft);color:var(--brand-dark);display:grid;place-items:center;margin:0 auto 24px}.done-icon .icon{width:32px;height:32px}.done-page p{margin:15px 0 26px;color:var(--muted)}.done-preview{max-width:380px;margin:28px auto;filter:drop-shadow(0 10px 12px #10151b22)}.done-page .row{justify-content:center;flex-wrap:wrap}
dialog{border:0;border-radius:12px;box-shadow:0 25px 90px #10151b40;padding:0;width:min(690px,calc(100vw - 28px));max-height:90vh;color:var(--ink);background:white}dialog::backdrop{background:#10151b65;backdrop-filter:blur(3px)}.dialog-head{display:flex;justify-content:space-between;align-items:center;padding:18px 22px;border-bottom:1px solid var(--line);gap:20px}.dialog-head h2{font-size:20px}.dialog-body{padding:24px}.dialog-body p{color:var(--muted);margin-bottom:18px;font-size:14px}.dialog-body .choices{display:grid;grid-template-columns:1fr 1fr;gap:12px}.choice{padding:24px 14px;border:1px solid var(--line);border-radius:8px;display:grid;gap:12px;text-align:center;justify-items:center;min-height:125px}.choice:hover{background:var(--soft);border-color:var(--brand-dark)}.choice .icon{width:28px;height:28px}.dialog-footer{padding:16px 22px;border-top:1px solid var(--line);display:flex;justify-content:flex-end;gap:10px}.reference-image{display:block;max-height:430px;max-width:100%;margin:0 auto 22px;object-fit:contain}.reference-images{display:flex;gap:15px;overflow:auto}.reference-images img{height:180px;max-width:250px;object-fit:contain}.dialog-body .model-image{width:100%;height:340px;object-fit:contain;background:var(--subtle);border-radius:8px}.model-switch{display:flex;gap:6px;margin-top:15px;flex-wrap:wrap}#toast{position:fixed;bottom:95px;left:50%;transform:translate(-50%,18px);padding:13px 22px;border-radius:8px;background:#172923;color:white;box-shadow:var(--shadow);z-index:100;max-width:min(600px,92vw);opacity:0;pointer-events:none;transition:opacity 180ms,transform 180ms;font-size:13px}#toast.show{opacity:1;transform:translate(-50%,0)}body.is-fullscreen .sidebar,body.is-fullscreen #header,body.is-fullscreen #reviewer,body.is-fullscreen .editor-top{display:none}body.is-fullscreen .edit-layout{grid-template-columns:1fr;min-height:calc(100vh - 88px)}body.is-fullscreen .paper-wrap{max-width:800px}body.is-fullscreen .paper-wrap.portrait{max-width:400px}
@media(min-width:1600px){.edit-layout{grid-template-columns:340px 1fr}.stage{min-height:480px}.paper-wrap{max-width:700px}.paper-wrap.portrait{max-width:350px}}
@media(max-width:1100px){.design-grid{grid-template-columns:repeat(3,minmax(0,1fr))}.format-card{padding:13px 10px;gap:8px}.format-glyph{width:35px}.steps{gap:12px}.step-line{width:15px}.saved{display:none}.gallery-controls{align-items:flex-start}.filters{gap:5px}.chip{font-size:12px;padding:8px 11px}.edit-layout{grid-template-columns:280px minmax(0,1fr)}.workspace{padding:20px}.stage{min-height:335px}.editor-top{padding:12px 20px}.review-columns{grid-template-columns:minmax(0,1fr) 300px;gap:22px}}
@media(max-width:760px){#reviewer{padding:5px 16px}.review-notice{display:none}.review-tools button{display:none}#header{min-height:68px;padding:10px 16px;gap:12px}.brand-logo{width:117px;height:29px}.brand-logo.orwo{width:57px;height:36px}.steps{gap:6px;font-size:11px}.step{gap:5px}.step b{width:23px;height:23px;font-size:11px}.step:not(.active) .step-name{display:none}.step-line{width:10px}.header-actions{gap:0}.header-actions>.btn{display:none}.lang-btn{padding:8px;border:0}.gallery{padding:25px 16px}.gallery-top{display:block}.gallery-top h1{font-size:28px;max-width:430px}.gallery-top p{font-size:14px}.upload-hero{width:100%;margin-top:20px;padding:12px;gap:12px}.upload-hero .upload-symbol{height:46px;width:46px}.upload-hero p{display:none}.upload-hero>div:last-child{display:flex;align-items:center;justify-content:space-between;gap:14px;flex:1}.upload-hero h3{font-size:13px}.upload-hero .btn{margin:0;min-height:44px;flex-shrink:0}.format-grid{grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;margin:20px auto}.format-card{min-height:92px;padding:12px 10px}.format-card .format-title{font-size:13px}.format-card small{font-size:11px}.format-glyph{width:33px}.format-card strong{font-size:13px}.gallery-controls{display:flex;flex-direction:column;gap:14px}.filters{max-width:100%;flex-wrap:nowrap;overflow:auto;width:100%;padding:4px 2px}.chip{font-size:13px}.search{width:100%;max-width:none}.grid-head{font-size:12px}.design-grid{grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}.tile-image{height:168px;padding:16px 10px}.tile-footer{padding:11px 12px;gap:5px}.tile-footer h3{font-size:13px}.tile-footer small{font-size:11px}.tile-go{width:26px;height:26px}.tile-go .icon{width:16px}.resume{align-items:flex-start}.resume .btn{font-size:12px;flex-shrink:0}.editor-top{padding:9px 16px;gap:8px}.editor-top h1{font-size:15px;max-width:140px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.editor-top .project-name{gap:8px}.editor-top .project-name>.btn{padding:8px 0;font-size:0}.editor-top .field{font-size:12px;max-width:140px;height:40px;padding:0 6px}.edit-layout{display:flex;flex-direction:column;min-height:auto}.workspace{order:0;padding:14px 16px 7px}.sidebar{order:1;border-right:0;border-top:1px solid var(--line)}.workspace-toolbar{gap:6px}.segmented button{padding:8px 10px;font-size:12px}.workspace-tools .icon-btn{width:38px;height:38px}.workspace-tools{gap:4px}.stage{min-height:260px;max-height:365px;padding:23px 8px}.paper-wrap{max-width:460px}.paper-wrap.portrait{max-width:200px}.paper-wrap.wide{max-width:500px}.canvas-hint{margin-bottom:6px;font-size:11px}.side-tabs{gap:8px;padding:4px 0}.side-tab{padding:5px 4px;min-width:57px;font-size:10px}.side-tab svg{width:44px;height:32px}.side-tab.portrait svg{width:24px;height:33px}.tabs{padding:0 16px}.tab{min-height:48px}.panel{padding:18px 20px;gap:16px}.panel .photo-tray{grid-template-columns:repeat(6,1fr)}.crop-grid{grid-template-columns:repeat(2,minmax(0,1fr));gap:14px}.crop-grid .range-row:first-child{grid-column:1/-1}.editor-footer{padding:12px 16px;gap:12px}.order-summary strong{font-size:12px}.order-summary small{font-size:10px}.price-group{gap:10px}.price{display:none}.price-group .btn{font-size:13px;min-width:170px}.review-page{padding:18px 16px 35px}.review-heading h1{font-size:28px}.review-columns{display:flex;flex-direction:column}.review-pages{width:100%;gap:12px}.review-card{padding:12px}.summary-box{width:100%;position:static}.review-card .row{gap:5px}.review-card p{font-size:12px}.review-card button{font-size:11px}.dialog-body{padding:20px}.dialog-head{padding:15px 18px}.dialog-body .choices{grid-template-columns:1fr}.dialog-body .model-image{height:250px}.dialog-footer{padding:15px 18px}.dialog-footer .btn{font-size:13px}.done-page h1{font-size:28px}.done-page{padding:35px 20px}body.is-fullscreen .paper-wrap{max-width:600px}body.is-fullscreen .paper-wrap.portrait{max-width:290px}body.is-fullscreen .stage{max-height:none;min-height:400px}}
@media(max-width:370px){.step-name{display:none!important}.steps{gap:4px}.step-line{width:8px}.format-glyph{display:none}.format-card{min-height:87px}.tile-image{height:133px}.tile-footer{padding:9px}.tile-go{display:none}.editor-top h1{max-width:110px}.editor-top .field{max-width:135px}.order-summary{max-width:110px}.price-group .btn{min-width:155px;padding:10px}.panel .photo-tray{grid-template-columns:repeat(4,1fr)}.side-tabs{gap:4px}.reviewer .proto-label{font-size:10px}.upload-hero>div:last-child{gap:8px}}
@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation:none!important;transition:none!important;scroll-behavior:auto!important}}
@media(min-width:761px){.stage{min-height:240px;padding:22px 10px}.paper-wrap{max-width:min(570px,calc((100vh - 420px)*var(--ratio)))}.paper-wrap.portrait{max-width:min(300px,calc((100vh - 420px)*var(--ratio)))}.paper-wrap.wide{max-width:min(640px,calc((100vh - 420px)*var(--ratio)))}body.is-fullscreen .paper-wrap{max-width:min(800px,calc((100vh - 270px)*var(--ratio)))}}
.editor-top h1::after{content:'Layout demo';display:block;font-size:11px;font-weight:400;color:var(--muted);letter-spacing:0;margin-top:3px}
.spatial-demo{padding:65px 40px;background:#ebe7df;perspective:1000px;min-height:290px;display:flex;align-items:center;justify-content:center;margin-bottom:20px}.spatial-paper{width:75%;max-height:360px;transform:rotateX(30deg) rotateZ(-12deg);box-shadow:2px 3px 0 #d2cec5,12px 28px 25px #28241d30}.spatial-paper svg{width:100%;height:100%;display:block}
@media(max-width:760px){.paper-wrap.opened{transform:scale(.5) translateX(35%)}}
html[lang=de] .editor-top h1::after{content:'Layout-Demo'}
@media(min-width:761px){.edit-layout{height:calc(100dvh - 270px);min-height:430px}.sidebar{overflow-y:auto}.workspace{height:100%;overflow:hidden}.stage{min-height:0;padding:16px 8px}.paper-wrap{max-width:min(570px,calc((100dvh - 490px)*var(--ratio)))}.paper-wrap.portrait{max-width:min(300px,calc((100dvh - 490px)*var(--ratio)))}.paper-wrap.wide{max-width:min(640px,calc((100dvh - 490px)*var(--ratio)))}body.is-fullscreen .edit-layout{height:calc(100dvh - 88px)}.canvas-hint{margin-bottom:8px}.side-tabs{padding:3px 0}}
/* v3 — shared core / ORWO systems, quieter surfaces and direct editing. */
:root{--radius:8px;--focus-halo:rgba(53,178,182,.3)}
[data-brand=orwo]{--focus-halo:rgba(6,172,218,.3)}
button{transition:background 160ms,color 160ms,transform 80ms}
button:active:not(:disabled){transform:scale(.985)}
button:focus-visible,a:focus-visible,select:focus-visible,input:focus-visible,textarea:focus-visible{outline:2px solid var(--brand-dark);outline-offset:3px;box-shadow:0 0 0 5px var(--focus-halo)}
.btn{height:44px;min-height:44px;border-radius:8px;font-size:15px;letter-spacing:-.005em;padding:0 20px}
.btn.primary:hover{background:var(--brand-dark);color:white;filter:none}
[data-brand=orwo] .btn.primary:hover{background:#2a323b}
.btn.secondary{border-color:transparent;background:var(--soft);color:var(--brand-dark)}
.btn.secondary:hover{border-color:transparent;background:var(--soft);filter:brightness(.97)}
.btn:disabled{opacity:1;background:#d1d5db;color:#6b7280;border-color:transparent}
.icon-btn{border:0;background:transparent}.icon-btn:hover{background:var(--soft)}
#reviewer{border:0;background:#f3f4f6;min-height:32px;padding:2px 4vw}
.review-tools select{border:0;background:transparent}.review-notice{color:#6b7280}
#header{border:0;min-height:84px}.lang-btn{border:0;border-radius:8px}
.step b{border:0;background:#f3f4f6;color:#6b7280}.step.active b{background:var(--soft);color:var(--brand-dark);font-weight:700}.step.done b{background:var(--soft);color:var(--brand-dark)}
.step-line{background:#e5e7eb;width:24px}.steps{gap:16px}
.gallery{padding-top:40px}.gallery-top{align-items:center;gap:40px}.gallery-top h1{margin:10px 0 12px;max-width:680px;font-size:34px;letter-spacing:-.03em}.gallery-top p{font-size:15px;line-height:1.6;max-width:560px}
.upload-hero{border:0;background:transparent;padding:0 0 0 24px;width:320px;gap:16px;border-radius:0}.upload-hero .upload-symbol{background:#fff;width:60px;height:72px;border-radius:8px}.upload-hero h3{font-size:15px}.upload-hero .btn{background:white;height:44px;padding:0 16px;margin-top:12px}.upload-hero p{font-size:13px}
.format-grid{margin:32px auto;gap:16px}.format-card{background:transparent;border-color:transparent;box-shadow:none;padding:16px;border-radius:8px;min-height:104px}.format-card:hover{background:#f0e9df}.format-card.selected{background:var(--soft);border-color:var(--brand)}.format-card.selected:hover{background:var(--soft)}.format-card .check{top:12px;right:12px}.format-glyph span{border-color:var(--muted);box-shadow:3px 3px 0 #d1d5db}.format-card.selected .format-glyph span{border-color:var(--brand-dark);box-shadow:3px 3px 0 var(--brand)}
.gallery-controls{margin-bottom:24px;gap:24px}.filters{gap:4px}.chip{border:0;background:transparent;border-radius:8px;padding:0 14px;height:44px;font-size:13px}.chip:hover{background:#ffffff99}.chip[aria-pressed=true]{background:white;color:var(--brand-dark);box-shadow:none}.search input{border:0;background:#ffffffb3;border-radius:8px}.search{max-width:260px}.grid-head{margin-bottom:20px;font-size:13px}
.design-grid{gap:32px 24px}.design-tile{background:transparent;border:0;border-radius:0;overflow:visible}.design-tile:hover{transform:none;box-shadow:none}.tile-image{height:230px;background:#fff;border-radius:8px;padding:24px 16px;overflow:hidden}.tile-image img{transition:transform 240ms cubic-bezier(.2,.85,.25,1);filter:drop-shadow(0 7px 6px #10151b12)}.design-tile:hover .tile-image img{transform:scale(1.035)}.tile-footer{padding:12px 0 0;border:0;align-items:center}.tile-footer h3{font-size:15px;font-weight:500;margin:0}.tile-go{background:transparent;width:28px;height:32px;color:var(--muted)}.tile-go .icon{width:18px}.tile-action{border-radius:8px}.gallery-bottom{padding:32px 0 8px}.gallery-bottom+.gallery-bottom{padding-top:8px}.gallery-bottom .btn{background:transparent}.gallery-bottom .btn.secondary{background:#fff}
.resume{border:0;border-radius:8px;background:white;padding:16px 20px;margin-bottom:32px}.resume .btn.primary{background:var(--soft);color:var(--brand-dark)}
.editor-top{border:0;padding:12px 28px;background:white}.editor-top h1{font-size:20px}.editor-top .field{border:0;background:#f3f4f6;border-radius:8px}.sidebar{border:0}.tabs{border:0;gap:8px;padding:12px 20px 0}.tab{border:0;border-radius:8px;min-height:44px;background:transparent}.tab[aria-selected=true]{background:var(--soft);color:var(--brand-dark)}.panel{padding:24px 24px;gap:24px}.panel h3{font-size:17px}.panel .section{border:0;padding-top:0}.panel .help-inline{padding:0;background:none;font-size:11px!important}.reference{padding:0;border:0;background:transparent;gap:12px;border-radius:0}.reference img{width:56px;height:48px}.reference span{font-size:11px;color:var(--muted)}.reference strong{font-size:13px;color:var(--ink);font-weight:500}.sample-toggle{font-size:13px;text-decoration:none}.sample-toggle:hover{text-decoration:underline}.photo-thumb{border-radius:8px;border-width:2px}.text-field-btn{border:0;background:#f3f4f6;border-radius:8px}.text-field-btn[aria-pressed=true]{background:var(--soft)}.field{background:#f3f4f6;border:1.5px solid transparent;border-radius:8px}.field:focus{background:white;border-color:var(--brand)}
.workspace{background:#fff;padding:20px 32px 12px}.workspace-toolbar{padding-bottom:4px}.segmented{background:#f3f4f6;border:0;border-radius:8px;padding:4px}.segmented button{border-radius:6px;min-height:36px}.segmented button[aria-pressed=true]{background:white;color:var(--ink);box-shadow:0 1px 3px #10151b10;font-weight:600}.workspace-tools{gap:4px}.paper-wrap{filter:drop-shadow(0 12px 14px #10151b1c)}.side-tab{border:0;border-radius:8px;padding:7px 12px;gap:7px;color:var(--muted);min-height:66px}.side-tab[aria-pressed=true]{background:var(--soft);color:var(--brand-dark);font-weight:600}.side-tab svg{border:0;box-shadow:0 1px 4px #10151b18}.side-tabs{gap:8px}.canvas-hint{font-size:11px;color:#6b7280}
.editor-footer{border-top:1px solid #f3f4f6;box-shadow:none;padding:16px 28px}.editor-footer .btn{font-size:15px}.price strong{font-size:24px}.order-summary strong{font-weight:500}.text-fields{gap:8px}.swatch{width:36px;height:36px}.summary-box{border:0;border-radius:0;padding:8px 0 8px 24px;gap:20px}.review-card{border:0;background:transparent;padding:20px 16px;border-radius:0}.review-pages{gap:32px}.review-card .row{margin-top:20px}.review-card button{font-size:13px}.review-heading{margin:24px 0 40px}.summary-line.total{border-color:#f3f4f6}.quantity button{border:0;background:#f3f4f6;width:44px;height:44px;border-radius:8px}.notice{background:transparent;padding:0;color:var(--muted)}.summary-box>.notice{font-size:11px}
.dialog-head{border:0;padding-bottom:0}.dialog-footer{border:0}.dialog-body .choice{border:0;background:var(--subtle)}
@media(max-width:1000px) and (min-width:761px){.gallery-top{gap:24px}.upload-hero{width:280px;padding-left:0}.format-grid{gap:8px}.format-card{padding:12px}.gallery-controls{align-items:flex-start}.filters{flex-wrap:wrap}.search{min-width:190px}.steps{gap:10px}.step-line{width:14px}}
@media(max-width:760px){#reviewer{padding:2px 16px;min-height:32px}#header{min-height:72px;padding:12px 16px}.steps{gap:6px}.step-line{width:8px}.gallery{padding:24px 16px 32px}.gallery-top h1{font-size:28px}.gallery-top p{font-size:15px}.upload-hero{width:100%;padding:0;margin-top:20px}.upload-hero .upload-symbol{height:44px;width:44px}.upload-hero .btn{margin-top:0;padding:0 12px;font-size:13px}.format-grid{gap:8px;margin:24px 0}.format-card{padding:12px 10px;min-height:96px}.gallery-controls{gap:16px;margin-bottom:20px}.filters{padding:0}.chip{font-size:13px;padding:0 12px}.search{max-width:none}.grid-head{font-size:11px;gap:8px}.design-grid{gap:24px 12px}.tile-image{height:170px;padding:14px 8px}.tile-footer{padding:10px 0 0}.tile-footer h3{font-size:13px}.tile-go{width:22px}.editor-top{padding:8px 16px}.editor-top h1{font-size:15px}.editor-top .field{font-size:11px}.workspace{padding:12px 16px 8px}.workspace-tools .icon-btn{width:36px;height:44px}.workspace-toolbar>.segmented button{padding:8px;gap:5px}.sidebar{border:0}.tabs{padding:8px 16px}.panel{padding:16px 20px 24px;gap:20px}.side-tab{padding:6px 8px;min-width:0}.side-tabs{gap:4px}.editor-footer{padding:12px 16px}.editor-footer .btn{font-size:13px}.order-summary strong{font-size:11px}.order-summary small{font-size:10px}.summary-box{padding:12px 0}.review-heading{margin:24px 0}.review-pages{gap:16px}.review-card{padding:8px}.review-card .row{margin-top:12px}.review-card p{font-size:11px}.review-card button{font-size:13px}}

/* v4 — white canvas, brand typography and lightweight card photography. */
@font-face{font-family:Montserrat;src:url(assets/fonts/montserrat-latin-400-normal.woff2) format("woff2");font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:Montserrat;src:url(assets/fonts/montserrat-latin-500-normal.woff2) format("woff2");font-weight:500;font-style:normal;font-display:swap}
@font-face{font-family:Montserrat;src:url(assets/fonts/montserrat-latin-600-normal.woff2) format("woff2");font-weight:600;font-style:normal;font-display:swap}
@font-face{font-family:Montserrat;src:url(assets/fonts/montserrat-latin-700-normal.woff2) format("woff2");font-weight:700;font-style:normal;font-display:swap}
@font-face{font-family:Jost;src:url(assets/fonts/jost-latin-400-normal.woff2) format("woff2");font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:Jost;src:url(assets/fonts/jost-latin-500-normal.woff2) format("woff2");font-weight:500;font-style:normal;font-display:swap}
@font-face{font-family:Jost;src:url(assets/fonts/jost-latin-600-normal.woff2) format("woff2");font-weight:600;font-style:normal;font-display:swap}
@font-face{font-family:Jost;src:url(assets/fonts/jost-latin-700-normal.woff2) format("woff2");font-weight:700;font-style:normal;font-display:swap}

:root{--on-primary:#fff;--page:#fff;--subtle:#f6f7f8;--ui:Montserrat,system-ui,sans-serif;--paper:var(--surface);--paper-edge:rgba(0,0,0,.08);--stage:color-mix(in srgb,var(--brand) 7%,var(--page) 93%);--stage-deep:color-mix(in srgb,var(--brand) 13%,var(--page) 87%)}

/* ── CANVAS COLUMN BUDGET ────────────────────────────────────────────────
   Declared once, consumed by the stage AND the spread strip, so the column
   adds up by construction instead of whoever edits last winning. Bands from
   top to bottom: header chrome, toolbar, hint, STAGE, presets, strip, price
   bar, plus the workspace's own gutter.
   --header-h and --bottombar-h are written by measureChrome() in app.js.
   The miniature is the flexible band: it shrinks before the stage does,
   because a small miniature is still readable and a small card is not.
   --strip-chrome is measured, not guessed - label + page name + status chip
   + the paddings around the miniature measure 80px once the strip internals
   below are pinned; 84 leaves four pixels of headroom. Every band here is the measured value plus a couple of
   pixels of headroom, never a guess - the verify script asserts the sum.
   It assumes a two-line status chip, which is what the longest German label
   needs; pinning the chip's box is what makes the number hold for every
   format and both languages instead of only the one that was measured. */
:root{
  --header-h:186px;          /* measured; reviewer + header + editor bar */
  --bottombar-h:84px;        /* measured; price bar */
  --canvas-toolbar:52px;
  --canvas-gutter:24px;      /* workspace margin 6+6 and padding 6+6 */
  --mini-h:clamp(48px,7vh,96px);
  --strip-chrome:66px;       /* name + chip + paddings; no caption row now */
  --strip-h:calc(var(--mini-h) + var(--strip-chrome));
  --canvas-inline:0px;       /* the inline format strip, when it is shown */
  --stage-floor:320px;
  --stage-h:clamp(var(--stage-floor),calc(100dvh - var(--header-h) - var(--bottombar-h)
    - var(--canvas-toolbar) - var(--strip-h) - var(--canvas-gutter)
    - var(--canvas-inline)),420px);
}
[data-brand=orwo]{--page:#fff;--subtle:#f6f7f8;--ui:Jost,system-ui,sans-serif;--primary:#060607}
#reviewer{background:#f8f9fa;font-size:10px}.proto-label{letter-spacing:.045em}
#header{border-bottom:1px solid #f1f3f4}
.gallery{padding-top:38px}.gallery-top{gap:32px}.gallery-top h1{font-size:36px;font-weight:600;letter-spacing:-.04em;line-height:1.2}.gallery-top .eyebrow{font-size:12px;letter-spacing:.1em}.gallery-top p{font-size:14px;line-height:1.65}
.upload-hero{width:310px;padding:0;gap:0}.upload-hero .upload-symbol{display:none}.upload-hero h3{font-size:14px;font-weight:600}.upload-hero p{font-size:12px}.upload-hero .btn{background:var(--primary);color:white;font-size:13px;padding:0 20px}.upload-hero .btn:hover{background:var(--brand-dark)}
.format-grid{gap:12px;margin:32px auto 28px}.format-card{gap:8px;padding:12px 16px 12px 6px;min-height:116px;border:0;border-radius:10px}.format-card:hover{background:#f7f9f9}.format-card.selected{background:var(--soft);border:0}.format-card .format-title{font-size:13px;line-height:1.4;font-weight:600}.format-card small{font-size:11px;line-height:1.5;margin:4px 0}.format-card strong{font-size:13px;font-weight:600}.format-card .check{right:10px;top:9px;font-size:14px}.format-render{width:94px;height:86px;object-fit:contain;flex-shrink:0;mix-blend-mode:multiply}
.gallery-controls{gap:20px;margin-bottom:26px;padding-top:22px;border-top:1px solid #edf0f1}.chip{border-radius:6px;font-weight:500;padding:0 12px;font-size:12px}.chip:hover{background:#f6f8f8}.chip[aria-pressed=true]{background:var(--soft);color:var(--brand-dark)}.search input{background:#f5f7f8;font-size:12px}.search{max-width:245px}.grid-head{font-size:12px;margin-bottom:16px}
.design-grid{gap:32px 30px}.tile-image{height:210px;padding:16px 4px;background:transparent;border-radius:0;overflow:visible}.tile-image img{filter:drop-shadow(0 3px 3px #10151b13);transition:transform 240ms ease}.design-tile:hover .tile-image img{transform:translateY(-4px) scale(1.015)}.tile-footer{padding-top:8px}.tile-footer h3{font-size:13px;font-weight:600;line-height:1.5}.tile-go{color:#869097}.tile-go .icon{width:17px}.tile-action{border-radius:4px}.gallery-bottom .btn.secondary{background:#f3f6f7;font-size:13px}.resume{background:#f6f8f8}
.btn.primary{color:#fff}.btn{font-size:14px}.resume .btn.primary{background:var(--primary);color:#fff}.panel h3{font-size:16px}.panel .help-inline{font-size:12px!important}.canvas-hint{font-size:12px}.editor-top h1{font-weight:600}.editor-footer .btn{font-size:14px}.editor-top .field{max-width:290px}.editor-footer .order-summary strong{font-size:13px}.side-tab{font-size:12px}.step-name{font-size:12px}.summary-box>.notice{font-size:12px}
.preview-object{transform:rotateX(var(--tilt,8deg)) rotateY(var(--turn,0deg));cursor:grab;touch-action:pan-y;user-select:none;-webkit-user-select:none}.preview-object.rotating{transition:none;cursor:grabbing}.preview-object svg{pointer-events:none}.preview-face{outline:.5px solid #d9dddf;box-shadow:0 2px 2px #1b232b20}.paper-wrap.is-preview{filter:drop-shadow(0 18px 14px #13242d20)}
#preview-controls{width:100%;padding:12px 0 6px}.rotation-control{display:flex;align-items:center;gap:12px;max-width:320px;margin:16px auto 0;font-size:12px;color:var(--muted)}.rotation-control input{flex:1;min-width:0;height:32px;margin:0}.rotation-control output{min-width:36px;text-align:right;font-variant-numeric:tabular-nums}.rotation-control span{font-weight:500}
@media(min-width:761px){.paper-wrap.is-preview{max-width:min(530px,calc((100dvh - 450px)*var(--ratio)))}.paper-wrap.is-preview.portrait{max-width:min(290px,calc((100dvh - 450px)*var(--ratio)))}.paper-wrap.is-preview.opened{max-width:min(510px,calc((100dvh - 450px)*var(--ratio)))}.stage:has(.is-preview){perspective:1400px}}
@media(max-width:1200px) and (min-width:761px){.format-render{width:70px;height:74px}.format-card{padding-right:10px}.format-card .format-title{font-size:12px}.format-card small{font-size:10px}.gallery-controls{align-items:flex-start}.filters{gap:2px}.chip{padding:0 10px}.gallery-top h1{font-size:32px}}
@media(max-width:760px){.gallery{padding-top:26px}.gallery-top h1{font-size:28px;max-width:440px}.gallery-top p{font-size:13px}.upload-hero{margin-top:20px;width:100%}.upload-hero>div:last-child{gap:10px}.upload-hero h3{font-size:12px}.upload-hero .btn{font-size:12px;padding:0 14px}.format-grid{gap:6px;margin:26px 0 22px}.format-card{gap:5px;padding:12px 8px 12px 2px;min-height:100px}.format-render{width:52px;height:66px}.format-card .format-title{font-size:11px;line-height:1.4}.format-card small{font-size:10px}.format-card strong{font-size:12px}.format-card .check{font-size:12px;right:6px;top:5px}.gallery-controls{gap:12px;padding-top:18px;margin-bottom:18px}.search{max-width:none}.chip{font-size:12px}.grid-head{font-size:10px}.design-grid{gap:26px 18px}.tile-image{height:133px;padding:10px 0}.tile-footer h3{font-size:12px}.tile-footer{padding-top:2px}.tile-go{width:18px}.steps{gap:4px}.step-name{font-size:10px}.step-line{width:5px}.brand-logo{width:108px}.header-actions{gap:0}.lang-btn{font-size:12px;padding:8px 6px}.editor-top .field{max-width:160px;font-size:10px}.editor-footer .btn{font-size:12px;padding:0 13px;min-width:0}.order-summary{max-width:145px}.editor-footer .order-summary strong{font-size:10px}.editor-footer{gap:10px}.side-tab{font-size:10px}.rotation-control{max-width:270px;margin-top:8px}.canvas-hint{font-size:11px}#preview-controls{padding-top:4px}.stage:has(.is-preview){min-height:275px}.panel h3{font-size:16px}.step b{width:22px;height:22px}}
@media(prefers-reduced-motion:reduce){.preview-object,.preview-panel.cover,.paper-wrap,.tile-image img{transition:none!important}}
/* Let the artwork determine the gallery rhythm, without oversized tile containers. */
.tile-image{height:auto;aspect-ratio:1.8;padding:14px 4px}.tile-image img{width:100%;height:100%;object-fit:contain}
@media(max-width:760px){.tile-image{height:auto;aspect-ratio:1.5;padding:8px 0}}
/* Keep names attached to artwork at every format and viewport. */
.design-grid{align-items:start;row-gap:32px}.tile-image{display:block;height:auto;aspect-ratio:auto;padding:0}.tile-image img{display:block;width:100%;height:auto;max-height:none;object-fit:contain}.tile-footer{padding:10px 2px 0;min-height:34px}.tile-footer h3{margin:0}.grid-head{margin-bottom:26px}
.lang-btn{display:inline-flex;align-items:center;gap:4px;white-space:nowrap;flex-shrink:0}
@media(max-width:760px){.design-grid{row-gap:24px;column-gap:16px}.tile-image{height:auto;aspect-ratio:auto;padding:0}.tile-footer{padding:8px 0 0;min-height:30px}.format-card small{font-size:11px}.grid-head{margin-bottom:22px}.lang-btn .icon{width:14px}}

/* Shadow-free vector format miniatures, sharp at every pixel density. */
.format-render{mix-blend-mode:normal;filter:none;box-shadow:none}

/* v4.2: precise gallery edges, open-V cards and quiet page status. */
.tile-image{position:relative}.tile-image img{filter:none;box-shadow:none;clip-path:inset(1.5% 1% 2.5% 1%)}.tile-image::after{content:'';position:absolute;inset:1.5% 1% 2.5% 1%;border:1px solid #dce2e5;pointer-events:none}.design-tile:hover .tile-image img{transform:none}.design-tile:hover .tile-image::after{border-color:#aabcc1}
.paper-wrap.opened{transform:scale(.62) translateX(43%)}
.page-label{display:inline-flex;align-items:center;justify-content:center;gap:5px}.page-indicator{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;flex-shrink:0}.page-indicator svg,.page-indicator .icon{width:16px!important;height:16px!important;background:none!important;box-shadow:none!important;border:0!important}.page-indicator.pending{color:#a36b1d}.page-indicator.ready{color:var(--brand-dark)}.page-indicator.blank{color:#8a959b}.preview-pages-nav{padding-top:8px;gap:4px}.preview-pages-nav .side-tab{min-height:36px;padding:6px 10px;font-size:11px;background:none}.text-review-prompt{display:flex;align-items:center;justify-content:space-between;gap:8px;font-size:12px;color:var(--muted)}.text-review-prompt>span{display:inline-flex;align-items:center;gap:5px}.text-review-prompt .btn{font-size:12px;padding:0 6px;white-space:nowrap;color:var(--brand-dark)}
@media(min-width:761px){.paper-wrap.is-preview{max-width:min(530px,calc((100dvh - 505px)*var(--ratio)))}.paper-wrap.is-preview.portrait{max-width:min(290px,calc((100dvh - 505px)*var(--ratio)))}.paper-wrap.is-preview.opened{max-width:min(510px,calc((100dvh - 505px)*var(--ratio)))}}
@media(max-width:760px){.paper-wrap.opened{transform:scale(.5) translateX(43%)}.side-tab{padding:6px 5px}.side-tab .page-label{gap:3px}.page-indicator{width:14px;height:14px}.preview-pages-nav .side-tab{font-size:10px;padding:5px}.text-review-prompt{font-size:12px}}

.page-indicator.pending{width:16px;color:#9b650f}
@media(max-width:760px){.paper-wrap.portrait.opened{transform:scale(.68) translateX(43%)}}

/* v4.3 — angle-dependent, flat face shading, capped at 5% black. */

/* v4.4 — a bounded card workspace with controls anchored to the artwork. */
.workspace{--stage-height:var(--stage-h);background:#f6f8f9;border-radius:12px;margin:8px 24px 18px 0;padding:20px 24px;justify-content:center;height:auto;overflow:auto}
.workspace-inner{width:100%;max-width:920px;margin:auto;display:flex;flex-direction:column;align-items:center;min-height:0}
.workspace-toolbar{display:grid;grid-template-columns:1fr auto 1fr;align-items:center;gap:16px;padding:0;flex-shrink:0}
#workspace-title{font-size:14px;font-weight:600;letter-spacing:-.015em;color:var(--muted);white-space:nowrap}
.mode-switch{background:#e9edef;padding:4px;border-radius:9px;gap:3px}.mode-switch button{height:42px;min-height:42px;padding:0 18px;font-size:14px;gap:8px;white-space:nowrap;font-weight:500;border-radius:6px}.mode-switch button[aria-pressed=true]{background:var(--primary);color:var(--on-primary);box-shadow:none;font-weight:600}.mode-switch button:not([aria-pressed=true]):hover{background:#fff}
.workspace-tools{justify-self:end;gap:2px}.workspace-tools .icon-btn{width:36px;height:40px}.workspace-tools .icon{width:18px}
.workspace .canvas-hint{max-width:none;margin:14px 0 0;font-size:12px;line-height:1.5;color:#65727b;min-height:18px}
.workspace .stage{flex:none;height:var(--stage-height);min-height:0;max-height:none;width:100%;padding:24px 16px;margin:0;perspective:1600px}
.workspace .paper-wrap,.workspace .paper-wrap.is-preview{max-width:min(560px,calc((var(--stage-height) - 56px)*var(--ratio)))}
.workspace .paper-wrap.portrait,.workspace .paper-wrap.is-preview.portrait{max-width:min(300px,calc((var(--stage-height) - 56px)*var(--ratio)))}
.workspace .paper-wrap.is-preview.opened{max-width:min(690px,calc((var(--stage-height) - 64px)*var(--ratio)/.62));transform:scale(.62) translateX(43%)}
.workspace .paper-wrap.is-preview.portrait.opened{max-width:min(420px,calc((var(--stage-height) - 64px)*var(--ratio)/.62))}
.canvas-actions{display:flex;flex-direction:column;align-items:center;width:100%;gap:6px;flex-shrink:0}
.workspace #preview-controls{width:auto;padding:0;display:flex;gap:22px;align-items:center;justify-content:center;flex-wrap:wrap}.workspace #preview-controls:empty{display:none}.workspace #preview-controls>.row{gap:8px}.workspace #preview-controls .btn{background:#fff;font-size:12px;height:38px;min-height:38px;padding:0 14px;color:var(--brand-dark)}
.workspace .rotation-control{margin:0;width:235px;font-size:11px;gap:8px;max-width:none}.workspace .rotation-control input{height:36px}
.workspace .side-tabs{width:auto;gap:8px;padding:8px 0 0}.workspace .side-tab{padding:8px 12px;min-height:66px;font-size:12px}.workspace .side-tab[aria-pressed=true]{background:#e3eff0}.workspace .side-tab>svg{box-shadow:none;border:1px solid #dce3e7}.workspace .preview-pages-nav .side-tab{min-height:38px;background:transparent;font-size:12px;padding:7px 10px}.workspace .preview-pages-nav .side-tab:hover{background:#e8eef0}
@media(min-width:761px){.edit-layout{height:calc(100dvh - var(--header-h) - var(--bottombar-h));min-height:460px;grid-template-columns:300px minmax(0,1fr)}.sidebar{padding-top:8px}.tabs{padding-top:8px}.workspace{min-height:0}body.is-fullscreen .edit-layout{height:calc(100dvh - 88px);min-height:0}body.is-fullscreen .workspace{margin:16px;--stage-height:clamp(320px,calc(100dvh - 330px),680px)}}
@media(max-width:1100px) and (min-width:761px){.workspace{padding:16px;margin-right:16px}.workspace-toolbar{grid-template-columns:1fr auto;gap:12px}#workspace-title{display:none}.mode-switch{justify-self:center;margin-left:45px}.mode-switch button{padding:0 14px;font-size:13px}.workspace-tools{gap:0}.workspace-tools .icon-btn{width:32px}.workspace #preview-controls{gap:10px}.workspace .rotation-control{width:210px}}
@media(max-width:760px){.edit-layout{height:auto;min-height:0}.workspace{--stage-height:290px;padding:16px 10px 14px;margin:8px 12px 16px;border-radius:10px;overflow:hidden}.workspace-toolbar{display:flex;justify-content:center;gap:8px;position:relative;flex-wrap:wrap}#workspace-title{display:none}.mode-switch{margin:0}.mode-switch button{padding:0 16px;font-size:13px;height:40px;min-height:40px}.workspace-tools{gap:0;justify-self:auto}.workspace-tools .icon-btn{width:32px;height:38px}.workspace .canvas-hint{font-size:11px;line-height:1.5;margin-top:12px;max-width:290px;min-height:32px}.workspace .stage{padding:24px 8px}.workspace .paper-wrap.is-preview.opened{max-width:340px;transform:scale(.52) translateX(43%)}.workspace .paper-wrap.is-preview.portrait.opened{max-width:250px;transform:scale(.64) translateX(43%)}.workspace #preview-controls{gap:8px 14px}.workspace #preview-controls .btn{font-size:12px}.workspace .rotation-control{width:245px}.workspace .side-tabs{gap:2px;padding-top:8px}.workspace .side-tab{font-size:10px;padding:6px;min-height:62px}.workspace .preview-pages-nav .side-tab{font-size:10px;padding:6px 5px;min-height:34px}.canvas-actions{gap:0}.sidebar{padding-top:0}.workspace .paper-wrap{max-width:min(330px,calc((var(--stage-height) - 48px)*var(--ratio)))}.workspace .paper-wrap.portrait{max-width:170px}body.is-fullscreen .workspace{--stage-height:420px;margin:12px}.workspace .mode-switch .icon{width:18px}}

/* v4.5 — mobile progressive disclosure, prioritising the designs. */
.mobile-intro,.mobile-format,.mobile-category{display:none}
/* Keep each paper face on a separate plane; avoid filtered 3D ancestors. */
.workspace .paper-wrap.is-preview{filter:none!important;transform-style:preserve-3d}
.preview-face{box-shadow:none!important;transform:translateZ(.15px);backface-visibility:hidden;-webkit-backface-visibility:hidden}
.preview-face.reverse{transform:rotateY(180deg) translateZ(.15px)}
.preview-face::after{content:none!important;display:none!important}
@media(max-width:760px){
 #reviewer{min-height:26px;padding:0 16px;font-size:9px}.review-tools select{font-size:11px;height:26px}.proto-label{letter-spacing:.025em}
 #header{min-height:60px;padding:8px 16px;gap:12px}.brand-logo{width:112px;height:28px}.steps{gap:0;margin-left:auto}.steps .step:not(.active),.steps .step-line{display:none}.step.active{gap:7px}.step.active b{width:auto;min-width:30px;border:0;border-radius:0;background:none;height:auto;font-size:11px;white-space:nowrap}.step.active b::after{content:' / 3';white-space:pre;color:#829098;font-weight:400}.step-name{font-size:10px;line-height:1.3;max-width:72px}.lang-btn{min-height:36px;font-size:11px;padding:4px}.lang-btn .icon{display:none}
 .gallery{padding:20px 16px 28px}.gallery-top{margin:0 0 22px}.gallery-top .eyebrow,.gallery-top .desktop-intro,.gallery .upload-hero,.gallery>.format-grid{display:none}.mobile-intro{display:block}.gallery-top h1{font-size:25px;line-height:1.2;margin:0 0 8px;letter-spacing:-.035em}.gallery-top p.mobile-intro{font-size:13px;line-height:1.5;margin:0;color:var(--muted)}
 .resume{padding:0;margin:0 0 18px;background:transparent;gap:0;border:0}.resume>div:first-child{display:none}.resume .row{width:100%;gap:4px}.resume .btn.primary{height:40px;min-height:40px;flex:1;justify-content:flex-start;background:#f1f7f7;color:var(--brand-dark);font-size:12px;padding:0 12px}.resume .btn.quiet{width:36px;height:40px;min-height:40px;padding:0}.resume .icon{width:17px}
 .mobile-format{display:block;margin:0 0 20px}.mobile-format>label{display:block;margin:0 0 7px;font-size:12px;font-weight:600}.mobile-format select{height:48px;font-size:14px;background:#f5f7f8;padding:0 12px;border:1px solid #e7ecef;border-radius:7px}.mobile-format p{margin:8px 0 0;font-size:11px;color:var(--muted);line-height:1.5}
 .gallery-controls{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:10px;padding:0;margin-bottom:16px;border:0;align-items:center}.gallery-controls .filters{display:none}.mobile-category{display:block;min-width:0}.mobile-category .field{height:42px;font-size:12px;padding:0 9px;background:#f5f7f8;border:0}.gallery-controls .search{min-width:0;width:100%}.gallery-controls .search .field{height:42px;font-size:12px;padding-left:32px;padding-right:7px}.gallery-controls .search .icon{left:10px;top:12px;width:15px}
 .grid-head{margin-bottom:14px;font-size:12px}.grid-head>span:last-child{display:none}.design-grid{gap:22px 16px}.tile-footer h3{font-size:12px}.tile-footer{padding-top:7px}.gallery-bottom{padding-top:24px}
}

@media(max-width:760px){.step.active b{display:inline-flex;align-items:center;justify-content:center;gap:0}}


/* v4.6 — editor refinement: 3D preview
   Tokens live in the LAST :root above (three competing blocks; the last wins).
   The brief's snippet named --surface/--bg/--text; only --surface exists here,
   so --bg maps to --page and --text to --ink. Written verbatim it would have
   produced invalid color-mix() and dropped the declarations silently. */

/* Stage: fixed box, clips. The card grew UPWARD out of it at every yaw where it
   was not face-on and collided with .canvas-hint, which sits directly above. */
.workspace .stage{position:relative;overflow:hidden;background:var(--stage);border-radius:10px}

/* ONE transition on one gesture. The wrap animated over 400ms while the object
   took 700ms, so the scene kept re-projecting for 300ms after the card looked
   settled. The wrap no longer transitions at all. */
.paper-wrap.is-preview{transition:none}
.preview-object{transition:transform 450ms cubic-bezier(.2,.7,.2,1);will-change:transform}
.preview-panel.cover{transition:transform 450ms cubic-bezier(.2,.7,.2,1)}

/* Faces: a border on the face itself, never an outline. A 0.5px outline on a
   3D-transformed element is sub-pixel and re-rasterises every frame - that was
   the only paint left on the rotating faces once every box-shadow had been
   overridden to none. */
.preview-face{outline:0!important;box-shadow:none!important;border:1px solid var(--paper-edge);
  background:var(--paper);transform:translateZ(.4px)}
.preview-face.reverse{transform:rotateY(180deg) translateZ(.4px)}

/* Face shading: ONE system. The CSS ::after was dead (--face-shade never set,
   computed opacity 0 on all four faces) while an SVG .face-tint did the work.
   The CSS one is now the live one and the SVG tint is gone. */
.preview-face::after{content:'';position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(105deg,rgba(0,0,0,.14),rgba(0,0,0,0) 55%,rgba(255,255,255,.10));
  opacity:var(--yaw-shade,0);transition:opacity 450ms cubic-bezier(.2,.7,.2,1)}
.preview-object.rotating .preview-face::after{transition:none}

/* One ground shadow, under the card, narrowing as it turns edge-on. */
.card3d-ground{position:absolute;left:50%;bottom:10%;width:46%;height:30px;
  transform:translateX(-50%) scaleX(var(--ground-scale,1));transform-origin:50% 50%;
  background:radial-gradient(closest-side,rgba(16,21,27,.28),rgba(16,21,27,0));
  filter:blur(6px);pointer-events:none;z-index:0;
  transition:transform 450ms cubic-bezier(.2,.7,.2,1),opacity 450ms cubic-bezier(.2,.7,.2,1);
  opacity:var(--ground-opacity,1)}
.preview-object.rotating~.card3d-ground,.rotating .card3d-ground{transition:none}

/* Blank faces are never a bare white rectangle. */
.face-blank{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
  flex-direction:column;gap:6px;pointer-events:none;font-size:13px;color:var(--ink);opacity:.4;
  text-align:center;padding:0 12px}
.face-blank .face-lock{display:flex;align-items:center;gap:5px;font-size:11px;opacity:.85}
.face-blank .face-lock svg{width:12px;height:12px}

/* Preset segmented control replaces the slider and the degree readout. */
.view-presets{display:flex;gap:4px;background:#f3f4f6;border-radius:8px;padding:4px}
.view-presets button{min-height:44px;padding:0 16px;border-radius:6px;font-size:13px;
  color:var(--muted);white-space:nowrap}
.view-presets button[aria-pressed=true]{background:#fff;color:var(--ink);font-weight:600;
  box-shadow:0 1px 3px #10151b10}
.view-presets button:focus-visible{outline:2px solid var(--brand);outline-offset:2px}

@media(prefers-reduced-motion:reduce){
  .preview-object,.preview-panel.cover,.preview-face::after,.card3d-ground{transition:none!important}
}

/* v4.6 phase 1 — the stage is a fixed box; the card is sized to fit it at any
   yaw the drag allows (±60° of the active preset). Previously the stage height
   was derived from 100dvh − 505px and then overridden by a 520px min-height,
   which at 1280×800 pushed .canvas-actions entirely below the viewport and
   still let the opened card escape the top of the stage into .canvas-hint.
   --yaw-k and --open-k are the bounding-box growth of a flat sheet and of an
   opened folded card at the yaw extremes, measured in-browser at 1280×800 and
   1366×768. Height is what matters: aspect-ratio turns the max-width below
   into a flat height of (stage − pad) / k, so the rotated box lands on the
   stage edge rather than past it. */
.workspace{--stage-pad:48px;--yaw-k:1.40;--open-k:1.00}
.workspace .stage{height:var(--stage-height);min-height:0}
.workspace .paper-wrap.is-preview,
.workspace .paper-wrap.is-preview.portrait{
  max-width:min(530px,calc((var(--stage-height) - var(--stage-pad))*var(--ratio)/var(--yaw-k)),100%)}
/* The opened sheet is scaled .62 and pushed 43% right, so its right edge lands
   at .577 of its own max-width from the centre. On a narrow stage the height
   term alone let it run off the side, so width is a third bound here. */
.workspace .paper-wrap.is-preview.opened,
.workspace .paper-wrap.is-preview.portrait.opened{
  max-width:min(690px,calc((var(--stage-height) - var(--stage-pad))*var(--ratio)/var(--open-k)),86%)}

/* v4.6 phase 2 — pages as physical spreads
   The status was colour + icon with its meaning in a title attribute on an
   aria-hidden span (WCAG 1.4.1, and it reached no keyboard user). It is now a
   text chip under every page. pageStatus() already returned a specific action
   label for all eight states in both languages - they were simply not shown. */
.spread-strip{display:flex;gap:26px;align-items:flex-start;justify-content:center;
  width:100%;padding:10px 0 4px;flex-wrap:wrap}
.spread{display:flex;flex-direction:column;gap:6px;align-items:center}
.spread-label{font-size:11px;font-weight:600;color:var(--muted);letter-spacing:.04em;
  text-transform:uppercase}
/* two joined pages with a single fold line between them */
.spread-pages{display:flex;align-items:flex-start;border-radius:8px}
.spread-pages>*+*{border-left:1px solid var(--line)}
.page-tab{display:flex;flex-direction:column;align-items:center;gap:6px;
  padding:8px 10px 9px;min-width:64px;min-height:44px;background:none;border:0;
  border-radius:8px;color:var(--muted);font-size:11px}
.page-tab .page-mini{display:block;width:134px;height:96px;overflow:hidden;
  border:2px solid transparent;border-radius:4px;background:#fff;
  box-shadow:0 1px 4px #10151b18}
.page-tab.portrait .page-mini{width:69px;height:96px}
.page-tab .page-mini svg{width:100%;height:100%;display:block}
.page-tab .page-name{font-size:11px;line-height:1.2}
.page-tab[aria-selected=true]{color:var(--brand-dark);font-weight:600}
.page-tab[aria-selected=true] .page-mini{border-color:var(--brand-dark)}
.page-tab:focus-visible{outline:2px solid var(--brand);outline-offset:2px}
.page-tab.is-blank{opacity:1;cursor:default}
.page-tab.is-blank .page-mini{background:var(--subtle)}

/* Status, written out. Never an icon on its own. */
.status-chip{display:inline-flex;align-items:center;gap:4px;font-size:10px;
  line-height:1.3;max-width:96px;text-align:left}
.status-chip svg{width:11px;height:11px;flex:none}
.status-chip.ready{color:var(--brand-dark)}
.status-chip.pending{color:#805500}
.status-chip.blank{color:color-mix(in srgb,var(--ink) 50%,transparent)}
.status-chip.pulse{animation:chip-pulse 900ms ease-out 1}
@keyframes chip-pulse{
  0%{transform:scale(1)} 25%{transform:scale(1.14)} 60%{transform:scale(1)}
  0%,100%{opacity:1} 30%{opacity:.55}
}
@media(prefers-reduced-motion:reduce){.status-chip.pulse{animation:none}}
@media(max-width:760px){
  .spread-strip{gap:14px;padding:8px 0 2px}
  .page-tab .page-mini{width:92px;height:66px}
  .page-tab.portrait .page-mini{width:47px;height:66px}
  .status-chip{font-size:9px;max-width:74px}
}


/* ── Strip and stage, sized together ─────────────────────────────────────
   Phase 2 shipped the strip with a flat 96px miniature and loose internals:
   200px tall, which put .canvas-actions at 826px in an 800px viewport. The
   miniature now scales with --mini-h and the internals are tightened so the
   strip's overhead matches --strip-chrome, which is what the stage subtracts. */
.spread-strip{gap:22px;padding:6px 0 2px}
.spread{gap:4px}
.spread-label{font-size:10px;line-height:1.3}
.page-tab{padding:4px 8px 5px;gap:4px;min-height:0}
.page-tab .page-mini{height:var(--mini-h);width:calc(var(--mini-h)*1.4);box-shadow:0 1px 3px #10151b14}
.page-tab.portrait .page-mini{height:var(--mini-h);width:calc(var(--mini-h)*.72)}
.page-tab .page-name{font-size:10px;line-height:1.2}
.status-chip{font-size:10px;line-height:1.3}

/* The stage gives the card a little more room now the column is tight. */
.workspace .stage{padding:16px}
/* Phase 1 needed a --card-lift here: the old stage was a flex container that
   also held the ground element, and the card's projected box sat ~17% of its
   height too high. The card now lives in .card-layer, a clean absolutely
   positioned box that centres it on its own, and the correction measures zero
   - clearance is 41px top and bottom at 1280x800. The token is gone rather
   than pinned at 0, so nobody re-tunes a knob that no longer does anything. */
.workspace .paper-wrap.is-preview.opened{transform:scale(.62) translateX(43%)}
.workspace{--stage-pad:32px}

@media(max-width:760px){
  .spread-strip{gap:12px;padding:6px 0 2px}
  .page-tab{padding:4px 6px 5px}
}


/* The column is tight at 768px, so the workspace gives its own padding back to
   the stage. These two must stay in step with --canvas-gutter and
   --canvas-hint above; the verify script fails if they drift. */
@media(min-width:761px){.workspace{margin:8px 24px 8px 0;padding:12px 24px}} /* desktop only: unguarded it beat the phone margins (v4.7 phase 10) */
.canvas-hint{margin-top:8px}


/* The strip's height has to be predictable or the budget above is fiction.
   Portrait miniatures are narrow, so the page name and the status label both
   wrapped and the strip grew 32px past its token - enough to push the status
   chips behind the price bar at 1280x800. The name is now one line and the
   chip is a fixed two-line box, so the tallest case IS the normal case. */
.page-tab{min-width:88px}
.page-tab .page-name{white-space:nowrap}
.status-chip{max-width:none;height:26px;overflow:hidden;align-items:flex-start}
.status-chip svg{margin-top:1px}

/* ═══ v4.6 phase 2b — spreads as sheets, tonal stage ═══════════════════════
   The brief's token snippet names --bg and --text; this project has neither,
   and the established mapping (HANDOVER, phase 1) is --page and --ink. Used
   verbatim the color-mix() would be invalid and the declarations would drop
   silently, so the recipe is the brief's with those two substitutions. ORWO
   gets the same recipe below; because --brand differs there, the stage tints
   itself without a second set of hex values. */
[data-brand=orwo]{--stage:color-mix(in srgb,var(--brand) 7%,var(--page) 93%);
  --stage-deep:color-mix(in srgb,var(--brand) 13%,var(--page) 87%)}

/* ── Stage: one tonal ground, one shadow ───────────────────────────────── */
.workspace .stage{position:relative;overflow:hidden;border-radius:12px;
  background:linear-gradient(180deg,var(--stage) 0%,var(--stage-deep) 100%);
  padding:0;display:block}
.card-layer{position:absolute;inset:0;display:flex;align-items:center;
  justify-content:center;padding:16px}
/* The only shadow on the stage is the ground. Every drop-shadow the card used
   to carry is off: two shadows from one light source is what made the card
   read as a sticker rather than a sheet. */
.workspace .paper-wrap,.workspace .paper-wrap.is-preview{filter:none}
.card3d-ground{left:50%;bottom:12%;
  width:calc(var(--card-w,300px)*.9);height:calc(var(--card-h,200px)*.1);
  background:radial-gradient(ellipse,rgba(0,0,0,.35) 0%,transparent 70%);
  filter:blur(10px);opacity:var(--ground-opacity,0)}
/* Face shading: the 0.06 ceiling is in the gradient, so --yaw-shade is a
   plain 0..1 angle term and the cap cannot drift out of the JS. */
.preview-face::after{background:linear-gradient(105deg,rgba(0,0,0,.06),
  rgba(0,0,0,0) 55%,rgba(255,255,255,.045))}

/* ── Hint and presets float inside the stage ───────────────────────────── */
.workspace .canvas-hint{position:absolute;top:10px;left:14px;z-index:2;margin:0;
  max-width:58%;text-align:left;font-size:12px;pointer-events:none;
  color:color-mix(in srgb,var(--ink) 60%,transparent)}
.workspace .preview-controls{position:absolute;left:50%;bottom:12px;z-index:3;
  transform:translateX(-50%)}
.workspace .preview-controls:empty{display:none}
.view-presets{height:44px;padding:4px;border-radius:999px;background:var(--surface);
  border:1px solid var(--paper-edge);box-shadow:none}
.view-presets button{min-height:36px;border-radius:999px;padding:0 18px}

/* ── The strip: sheets, not cards ──────────────────────────────────────── */
.spread-strip{display:flex;gap:28px;align-items:flex-start;justify-content:center;
  width:100%;padding:6px 0 2px;flex-wrap:wrap}
.sheet{position:relative;display:grid;grid-template-columns:1fr 1fr;
  column-gap:0;align-items:start}
/* One rectangle behind both halves, creased at 50%. Drawing the sheet once,
   behind the halves, is what makes two pages read as one folded object. */
.sheet-paper{position:absolute;left:0;right:0;top:0;height:var(--mini-h);
  border:1px solid var(--paper-edge);border-radius:4px;background:var(--surface)}
.sheet.is-folded .sheet-paper::before{content:'';position:absolute;top:0;bottom:0;
  left:50%;width:1px;background:var(--paper-edge);transform:translateX(-.5px)}
.sheet.is-folded .sheet-paper::after{content:'';position:absolute;top:0;bottom:0;
  left:calc(50% - 12px);width:24px;pointer-events:none;
  background:linear-gradient(90deg,transparent 0%,rgba(0,0,0,.05) 48%,
    rgba(0,0,0,.05) 52%,transparent 100%)}
.sheet-flip{position:absolute;top:calc(var(--mini-h)/2);left:50%;
  width:16px;height:16px;margin:-8px 0 0 -8px;z-index:2;
  color:color-mix(in srgb,var(--ink) 50%,transparent);
  background:var(--surface);border-radius:50%}
.sheet-flip svg{width:16px;height:16px;display:block}

.page-tab{position:relative;display:flex;flex-direction:column;align-items:center;
  gap:4px;padding:0;min-width:0;background:none;border:0;border-radius:0;
  color:var(--muted);font-size:11px}
.half-mini{position:relative;display:grid;place-items:center;width:100%;
  height:var(--mini-h);border-radius:4px;overflow:hidden}
.page-tab .page-mini{display:block;width:auto;height:calc(var(--mini-h) - 10px);
  aspect-ratio:1.4;background:none;border:0;box-shadow:none}
.page-tab.portrait .page-mini{aspect-ratio:.72}
.page-tab .page-mini svg{width:100%;height:100%;display:block}
/* The ring is on the half, not the sheet: the selection is a page. */
.page-tab[aria-selected=true] .half-mini{box-shadow:inset 0 0 0 2px var(--brand)}
.page-tab[aria-selected=true]{color:var(--brand-dark);font-weight:600}
.page-tab:focus-visible{outline:none}
.page-tab:focus-visible .half-mini{outline:2px solid var(--brand);outline-offset:2px}
.page-tab .page-name{margin-top:6px;white-space:nowrap;font-size:10px;line-height:1.2}
.page-tab.is-blank{cursor:default}

@media(max-width:760px){
  .spread-strip{gap:16px}
  .workspace .canvas-hint{font-size:11px;max-width:52%}
}

/* ── Chrome gives way on short viewports ───────────────────────────────────
   At 1366x768 the fixed chrome above and below the canvas was 270px of a
   768px screen. These three bands lose 44px between them so the stage can
   hold its 320px floor; measureChrome() re-reads --header-h/--bottombar-h
   after the media query applies, so the budget follows automatically.
   Desktop only (guards added in v4.7 phase 10): unguarded, these rules beat the
   mobile ones and left the phone workspace flush left - 0px one side, 24px
   the other - with 28px footer gutters and a 72px header. */
@media(min-width:761px){.workspace{margin:6px 24px 6px 0;padding:6px 24px}}
@media(max-height:899px) and (min-width:761px){
  #header{min-height:72px}
  .editor-top{min-height:56px;padding:8px 28px}
  .editor-footer{padding:8px 28px}
  .editor-footer .price strong{font-size:19px}
  .editor-footer .order-summary strong{font-size:14px}
}

/* The miniature is artwork ON the sheet, not a card in front of it. Filling the
   half edge to edge hid the crease and the sheet's own border behind an opaque
   white rectangle, so each sheet read as two separate tiles. Inset the artwork
   and the paper shows around it - including the 1px crease and its shade in the
   gutter between the halves, which is the whole point of drawing a sheet. */
.sheet .page-tab .page-mini{height:calc(var(--mini-h) - 12px);width:auto;background:none}
.sheet .page-tab.portrait .page-mini{aspect-ratio:.72}
.sheet .page-tab:not(.portrait) .page-mini{aspect-ratio:1.4}
.sheet .half-mini{padding:6px}
/* The selection ring hugs the artwork's half of the sheet, inset by 2px so it
   reads as the page being chosen rather than a box drawn over the paper. */
.page-tab[aria-selected=true] .half-mini{box-shadow:inset 0 0 0 2px var(--brand);border-radius:4px}

/* The sheet has to be the size of the paper, not the size of the longest status
   label. Left to the grid, "Check example text" set the column width and a
   10x14 page ended up floating in a sheet twice its width. The halves are sized
   from the artwork; the label and chip sit under their half and may use the
   gap between sheets, which is what the gap is for. */
.sheet{--art-h:calc(var(--mini-h) - 12px);
  --half-w:max(calc(var(--art-h)*1.4 + 12px),88px);
  grid-template-columns:repeat(2,var(--half-w))}
.sheet.portrait{--half-w:max(calc(var(--art-h)*.72 + 12px),88px)}
.sheet .page-tab{min-width:0;overflow:hidden}
/* 88px is the floor the LABELS need, not a guess at the paper: it is what
   "Check example text" needs to wrap to two lines beside its dot, and what
   keeps "Inside left" off "Inside right". Sizing purely from the artwork made
   a 10x14 sheet tight and lovely and then overlapped both. A portrait sheet is
   therefore wider than its pages; the alternative was truncating a status the
   customer is being asked to act on. */
.sheet .page-tab .page-name,.sheet .page-tab .status-chip{
  max-width:var(--half-w);margin-inline:auto;justify-content:center;text-align:center}
.sheet .page-tab .status-chip{width:100%}

/* ═══ v4.6 phase 3b — format tiles, icons at scale ════════════════════════
   The tile shows the format and nothing else. The miniature had been the phase
   2b sheet with a 45px icon inside it - a box inside a box, and the icon too
   small to read either way. The sheet is gone: the icon sits directly on the
   tile's image area, at roughly double the v4.5 size, and carries the tile.

   The shapes are the original assets/format-icons drawings, untouched. Only the
   paints are tokens now, which is what lets the photo placeholder deepen on the
   selected tile and lets ORWO retint the whole set from --brand without a
   second set of artwork. --text and --bg do not exist here; the project's
   mapping is --ink and --page (HANDOVER, phase 1). */
.fmt-strip{--fmt-h:132px;display:grid;grid-template-columns:repeat(4,minmax(0,1fr));
  gap:12px;max-width:1360px;margin:28px auto}

/* Image area: one 4:3 band per tile, the stage gradient behind it, rounded at
   the top only because the text block below finishes the card. */
.fmt-card-art{position:relative;width:100%;aspect-ratio:4/3;display:grid;
  place-items:center;border-radius:8px 8px 0 0;overflow:hidden;
  /* Lightened for the tile only - 4%/8% instead of the editor stage's 7%/13% -
     so a pale icon still separates from a white tile. Scoped here rather than
     redefining --stage globally, which would also lighten the 3D stage that was
     already signed off in 2b. */
  --stage:color-mix(in srgb,var(--brand) 4%,var(--page));
  --stage-deep:color-mix(in srgb,var(--brand) 8%,var(--page));
  background:linear-gradient(180deg,var(--stage) 0%,var(--stage-deep) 100%)}
/* Height drives it and the width follows the viewBox, so the panorama comes out
   wide and the 10x14 upright. The source files were framed in a 120x100 box the
   drawing only filled 55-67% of, which is why the icon looked lost in the tile:
   the viewBox is now the drawing's own bounds, so 112px of icon is 112px of
   card. The shapes are untouched - this is framing, not redrawing.

   Weight: ONE 1px non-scaling stroke at --ink 28%, and nothing on the icon is
   heavier. The 3b build stroked each panel's face at 1.5px, which doubled on
   the fold - two panels share that edge, so it was drawn twice at roughly twice
   the weight of every other line. The outline is now a separate group: panel 1
   closed, panel 2 open and missing the edge panel 1 already drew. */
.fmt-icon{display:block;height:var(--fmt-h);width:auto;max-width:88%;
  transition:transform 150ms ease;
  color:color-mix(in srgb,var(--ink) 28%,transparent);
  --fmt-paper:var(--paper);
  --fmt-paper-2:color-mix(in srgb,var(--ink) 3%,var(--paper));
  --fmt-depth:color-mix(in srgb,var(--ink) 3%,var(--paper));
  --fmt-photo:color-mix(in srgb,var(--brand) 26%,var(--paper));
  --fmt-photo-2:color-mix(in srgb,var(--brand) 42%,var(--paper));
  --fmt-rule:color-mix(in srgb,var(--ink) 14%,transparent)}
.fmt-icon-svg{height:100%;width:auto;display:block;overflow:visible}

/* The tile: image band, then the text block. */
.fmt-card{position:relative;display:flex;flex-direction:column;align-items:stretch;
  gap:0;min-height:44px;padding:0;text-align:left;border-radius:8px;overflow:hidden;
  border:1px solid var(--paper-edge);background:var(--surface);
  transition:border-color var(--motion)}
.fmt-card:hover{border-color:color-mix(in srgb,var(--brand) 50%,transparent)}
.fmt-card:hover .fmt-icon{transform:translateY(-2px)}
.fmt-card.selected{border:2px solid var(--brand)}
.fmt-card:focus-visible{outline:2px solid var(--brand-dark);outline-offset:2px}
/* Selection reads in the image, not only at the edge. */
.fmt-card.selected .fmt-icon{
  --fmt-photo:color-mix(in srgb,var(--brand) 38%,var(--paper));
  --fmt-photo-2:color-mix(in srgb,var(--brand) 56%,var(--paper))}

.fmt-meta{display:flex;flex-direction:column;gap:2px;min-width:0;width:100%;padding:16px}
.fmt-name{font-weight:600;color:var(--ink);font-size:15px;line-height:1.2}
.fmt-price{font-weight:700;font-size:1.25em;line-height:1.15;color:var(--ink)}
.fmt-conseq{font-weight:400;font-size:.875em;line-height:1.25;
  color:color-mix(in srgb,var(--ink) 70%,transparent)}
.fmt-tick{position:absolute;top:10px;right:10px;width:22px;height:22px;border-radius:50%;
  background:var(--brand);color:var(--on-primary);display:grid;place-items:center;z-index:2}
.fmt-tick svg{width:14px;height:14px}
[data-brand=orwo] .fmt-tick{color:#fff}

.format-grid{display:block}
.fmt-strip.in-gallery{margin:28px auto}

/* Editor pill: the same icon, small, no image band. */
.fmt-switch{position:relative}
.fmt-pill{display:flex;align-items:center;gap:10px;min-height:44px;padding:6px 12px;
  border:1px solid var(--line);border-radius:999px;background:var(--surface)}
.fmt-pill:hover{border-color:var(--brand-dark)}
.fmt-pill:focus-visible{outline:2px solid var(--brand-dark);outline-offset:2px}
.fmt-pill .fmt-icon{--fmt-h:30px;height:30px}
.fmt-pill-meta{display:flex;align-items:baseline;gap:8px;white-space:nowrap}
.fmt-pill-name{font-weight:600;font-size:14px}
.fmt-pill-price{font-weight:700;font-size:14px}
.fmt-pill svg.icon{width:16px;height:16px;color:var(--muted)}

.fmt-popover{position:absolute;top:calc(100% + 8px);right:0;z-index:60;
  background:var(--surface);border:1px solid var(--line);border-radius:12px;
  padding:14px;box-shadow:0 18px 50px #10151b24;width:min(880px,88vw)}
.fmt-popover[hidden]{display:none}
.fmt-popover .fmt-strip{margin:0;gap:10px;--fmt-h:104px}
.fmt-inline{width:100%;padding:6px 0 2px}
.fmt-inline .fmt-strip{margin:0;gap:10px}

@media(max-width:1279px){.fmt-strip{--fmt-h:116px}}
@media(max-width:760px){
  .fmt-strip{--fmt-h:104px;display:flex;gap:10px;overflow-x:auto;scroll-snap-type:x mandatory;
    -webkit-overflow-scrolling:touch;padding:2px 16px 8px;margin:16px -16px 0;max-width:none}
  .fmt-card{flex:0 0 70vw;scroll-snap-align:start;min-width:0}
  .fmt-meta{padding:14px}
  .fmt-name,.fmt-price,.fmt-conseq{white-space:nowrap}
  .fmt-popover{position:fixed;left:12px;right:12px;top:auto;bottom:12px;width:auto}
}

/* CONFIG.FORMAT_SWITCH_IN_EDITOR = 'inline' puts the strip permanently under
   the card. That is a whole extra band in a column that is already tight, so
   it declares its height to the budget rather than silently pushing
   .canvas-actions off the bottom, and its cards go compact: miniature beside
   the text, not above it. */
/* Declared on :root, not on .workspace: --stage-h is computed where it is
   DECLARED, so a var() it references resolves against :root's own value. Set
   on .workspace this read 0px and the stage never gave the band its height.
   The floor drops with it: the inline strip is 120px the stage no longer has,
   and holding 320px on top of that simply does not fit at 1280x800. A variant
   that overflows is not a variant, it is a bug with a flag on it. */
:root:has(.fmt-inline){--canvas-inline:120px;--stage-floor:240px}
.fmt-inline .fmt-strip{--fmt-h:56px;gap:8px}
.fmt-inline .fmt-card{flex-direction:row;align-items:center;gap:10px;padding:8px 10px}
.fmt-inline .fmt-card.selected{padding:7px 9px}
.fmt-inline .fmt-card-art{width:auto;height:var(--fmt-h)}
.fmt-inline .fmt-name{font-size:13px}
.fmt-inline .fmt-price{font-size:14px}
.fmt-inline .fmt-conseq{font-size:11px}
.fmt-inline .fmt-tick{top:4px;right:4px;width:16px;height:16px}
.fmt-inline .fmt-tick svg{width:10px;height:10px}

/* The phone showed a <select> for format because the old four-up grid could not
   fit. The snap strip can, so the select goes and the silhouettes survive on the
   screen where they matter most. (Selector matches the mobile rule that hides
   it — `.gallery > .format-grid` — or specificity keeps it hidden.) */
@media(max-width:760px){
  .gallery>.format-grid{display:block}
  .mobile-format{display:none}
}

/* ═══ v4.6 phase 4 — design rail ═══════════════════════════════════════════
   The right column of the editor, so step 1 is revisitable without Back. Its
   miniatures are the real shop fronts in the format the customer is on, framed
   by the 2b sheet. Never an icon: an icon says "a card", and the rail exists to
   say WHICH card. */
.design-rail{display:flex;flex-direction:column;min-height:0;min-width:0;
  border-left:1px solid var(--line);background:var(--surface)}
.rail-head{flex:none;display:grid;gap:6px;padding:14px 16px 12px;
  border-bottom:1px solid var(--line)}
.rail-label{font-size:11px;letter-spacing:.12em;text-transform:uppercase;
  font-weight:600;color:var(--muted)}
.rail-current-name{font-size:15px;font-weight:600;color:var(--ink);line-height:1.2}
.rail-search{margin-top:4px;max-width:none}
.rail-search input{height:40px;font-size:13px;background:#f3f4f6;border:0;border-radius:8px}
/* min-height:0 is what stops the grid pushing the column taller than its
   parent; without it the rail scrolls the PAGE instead of itself. */
.rail-grid{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;
  display:grid;grid-template-columns:1fr 1fr;gap:8px;padding:12px 16px 20px;align-content:start}
.rail-empty{grid-column:1/-1;padding:24px 4px;color:var(--muted);font-size:13px}

.rail-card{position:relative;display:grid;gap:6px;padding:6px;border-radius:8px;
  border:1px solid transparent;background:none;text-align:left;min-width:0}
.rail-card:hover{border-color:color-mix(in srgb,var(--brand) 50%,transparent);
  background:color-mix(in srgb,var(--brand) 5%,transparent)}
.rail-card:focus-visible{outline:2px solid var(--brand-dark);outline-offset:1px}
.rail-card.current{border:2px solid var(--brand);padding:5px}
/* German names run past a 106px column - "Goldenes Henna-Muster" needs 135px -
   and an ellipsis there hides the very word that tells the designs apart. The
   name wraps instead; the grid's rows are auto, so a taller card costs nothing
   but a taller card. */
.rail-name{font-size:11px;line-height:1.25;color:var(--ink);
  white-space:normal;overflow-wrap:anywhere}
.rail-current{position:absolute;top:8px;right:8px;z-index:2;font-size:9px;font-weight:600;
  letter-spacing:.04em;text-transform:uppercase;padding:2px 6px;border-radius:999px;
  background:var(--brand);color:var(--on-primary)}
[data-brand=orwo] .rail-current{color:#fff}

/* The 2b sheet, one panel: 1px --paper-edge, 4px radius, --paper fill, and the
   fold as a 1px line with its 12px crease shade - only when the card folds. */
.rail-sheet{position:relative;display:block;width:100%;aspect-ratio:4/3;
  border:1px solid var(--paper-edge);border-radius:4px;background:var(--paper);
  overflow:hidden}
.rail-art{width:100%;height:100%;object-fit:cover;display:block}
/* The crease sits at 50%, as it does on the 2b sheet - and as it does in the
   artwork, because the shop previews for a folded card are the spread, so the
   real fold is down the middle. At the left edge it read as a spine on an image
   that plainly was not one. */
.rail-sheet.is-folded .rail-paper{position:absolute;top:0;bottom:0;
  left:calc(50% - 12px);width:24px;z-index:1;pointer-events:none;
  background:linear-gradient(90deg,transparent 0%,rgba(0,0,0,.05) 48%,
    rgba(0,0,0,.05) 52%,transparent 100%)}
.rail-sheet.is-folded .rail-paper::after{content:'';position:absolute;top:0;bottom:0;
  left:12px;width:1px;background:var(--paper-edge)}

/* Three columns from 1280; the rail narrows before the canvas does. */
@media(min-width:1280px){
  .edit-layout{grid-template-columns:300px minmax(0,1fr) 320px}
  .change-design-chip{display:none}
}
@media(min-width:1024px) and (max-width:1279px){
  .edit-layout{grid-template-columns:280px minmax(0,1fr) 280px}
  .change-design-chip{display:none}
}

/* Below 1024 the rail is a bottom sheet behind a chip beside the design title. */
@media(max-width:1023px){
  .design-rail{position:fixed;left:0;right:0;bottom:0;z-index:80;max-height:76vh;
    border-left:0;border-top:1px solid var(--line);border-radius:14px 14px 0 0;
    box-shadow:0 -18px 50px #10151b26;transform:translateY(102%);
    transition:transform 260ms cubic-bezier(.2,.7,.2,1);visibility:hidden}
  /* The open state is a class on the RAIL, not a body-descendant selector.
     As `body.design-sheet-open .design-rail` the visibility applied and the
     transform did not - the element sat one height below the fold with the
     scrim over an empty screen. Same specificity story on paper; not worth
     arguing with when a class on the element itself is unambiguous. */
  .design-rail.is-open{transform:none;visibility:visible}
  body.design-sheet-open{overflow:hidden}
  .rail-scrim{position:fixed;inset:0;z-index:79;background:#10151b4d}
  .rail-scrim[hidden]{display:none}
  .rail-grid{grid-template-columns:repeat(3,1fr)}
  .change-design-chip{display:inline-flex}
}
@media(max-width:600px){.rail-grid{grid-template-columns:1fr 1fr}}
@media(prefers-reduced-motion:reduce){.design-rail{transition:none}}

.change-design-chip{margin-left:14px;min-height:36px;padding:0 12px;font-size:12px;
  border:1px solid var(--line);background:var(--surface)}

/* The undo toast carries a real button, not just a word. */
#toast.has-action{display:flex;align-items:center;gap:16px}
.toast-undo{color:#fff;font-weight:600;text-decoration:underline;font-size:13px;
  min-height:32px;padding:0 4px}

/* ═══ v4.6 phase 5 — 44px tap targets in the editor toolbar ════════════════
   The base .icon-btn is 44x44 and .segmented button 38px, then five later
   layers shrink them to 32x40 / 36x40 / 36px. Nothing re-grew them, so the
   mode switch and the undo/redo/fullscreen buttons have been under the 44px
   floor at every desktop width. Restored here, at the end, because that is how
   this stylesheet resolves anything. */
.workspace-toolbar .segmented button{min-height:44px}
.workspace-tools .icon-btn{width:44px;height:44px}
@media(max-width:760px){
  .workspace-tools .icon-btn{width:44px;height:44px}
}

/* ── Phase 5: the editor header at phone widths ────────────────────────────
   .editor-top is a nowrap flex row. Phase 3 put the format pill in it, and at
   320px the title block (252px) plus the pill (291px) came to 543px in a 320px
   viewport - the page scrolled sideways. The row wraps now and the pill gives
   way: it keeps the silhouette and the name, and drops the price, which the
   price bar carries anyway and in larger type. */
@media(max-width:760px){
  .editor-top{flex-wrap:wrap;gap:8px 12px}
  .editor-top .project-name{min-width:0;flex:1 1 auto}
  .editor-top h1{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .fmt-switch{min-width:0;flex:0 1 auto}
  .fmt-pill{min-width:0;max-width:100%}
  .fmt-pill-meta{min-width:0;overflow:hidden}
  .fmt-pill-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
}
@media(max-width:600px){.fmt-pill-price{display:none}}

/* ── Phase 5: the last tap targets under 44px ──────────────────────────────
   All pre-existing: the language toggle, the Back button once its label is
   hidden, and the mobile category select. The 44px floor applies to them too. */
.lang-btn{min-width:44px;min-height:44px}
.editor-top [data-action=back-gallery]{min-width:44px;min-height:44px}
.mobile-category select,.mobile-format select{min-height:44px}
.gallery-controls .field,.rail-search input{min-height:44px}

/* The base #toast is pointer-events:none - correct for a message that must not
   block the card behind it, and fatal for one carrying a button. The Undo that
   is the entire safety net for applying a design without confirming could not
   be clicked; only the toast with an action takes pointer events back. */
#toast.has-action{pointer-events:auto}

/* ═══ v4.6 phase 6 — stage tone and the axis you turn the card on ══════════
   The stage was a gradient from --stage to --stage-deep. At the sizes it is
   actually drawn that does not read as one surface lit from above; it reads as
   a grey band sitting on a teal band, with a visible seam across the middle.
   One flat tone, a little stronger than the old top end. */
.workspace .stage{background:var(--stage)}
:root{--stage:color-mix(in srgb,var(--brand) 12%,var(--page))}
[data-brand=orwo]{--stage:color-mix(in srgb,var(--brand) 12%,var(--page))}

/* An open card turns on its SPINE. With the default centre origin the axis ran
   through the plane of the inside-right/back page, so dragging swung the card
   about a line lying on the back of it - which is what read as wrong, even
   though the fold was already centred in the stage. The origin moves to the
   object's left edge, where the cover is hinged and therefore where the fold
   is, and the wrap shifts 50% to put that fold back on the stage's centre line.
   Measured across the whole drag range (270-390 degrees): fold offset 0px,
   worst horizontal clearance 37px. The card sweeps a wider arc this way than
   about its own centre - that is what turning on a spine looks like. */
.workspace .paper-wrap.is-preview.opened .preview-object{transform-origin:0% 50%}
.workspace .paper-wrap.is-preview.opened{transform:scale(.62) translateX(50%)}

/* The rail's category chips: step 1's filters, so the rail can be browsed.
   They sit under the search field and wrap; the rail is narrow and the German
   names are long, so a horizontal scroller would hide the last two. */
.rail-chips{display:flex;flex-wrap:wrap;gap:6px;padding:10px 16px 0}
.rail-chip{min-height:44px;min-width:44px;height:auto;padding:8px 12px;font-size:11px;line-height:1.25;
  border-radius:8px;border:1px solid var(--line);background:var(--surface);color:var(--muted)}
.rail-chip:hover{border-color:color-mix(in srgb,var(--brand) 50%,transparent)}
.rail-chip[aria-pressed=true]{background:var(--soft);border-color:var(--brand);
  color:var(--brand-dark);font-weight:600}
.rail-chip:focus-visible{outline:2px solid var(--brand-dark);outline-offset:2px}

/* The teal stage sat inside a grey workspace, and the two tones fought: a
   cool grey and a tinted teal at similar lightness read as a mistake rather
   than as a panel holding a stage. The workspace goes white and takes a light
   stroke instead, so the only colour in the canvas column is the stage the card
   sits on. */
.workspace{background:var(--surface);border:1px solid var(--line)}

/* ═══ White room, off-white card ═══════════════════════════════════════════
   The stage goes white, so the whole canvas column is one surface. The card
   then has to carry itself: --paper is a few percent of --ink over white, which
   is enough to separate the sheet from the room and to let the two pages of an
   open card read as two pages. Its 1px --paper-edge and the ground shadow do
   the rest. A pure-white card on a pure-white stage has nothing but the edge. */
:root{--stage:var(--page);--paper:color-mix(in srgb,var(--ink) 4%,var(--surface))}
[data-brand=orwo]{--stage:var(--page)}

/* ═══ v4.6 phase 7 — lighter card, calmer strip, one control language ══════ */

/* Lighter card: 2% ink over white, not 4%. Enough to separate the sheet from a
   white room; at 4% the pages read as grey card rather than paper. */
:root{--paper:color-mix(in srgb,var(--ink) 2%,var(--surface))}

/* The strip was box-in-box-in-box: a white sheet with a border, an inset grey
   page inside it, a crease gradient down the middle, then a ring on top. The
   sheet and its pages are now one surface in one tone - the artwork fills its
   half, the fold is a single 1px line, and the gradient is gone. */
.sheet-paper{background:var(--paper)}
.sheet .half-mini{padding:0}
.sheet .page-tab .page-mini{height:100%;width:100%;aspect-ratio:auto}
.sheet.is-folded .sheet-paper::after{display:none}

/* Status: the words stay, the colour quietens. Before, four chips wore four
   colours and one wrapped to two lines. Now only a BLOCKING status is in the
   warning tone - the thing that must be done before ordering. Advisory, ready
   and blank read in muted ink; their glyph carries the meaning, and the label
   still states it, so colour is never the only signal (WCAG 1.4.1). */
.status-chip.tone-quiet,.status-chip.tone-advisory{color:color-mix(in srgb,var(--ink) 62%,transparent)}
.status-chip.tone-blocking{color:#805500}
.status-chip.ready svg{color:var(--brand-dark)}
.status-chip.tone-advisory svg{color:color-mix(in srgb,var(--ink) 40%,transparent)}
/* Selection is carried by the ring on the half; the page name stays ink. */
.page-tab[aria-selected=true]{color:var(--ink);font-weight:600}

/* The mode switch sat on a #e9edef track - the darkest surface left in the
   canvas once everything else went white. It now uses the same language as the
   presets pill and the format pill: white track, light stroke, pill shape. */
.mode-switch{background:var(--surface);border:1px solid var(--line);border-radius:999px;padding:3px;gap:2px}
.mode-switch button{border-radius:999px}
.mode-switch button:not([aria-pressed=true]):hover{background:var(--soft)}
/* Filling the halves edge to edge hid the sheet's own 1px border under the
   page artwork, and a 2%-ink page on a white strip with no edge simply floats.
   The border and fold line now draw ABOVE the pages; the pages carry the fill. */
.sheet-paper{background:transparent;z-index:2;pointer-events:none}
.sheet .half-mini{background:var(--paper)}

/* ═══ v4.6 phase 8 — rail: occasion dropdown, no search; card tone ════════ */

/* One native select in place of the search field and six chips. White track
   and light stroke, the same language as the mode switch and the format pill.
   The chevron is drawn from borders in --muted rather than a data-URI SVG,
   which would need a hard-coded hex the token lanes do not allow. */
.rail-select-wrap{position:relative;display:block;margin-top:6px}
.rail-select-wrap::after{content:'';position:absolute;right:15px;top:50%;width:7px;height:7px;
  border-right:1.5px solid var(--muted);border-bottom:1.5px solid var(--muted);
  transform:translateY(-70%) rotate(45deg);pointer-events:none}
.rail-select{width:100%;height:44px;padding:0 38px 0 12px;font-size:13px;color:var(--ink);
  background:var(--surface);border:1px solid var(--line);border-radius:8px;
  appearance:none;-webkit-appearance:none;cursor:pointer}
.rail-select:hover{border-color:color-mix(in srgb,var(--brand) 50%,transparent)}
.rail-select:focus-visible{outline:2px solid var(--brand-dark);outline-offset:2px}

/* Card tone, third pass: 4% read as grey card, 2% disappeared into the white
   room. 3% is where the sheet holds its own without going grey. */
:root{--paper:color-mix(in srgb,var(--ink) 3%,var(--surface))}

/* ═══ v4.6 phase 9 — the card is the point: a much bigger preview ══════════
   Measured before this pass, at 1440x900 AND at 1920x1080: the 3D card was
   388x277 in both - identical - because four limits were stacked on it.

   1. A 420px ceiling on the stage. At 1080p the workspace was 798px tall and
      the stage still stopped at 420.
   2. A rotation factor of 1.40, when the card's real bounding-box growth at
      +/-60 degrees measures 1.20. The card gave up ~30% of its height to a
      margin it never needed.
   3. 530px / 690px width caps on the card.
   4. Chrome: the presets pill floated inside the stage, and the spread strip
      and header bands were sized for a roomier layout than this one. */

/* 1. No ceiling worth hitting. */
:root{
  --stage-h:clamp(320px,calc(100dvh - var(--header-h) - var(--bottombar-h)
    - var(--canvas-toolbar) - var(--strip-h) - var(--canvas-gutter)
    - var(--canvas-inline)),900px);
}
/* 2. Sized for the growth it actually has, plus a small margin. */
.workspace{--yaw-k:1.26}

/* KNOWN, AND LEFT AS IT IS: the 3D preview renders without perspective. Since
   phase 2b put the card in its own .card-layer, the stage's perspective no
   longer reaches it - setting the stage to 400px changes nothing - so the card
   rotates orthographically. Restoring it on .card-layer was tried in this pass
   and reverted: with perspective on, a rotated card projects off-centre and the
   card pokes out of the top of the stage (-8px at 1920x1080, worse on Open),
   which is exactly the skew phase 1's --card-lift was compensating for. The
   flat rendering is what every review since 2b has been looking at, and the
   sizing below is fitted to it. Bringing perspective back is a decision of its
   own, and needs a lift correction with it. */

/* 3. Width caps raised; the stage and the card-layer padding bound it now. */
.workspace .paper-wrap.is-preview,
.workspace .paper-wrap.is-preview.portrait{
  max-width:min(1100px,calc((var(--stage-height) - var(--stage-pad))*var(--ratio)/var(--yaw-k)),100%)}
.workspace .paper-wrap.is-preview.opened,
.workspace .paper-wrap.is-preview.portrait.opened{
  max-width:min(1400px,calc((var(--stage-height) - var(--stage-pad))*var(--ratio)/var(--open-k)),var(--open-w,86%))}
/* Edit mode never rotates, so it gets the whole stage. */
.workspace .paper-wrap:not(.is-preview),
.workspace .paper-wrap.portrait:not(.is-preview),
.workspace .paper-wrap.wide:not(.is-preview){
  max-width:min(100%,calc((var(--stage-height) - var(--stage-pad))*var(--ratio)))}

/* 4a. Presets live in the toolbar now, in the slot the "Your card" heading used
   (the heading stays, for screen readers). Out of the stage, they no longer sit
   on top of a card that has grown into the bottom of it. */
.workspace-toolbar .preview-controls{position:static;transform:none;justify-self:start}
.workspace-toolbar .preview-controls:empty{display:block}
.workspace-toolbar .view-presets{height:auto;padding:3px}
.workspace-toolbar .view-presets button{padding:0 14px;font-size:13px}

/* 4b. The mode switch keeps its 44px hit area but loses visual weight. */
.mode-switch button{font-size:13px;padding:0 16px;gap:6px}
.mode-switch .icon{width:16px;height:16px}

/* 4c. The strip: smaller miniatures, tighter name and padding. The status box
   stays two lines (26px): five of the sixteen labels are wider than the 88px
   page tab on one line - "Beispielfoto ersetzen" 120px, "Foto hinzufügen"
   98px, "Text hinzufügen" 96px, "Replace sample" 95px, "Photo too small"
   94px - and a single-line box clipped them at every viewport. 58px is the
   66px of phase 8 less the 8px of name margin and padding taken out here. */
:root{--mini-h:clamp(40px,5vh,64px);--strip-chrome:58px}
.page-tab .page-name{margin-top:4px}
.spread-strip{padding:4px 0 0}

/* 4d. The compact header, editor bar and price bar now apply up to 1000px of
   viewport height instead of 899px, which takes in the 900px laptops this
   prototype is mostly reviewed on. Desktop only: without the width guard it
   also applied to phones, and put 28px gutters and a 72px header on them
   over the mobile rules (found in v4.7 phase 10). */
@media(max-height:1000px) and (min-width:761px){
  #header{min-height:72px}
  .editor-top{min-height:56px;padding:8px 28px}
  .editor-footer{padding:8px 28px}
  .editor-footer .price strong{font-size:19px}
  .editor-footer .order-summary strong{font-size:14px}
}
/* The open card's width cap, found by search rather than guessed: 78% is the
   largest that keeps the rotated V at least 16px inside the stage across the
   whole drag range at 1024, 1280, 1366, 1440 and 1920 (worst: 21px at 1024).
   The height term above is not what binds an open card - this cap is. */
:root{--open-w:78%}

/* 4e. Toolbar: mode switch left, presets in the middle, tools right. The
   three groups change width with language and brand typeface (German presets
   are 70px wider than English), so whether they fit on one row is measured on
   the rendered row by fitToolbar(), not guessed from the viewport. When they
   don't fit, the mode icons go and the gaps tighten (.is-compact), which
   costs no height; then the presets take a second row (.is-stacked); then
   both. fitToolbar() then writes
   the toolbar's real height into --canvas-toolbar, so the column budget
   always subtracts the rows that are actually there.
   Columns are pinned rather than auto-placed: in edit mode the empty preset
   slot is display:none (the older #preview-controls:empty rule outranks this
   layer), and auto-placement slid the tools into the middle column. The mode
   switch sits in the same place in both modes, so it never moves under the
   cursor that just clicked it. */
@media(min-width:761px){
  .workspace-toolbar{grid-template-columns:auto 1fr auto}
  .workspace-toolbar>*{min-width:max-content}
  .workspace-toolbar>.mode-switch{grid-column:1;grid-row:1;justify-self:start;margin:0}
  .workspace-toolbar>.preview-controls{grid-column:2;grid-row:1;justify-self:center}
  .workspace-toolbar>.workspace-tools{grid-column:3;grid-row:1;justify-self:end}
  .workspace-toolbar.is-stacked{row-gap:8px}
  .workspace-toolbar.is-stacked>.preview-controls{grid-column:1/-1;grid-row:2}
  .workspace-toolbar.is-compact{column-gap:12px}
  .workspace-toolbar.is-compact .mode-switch .icon{display:none}
  .workspace-toolbar.is-compact .view-presets button{padding:0 12px}
}

/* Ground shadow tracks the card, not the stage. It sat at a fixed 12% from
   the stage floor, which matched while the card filled the stage height;
   with the taller stage it floated ~70px under the open card. --card-h is
   the measured card box (sizeGround), and the card is centred in the layer,
   so this puts the ellipse's centre line on the card's bottom edge.
   --card-w/--card-h are the unscaled layout box; the open card's scale is one
   token read by both the card transform and the shadow, so they cannot drift.
   The ground paints under the card - its upper half is now behind the sheet,
   and in front of it the blur read as a grey smear across the card face. */
.workspace{--open-scale:.62}
.workspace .paper-wrap.is-preview.opened{transform:scale(var(--open-scale)) translateX(50%)}
.card-layer>.paper-wrap{z-index:1}
.card3d-ground{--s:1;bottom:auto;z-index:0;
  top:calc(50% + var(--card-h,200px)*var(--s)*.45);
  width:calc(var(--card-w,300px)*var(--s)*.9);height:calc(var(--card-h,200px)*var(--s)*.1);
  transition:transform 450ms cubic-bezier(.2,.7,.2,1),opacity 450ms cubic-bezier(.2,.7,.2,1),
    top 400ms ease,width 400ms ease,height 400ms ease}
.paper-wrap.opened~.card3d-ground{--s:var(--open-scale)}

/* ═══ v4.7 phase 10 — fixes ═══════════════════════════════════════════════
   Colour values are tokens only: new colours are defined in the last :root /
   [data-brand=orwo] block, component rules reference them. */

/* 10.1 The reviewer bar says when samples may go to the basket - a prototype
   setting a stakeholder should not mistake for shop behaviour. */
.review-flag{margin-left:10px;padding:1px 8px;border:1px solid var(--line);border-radius:999px;
  background:var(--surface);color:var(--muted);white-space:nowrap}
@media(max-width:760px){.review-flag{display:none}}

/* 10.2 CTA contrast. White on the core teal was 2.56:1 because line 63 set
   --on-primary to white over a --primary that was still the light brand teal.
   CONFIG.CTA_FILL picks the pair, via html[data-cta-fill]:
     brand-dark (default) - teal-dark fill, white text   6.4:1
     dark-text            - brand teal fill, ink text    ~7:1
   The brand teal stays for identity - rings, ticks, the active step - where
   it carries no text. ORWO's near-black primary passes and is untouched. */
:root:not([data-brand=orwo]){--primary:var(--brand-dark);--on-primary:var(--surface)}
:root:not([data-brand=orwo])[data-cta-fill=dark-text]{--primary:var(--brand);--on-primary:var(--ink)}
:root{--primary-hover:color-mix(in srgb,var(--primary) 86%,var(--ink));
  --badge:var(--primary);--on-badge:var(--on-primary)}
[data-brand=orwo]{--badge:var(--brand);--on-badge:var(--ink)}
/* Every filled primary control reads the pair; earlier layers hard-coded white
   text, which would fail again the moment the fill changed. */
.btn.primary,.upload-hero .btn,.mode-switch button[aria-pressed=true]{background:var(--primary);color:var(--on-primary)}
@media(min-width:761px){.resume .btn.primary{background:var(--primary);color:var(--on-primary)}}
.btn.primary:hover,.upload-hero .btn:hover{background:var(--primary-hover);color:var(--on-primary);filter:none}
/* "Current": 11px minimum, and the same rule - it is text on a fill. */
.rail-current,[data-brand=orwo] .rail-current{font-size:11px;background:var(--badge);color:var(--on-badge)}
/* Inactive step numbers were #6b7280 on #f3f4f6, 4.39:1. */
.step b{color:var(--muted)}

/* 10.3 One contextual CTA. The label never wraps; below 360px the price leaves
   the label and sits to the left of the button, so "Prüfen · 9,90 €" never has
   to fit a 320px German footer. .price (the separate total beside the CTA) is
   gone - the pill and the CTA carry the price (10.7). */
.editor-footer .cta{white-space:nowrap}
.editor-footer .cta .icon{flex:none}
.price-group .cta-price{display:none;font-weight:600;font-variant-numeric:tabular-nums;white-space:nowrap}
.editor-footer .order-summary{min-width:0}
.editor-footer .order-summary strong,.editor-footer .order-summary small{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
@media(max-width:760px){.price-group .btn.cta{min-width:0}}
@media(max-width:359px){
  .price-group[data-state=review] .cta-price{display:inline-block}
  .cta .cta-label-price{display:none}
  .editor-footer .order-summary{display:none}
  .editor-footer .price-group{margin-left:auto}
}

/* 10.6 Crop by direct manipulation. A pannable slot shows it; while one is
   selected the card takes touch gestures instead of scrolling the page. */
.paper-wrap [data-slot].can-pan{cursor:grab}
.paper-wrap [data-slot].can-pan:active{cursor:grabbing}
.paper-wrap:has([data-slot].can-pan){touch-action:none;-webkit-user-select:none;user-select:none}
.crop-section .crop-actions{margin-top:12px;gap:8px;flex-wrap:wrap}
.crop-section .crop-actions .btn{min-height:44px}
.crop-section .photo-warning{margin-top:12px}
details.adjust{margin-top:12px;border-top:1px solid var(--line)}
details.adjust>summary{min-height:44px;display:flex;align-items:center;gap:8px;cursor:pointer;
  font-size:13px;font-weight:600;color:var(--ink);list-style:none}
details.adjust>summary::-webkit-details-marker{display:none}
details.adjust>summary::before{content:'';width:7px;height:7px;border-right:1.5px solid var(--muted);
  border-bottom:1.5px solid var(--muted);transform:rotate(-45deg);transition:transform var(--motion)}
details.adjust[open]>summary::before{transform:rotate(45deg)}
details.adjust .crop-grid{padding:4px 0 12px}
details.adjust>.btn{margin-bottom:8px}

/* 10.7 Cleanup ---------------------------------------------------------- */
/* Toast: top-centre of the stage (placeToast() measures it), never over the
   page navigation; falls back to the top of the page. */
#toast{top:var(--toast-top,96px);left:var(--toast-left,50%);bottom:auto;z-index:90;
  transform:translate(-50%,-8px)}
#toast.show{transform:translate(-50%,0)}
/* "Layout demo" is reviewer information; the reviewer bar already says
   "demonstration layouts". It leaves the customer's title. */
.editor-top h1::after,html[lang=de] .editor-top h1::after{content:none;display:none}
/* One instruction line in the tools panel. */
.panel .panel-hint{color:var(--muted);font-size:13px;margin-top:4px}
/* Undo / redo are hidden, not removed, in 3D: nothing to undo there, and the
   toolbar keeps its width so nothing moves when the view changes. */
.workspace-toolbar.is-3d [data-action=undo],.workspace-toolbar.is-3d [data-action=redo]{visibility:hidden}
/* ⋯ overflow menu next to undo/redo. */
.more-wrap{position:relative;display:inline-flex}
.more-menu{position:absolute;right:0;top:calc(100% + 6px);z-index:40;min-width:228px;padding:6px;
  background:var(--surface);border:1px solid var(--line);border-radius:10px;box-shadow:var(--shadow)}
.more-menu[hidden]{display:none}
.more-menu [role=menuitem]{display:flex;align-items:center;gap:10px;width:100%;min-height:44px;padding:0 12px;
  border-radius:6px;font-size:14px;text-align:left;color:var(--ink);white-space:nowrap}
.more-menu [role=menuitem]:hover,.more-menu [role=menuitem]:focus-visible{background:var(--subtle)}
.more-menu .icon{width:18px;height:18px;color:var(--muted)}
/* 3D presets: 44px targets everywhere, phones included. */
.view-presets,.workspace-toolbar .view-presets{height:auto}
.view-presets button,.workspace-toolbar .view-presets button{min-height:44px}
/* Language control names the target language. */
.lang-btn{min-height:44px;white-space:nowrap}
/* Design sheet (below 1024px): a drag handle and a labelled close button. */
.sheet-bar{display:none}
@media(max-width:1023px){
  .sheet-bar{display:flex;align-items:center;justify-content:center;position:relative;
    min-height:36px;padding-top:6px;touch-action:none;cursor:grab}
  .sheet-handle{width:40px;height:4px;border-radius:2px;background:color-mix(in srgb,var(--ink) 22%,transparent)}
  .sheet-close{position:absolute;right:6px;top:2px;width:44px;height:44px}
  .design-rail.is-open{transform:translateY(var(--sheet-drag,0px))}
  .design-rail.is-dragging{transition:none}
}
/* Mobile: the "Change design" chip centres its label; the stepper's active
   label never wraps. */
.change-design-chip{align-items:center;justify-content:center;line-height:1.2}
@media(max-width:760px){.step-name{white-space:nowrap;max-width:none}}

/* 10.8 Review page, found by the wider sweep (the phase 5 suite never visited
   it): the Edit buttons were 33-38px wide, and at 320px German "Bearbeiten"
   ran 18px past the viewport beside the page label. */
.review-card .row{flex-wrap:wrap;row-gap:2px}
.review-card [data-action=edit-side]{min-width:44px;min-height:44px}

/* ═══ v4.7 phase 11 — flow and layout ═══════════════════════════════════════ */

/* 11.0 The Variants menu in the reviewer bar became a one-click switch in
   review - see "the open variant" at the end of the file. */

/* 11.1 Gallery, design first. */
.gallery.is-design-first{padding-top:28px}
.gallery-hero{display:flex;align-items:center;justify-content:space-between;gap:24px;max-width:1360px;
  margin:0 auto 20px;max-height:160px}
.gallery-hero .hero-copy{min-width:0}
.gallery-hero h1{font-size:34px;line-height:1.15;letter-spacing:-.035em;margin:0}
.gallery-hero p{margin:6px 0 0;color:var(--muted);font-size:15px}
.hero-upload{flex:none;display:inline-flex;align-items:center;gap:10px;min-height:44px;padding:0 16px;
  font-size:14px;white-space:nowrap}
.hero-upload .icon{width:18px;height:18px}
.hero-upload-thumb{width:28px;height:28px;border-radius:50%;object-fit:cover}
.hero-upload-short{display:none}
/* The format row: one radiogroup, four segments. */
.fmt-row{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px;max-width:1360px;margin:0 auto 24px}
.fmt-seg{display:flex;align-items:center;gap:12px;min-height:72px;padding:7px 14px 7px 8px;text-align:left;
  border:1px solid var(--line);border-radius:10px;background:var(--surface);color:var(--ink)}
.fmt-seg:hover{border-color:color-mix(in srgb,var(--brand) 50%,var(--line))}
.fmt-seg.selected{border:2px solid var(--primary);background:var(--soft);padding:6px 13px 6px 7px}
.fmt-seg:focus-visible{outline:3px solid var(--brand-dark);outline-offset:2px}
.fmt-seg-meta{display:flex;flex-direction:column;gap:1px;min-width:0}
.fmt-seg-name{font-size:14px;font-weight:600;line-height:1.2;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.fmt-seg-price{font-size:13px;color:var(--muted);font-variant-numeric:tabular-nums}
.fmt-seg.selected .fmt-seg-price{color:var(--ink);font-weight:600}
.fmt-seg-icon{--icon-w:56px;flex:none;display:grid;place-items:center}
/* A3a: the unchanged v4.5 drawing on a tinted ground - its white face no
   longer merges with the white page. */
.fmt-seg-icon.is-ground{width:72px;height:57px;border-radius:8px;background:color-mix(in srgb,var(--brand) 15%,var(--surface))}
.fmt-seg-icon.is-ground img{width:var(--icon-w);height:auto;display:block}
/* A3b: the same drawing inline, on white, with a darker edge and a stronger
   photo tint - tokens, not hex. */
.fmt-seg-icon.is-strong{width:72px;height:57px}
.fmt-seg-icon.is-strong .fmt-icon-svg{width:var(--icon-w);height:auto;
  --fmt-depth:color-mix(in srgb,var(--ink) 45%,var(--surface));--fmt-paper:var(--surface);
  --fmt-paper-2:color-mix(in srgb,var(--ink) 5%,var(--surface));
  --fmt-photo:color-mix(in srgb,var(--brand) 30%,var(--surface));
  --fmt-photo-2:color-mix(in srgb,var(--brand) 70%,var(--surface));
  --fmt-rule:color-mix(in srgb,var(--ink) 30%,transparent);color:color-mix(in srgb,var(--ink) 45%,transparent)}
/* A1 fallback: the 3c tile component shrunk to 88px, icon beside the text. */
.format-grid.is-compact{margin:0 auto 24px;max-width:1360px}
.fmt-strip.is-compact{--fmt-h:48px;margin:0;gap:10px}
.fmt-strip.is-compact .fmt-card{flex-direction:row;align-items:center;gap:12px;min-height:88px;padding:8px 14px}
.fmt-strip.is-compact .fmt-card.selected{padding:7px 13px}
.fmt-strip.is-compact .fmt-card-art{width:auto;height:var(--fmt-h);aspect-ratio:auto;background:none;border-radius:0;flex:none}
.fmt-strip.is-compact .fmt-meta{padding:0;gap:1px}
.fmt-strip.is-compact .fmt-name{font-size:14px}
.fmt-strip.is-compact .fmt-price{font-size:15px}
.fmt-strip.is-compact .fmt-conseq{font-size:12px}
.fmt-strip.is-compact .fmt-tick{top:6px;right:6px;width:18px;height:18px}
.fmt-strip.is-compact .fmt-tick svg{width:11px;height:11px}
@media(max-width:1100px) and (min-width:761px){.fmt-seg-name{font-size:13px}.fmt-seg{gap:8px}}
/* Mobile: hero at most 120px, the row scrolls sideways at 60px. */
@media(max-width:760px){
  .gallery.is-design-first{padding:16px 16px 28px}
  .gallery-hero{gap:12px;margin:0 0 14px;max-height:120px}
  .gallery-hero h1{font-size:23px;line-height:1.18}
  .gallery-hero p{font-size:13px;margin-top:4px;line-height:1.4}
  .hero-upload{padding:0 12px;font-size:13px}
  .hero-upload-long{display:none}.hero-upload-short{display:inline}
  .fmt-row{display:flex;gap:8px;overflow-x:auto;scroll-snap-type:x mandatory;margin:0 -16px 16px;padding:2px 16px 4px;
    scrollbar-width:none}
  .fmt-row::-webkit-scrollbar{display:none}
  .fmt-seg{flex:0 0 auto;min-height:60px;scroll-snap-align:start;padding:5px 12px 5px 6px;gap:8px}
  .fmt-seg.selected{padding:4px 11px 4px 5px}
  .fmt-seg-icon{--icon-w:42px}
  .fmt-seg-icon.is-ground,.fmt-seg-icon.is-strong{width:54px;height:44px}
  .format-grid.is-compact{margin:0 -16px 16px}
  .fmt-strip.is-compact{padding:2px 16px 4px}
  .fmt-strip.is-compact .fmt-card{flex:0 0 auto;min-height:88px}
}

/* 11.2 / 11.3 View switching inside the page navigation (desktop).
   The canvas toolbar row is gone: its height goes to the stage and the
   navigation. fitNav() publishes the navigation row's real height as
   --strip-h and sets --nav-mini (80px when the row can hold it). The row's
   layout is at the end of the file ("The page row, second pass"). */
@media(min-width:761px){
  :root{--canvas-toolbar:0px;--mini-h:var(--nav-mini,80px)}
  .page-nav-row .side-tabs{min-width:0;display:flex;justify-content:center;padding:4px 0 6px}
  .page-nav-row .spread-strip{justify-content:safe center;padding:0;flex-wrap:nowrap;gap:12px}
  .page-tab .page-name{font-size:13px}
}
/* The quiet 3D control: cube + "3D", muted ink, no fill, no border. */
.view-3d{flex:none;display:inline-flex;align-items:center;justify-content:center;gap:6px;min-height:44px;min-width:56px;
  padding:0 10px;border:0;border-radius:8px;background:none;color:var(--muted);font-size:13px}
.view-3d .icon{width:16px;height:16px}
.view-3d:hover{color:var(--ink)}
.nav-divider{flex:none;align-self:stretch;width:1px;margin:6px 4px 30px;background:var(--line)}
/* B1: one button at the right end of the navigation row. */
.view-toggle{min-height:44px;gap:8px;margin-right:6px;white-space:nowrap;font-size:13px}
.view-toggle .icon{width:16px;height:16px}
/* A blocking status that is not the next thing to do reads in muted ink. */
.status-chip.tone-waiting{color:color-mix(in srgb,var(--ink) 62%,transparent)}
/* Blank and fixed pages are tabs now; they keep their quieter look. */
.page-tab.is-blank .half-mini{opacity:.72}
/* 3D: presets float at the bottom of the stage, and the card is sized and
   centred in the space above them - phase 9 took them out of the stage
   because a grown card ran underneath; this reserve is what lets them back. */
.workspace .stage .preview-controls{position:absolute;left:50%;bottom:12px;transform:translateX(-50%);z-index:3}
.workspace .stage .preview-controls:empty{display:none}
.workspace.is-3d{--pill-reserve:64px}
.workspace.is-3d .card-layer{padding-bottom:calc(16px + var(--pill-reserve))}
.workspace.is-3d .paper-wrap.is-preview,.workspace.is-3d .paper-wrap.is-preview.portrait{
  max-width:min(1100px,calc((var(--stage-height) - var(--stage-pad) - var(--pill-reserve))*var(--ratio)/var(--yaw-k)),97%)}
.workspace.is-3d .paper-wrap.is-preview.opened,.workspace.is-3d .paper-wrap.is-preview.portrait.opened{
  max-width:min(1400px,calc((var(--stage-height) - var(--stage-pad) - var(--pill-reserve))*var(--ratio)/var(--open-k)),var(--open-w,86%))}
.workspace.is-3d .card3d-ground{top:calc(50% - var(--pill-reserve)/2 + var(--card-h,200px)*var(--s)*.45)}
/* Undo / redo hidden in 3D (10.7), now in the navigation row. */
.workspace.is-3d .nav-left [data-action=undo],.workspace.is-3d .nav-left [data-action=redo]{visibility:hidden}
/* The tools panel says one line in 3D and on the address side. */
.sidebar.is-quiet .tabs{display:none}

/* 11.5 Review as a sheet (D2). Desktop: a 440px drawer from the right, over
   the rail. Phones: full height, with a handle and X. The page behind is
   inert while it is open. */
.review-scrim{position:fixed;inset:0;z-index:150;background:color-mix(in srgb,var(--ink) 28%,transparent)}
.review-scrim[hidden]{display:none}
.review-sheet{position:fixed;top:0;right:0;bottom:0;z-index:160;width:min(440px,100vw);display:flex;flex-direction:column;
  background:var(--surface);color:var(--ink);border-left:1px solid var(--line);box-shadow:var(--shadow);
  transform:translateY(var(--sheet-drag,0px))}
.review-sheet[hidden]{display:none}
.review-sheet.is-dragging{transition:none}
.rs-bar{flex:none;display:flex;align-items:center;gap:8px;min-height:56px;padding:6px 8px 6px 20px;border-bottom:1px solid var(--line)}
.rs-bar h2{flex:1;margin:0;font-size:18px;line-height:1.25;letter-spacing:-.01em}
.rs-bar h2:focus{outline:none}
.rs-bar .sheet-handle{display:none}
.rs-close{width:44px;height:44px;flex:none}
.rs-body{flex:1;overflow:auto;padding:16px 20px 20px}
/* The 3D stage reuses the workspace rules; only its box is reset here. */
.review-sheet .rs-workspace{margin:0 0 14px;padding:0;border:0;border-radius:0;background:none;height:auto;overflow:visible;
  --stage-height:280px;--stage-pad:24px;--pill-reserve:58px;box-shadow:none}
.review-sheet .rs-workspace .stage{height:var(--stage-height);border-radius:10px;background:var(--page);border:1px solid var(--line)}
.review-sheet .rs-workspace .stage .preview-controls{bottom:8px}
.rs-pages{--mini-h:52px;display:flex;flex-wrap:wrap;justify-content:center;gap:10px;margin:0 0 14px}
.rs-pages .page-tab{cursor:pointer}
.rs-summary h3{font-size:16px;margin:0}
.rs-summary p{margin:4px 0 0;font-size:13px;color:var(--muted);line-height:1.5}
.rs-qty{display:flex;align-items:center;gap:12px;margin-top:14px;font-size:14px}
.rs-qty .quantity{display:inline-flex;align-items:center;border:1px solid var(--line);border-radius:10px}
.rs-qty .quantity button{width:44px;height:44px;font-size:18px}
.rs-qty .quantity output{min-width:28px;text-align:center;font-weight:600;font-variant-numeric:tabular-nums}
.rs-qty .rs-cards{color:var(--muted);font-size:13px}
.rs-total{display:flex;justify-content:space-between;align-items:baseline;margin-top:14px;font-size:15px}
.rs-total strong{font-size:22px;letter-spacing:-.02em;font-variant-numeric:tabular-nums}
.rs-vat,.rs-demo{margin:2px 0 0;font-size:12px;color:var(--muted)}
.rs-demo{margin-top:12px}
.rs-advice{list-style:none;margin:12px 0 0;padding:0;display:grid;gap:6px;font-size:13px;color:var(--muted)}
.rs-advice li{display:flex;gap:8px;align-items:flex-start}
.rs-advice .icon{width:16px;height:16px;flex:none;margin-top:2px}
.rs-foot{flex:none;display:flex;flex-direction:column;gap:10px;padding:12px 20px 16px;border-top:1px solid var(--line);background:var(--surface)}
.rs-foot .check-row{font-size:13px}
.rs-check-hint{margin:-4px 0 0;font-size:13px;color:var(--danger)}
.rs-implicit{margin:0;font-size:12px;color:var(--muted);text-align:center}
.rs-done{text-align:center}
.rs-done-card{width:min(240px,70%);aspect-ratio:var(--ratio);margin:20px auto 16px;border:1px solid var(--line);
  box-shadow:0 10px 24px -12px color-mix(in srgb,var(--ink) 35%,transparent)}
.rs-done-card svg{display:block;width:100%;height:100%}
.rs-done-line{margin:0;font-size:14px}
.rs-done-total{margin:4px 0 0;font-size:22px;font-weight:600}
body.review-open{overflow:hidden}
/* Stepper: "1/2" when review is a sheet, "1/3" when it is a page. */
@media(max-width:760px){.step.active b::after{content:' / ' attr(data-total)}}
@media(max-width:760px){
  .review-sheet{width:100vw;border-left:0;border-radius:0}
  .rs-bar{flex-wrap:wrap;padding:4px 6px 8px 16px;touch-action:none}
  .rs-bar .sheet-handle{display:block;flex-basis:100%;width:40px;max-width:40px;margin:2px auto 2px;height:4px;border-radius:2px;
    background:color-mix(in srgb,var(--ink) 22%,transparent)}
  .rs-body{padding:12px 16px 16px}
  .review-sheet .rs-workspace{--stage-height:240px}
  .rs-foot{padding:10px 16px 14px}
}
/* D1: the review page keeps its basket button in reach on phones. */
@media(max-width:760px){.review-page .summary-box #basket-button{position:sticky;bottom:12px;z-index:5}}

/* 11.4 Mobile editor. Budget at 390x844: chrome above the card <= 110px
   (header 56 + one 48px row), card >= 358px wide, pager + CTA <= 150px, no
   page scroll. The card is capped by the height that is left, so tall
   formats and short phones never scroll either. */
:root{--warn:#805500}
.pager-wrap,.m-photo-bar,.m-sheet-bar,.sheet-seg,.sheet-format,.phone-more,.chip-short,.blank-use{display:none}
.m-photo-bar[hidden]{display:none!important}
@keyframes slide-in-next{from{transform:translateX(28px);opacity:.4}to{transform:none;opacity:1}}
@keyframes slide-in-prev{from{transform:translateX(-28px);opacity:.4}to{transform:none;opacity:1}}
@media(max-width:760px){
  :root{--m-pager-h:76px}
  #header{min-height:56px;padding:6px 16px}
  /* One row: Back · name · Change · ⋯ ; the format pill moves into Change. */
  .editor-top{min-height:48px;padding:2px 8px 2px 4px;flex-wrap:nowrap;gap:4px;border-bottom:0}
  .editor-top .project-name{flex:1 1 auto;min-width:0;gap:4px}
  .editor-top .project-name>.btn{min-width:44px;min-height:44px;padding:0;justify-content:center}
  .editor-top h1{flex:1 1 auto;min-width:0;max-width:none;font-size:16px}
  .editor-top .fmt-switch{display:none}
  .change-design-chip{margin-left:auto;min-height:44px;flex:none}
  .chip-long{display:none}.chip-short{display:inline}
  .phone-more{display:inline-flex;flex:none}
  .edit-layout{display:block}
  /* The card: full width minus 16px gutters, straight under the row. */
  .workspace{margin:0;padding:0 16px;border:0;border-radius:0;background:transparent;overflow:visible;box-shadow:none}
  .workspace:not(.is-3d) .stage{height:auto;min-height:0;max-height:none;padding:4px 0 0;background:transparent;border:0;overflow:visible}
  .workspace:not(.is-3d) .card-layer{position:relative;inset:auto;padding:0;display:flex;justify-content:center}
  .workspace:not(.is-3d) .paper-wrap,.workspace:not(.is-3d) .paper-wrap.portrait,.workspace:not(.is-3d) .paper-wrap.wide{
    width:min(100%,calc((100dvh - var(--header-h) - var(--bottombar-h) - var(--m-pager-h) - 8px)*var(--ratio)));max-width:none}
  .workspace.is-3d{--stage-height:calc(100dvh - var(--header-h) - var(--bottombar-h) - var(--m-pager-h) - 8px);--pill-reserve:56px;--stage-pad:24px}
  .workspace.is-3d .stage{padding:0;border:0;background:transparent}
  .workspace .card-layer.slide-next{animation:slide-in-next 220ms ease-out}
  .workspace .card-layer.slide-prev{animation:slide-in-prev 220ms ease-out}
  /* A blank page gets one button that puts it to use. */
  .blank-use{display:inline-flex;position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);z-index:4;min-height:44px}
  /* The desktop navigation row gives way to the pager. */
  .page-nav-row{display:none}
  .canvas-actions{padding:0}
  .pager-wrap{display:block}
  .pager{display:flex;align-items:center;justify-content:center;gap:2px;min-height:44px;margin-top:6px}
  .pager .icon-btn{width:44px;height:44px}
  .pager-dots{display:flex;align-items:center;gap:8px;padding:0 6px}
  .pager-dot{width:8px;height:8px;border-radius:50%;background:color-mix(in srgb,var(--ink) 18%,transparent)}
  .pager-dot.is-current{background:var(--ink)}
  .pager-dot.is-blocking{box-shadow:0 0 0 2px var(--surface),0 0 0 3.5px var(--warn)}
  .pager-3d{margin-left:6px}
  .pager .view-toggle{min-height:44px;font-size:12px;padding:0 10px}
  .pager-status{margin:0;min-height:22px;text-align:center;font-size:13px;color:var(--muted)}
  .pager-status .tone-blocking{color:var(--warn);font-weight:600}
  /* Tools appear on selection only. The tools panel is a bottom sheet. */
  .sidebar{display:none}
  body.m-sheet-open .sidebar{display:flex;position:fixed;left:0;right:0;bottom:0;z-index:95;max-height:72dvh;overflow:auto;
    border:0;border-radius:14px 14px 0 0;background:var(--surface);box-shadow:0 -12px 32px -12px color-mix(in srgb,var(--ink) 30%,transparent)}
  body.m-sheet-open .sidebar .tabs{display:none}
  .m-sheet-bar{display:flex;align-items:center;justify-content:center;position:sticky;top:0;z-index:2;min-height:44px;background:var(--surface)}
  .m-sheet-bar .sheet-handle{width:40px;height:4px;border-radius:2px;background:color-mix(in srgb,var(--ink) 22%,transparent)}
  .m-sheet-bar .m-close{position:absolute;right:4px;top:0;width:44px;height:44px}
  body.m-sheet-open .sidebar .panel{padding-top:0}
  /* A selected photo: the compact bar, over the pager. */
  .m-photo-bar{display:flex;position:fixed;left:0;right:0;bottom:var(--bottombar-h);z-index:85;align-items:center;justify-content:space-around;
    min-height:64px;padding:4px 4px;background:var(--surface);border-top:1px solid var(--line);
    box-shadow:0 -8px 20px -12px color-mix(in srgb,var(--ink) 30%,transparent)}
  .m-photo-bar .btn{flex-direction:column;gap:2px;min-height:56px;min-width:56px;padding:4px 6px;font-size:11px;font-weight:500}
  .m-photo-bar .btn .icon{width:20px;height:20px}
  .m-photo-bar .icon-btn{width:44px;height:44px}
  /* Change: one sheet, two segments. */
  .design-rail .sheet-seg{display:flex;margin:2px 16px 10px}
  .design-rail .sheet-seg button{flex:1;min-height:44px}
  .design-rail.show-format .sheet-format{display:block;padding:0 16px 16px}
  .design-rail.show-format .rail-head,.design-rail.show-format .rail-grid{display:none}
  .design-rail .sheet-seg button[aria-selected=true]{background:var(--surface);color:var(--ink);font-weight:600;box-shadow:0 1px 3px color-mix(in srgb,var(--ink) 12%,transparent)}
}
@media(max-width:760px){
  /* The CTA is pinned to the bottom of the screen - sticky only pins once the
     page overflows, and the phone editor no longer does. */
  .editor-footer{position:fixed;left:0;right:0;bottom:0;z-index:80}
  body:has(.editor-footer) #app{padding-bottom:var(--bottombar-h)}
}
/* The crop sliders get a 44px hit area (they were 25px tall; phase 5's sweep
   never opened "Adjust precisely"). */
details.adjust input[type=range]{height:44px}

/* ── v4.7 review fixes: the page row draws cards, not boxes ─────────────────
   Page miniatures are drawn at the page's true proportion (--page-ratio, set
   per sheet from the format). The half stays at least 88px wide - the width
   the two-line status needs - but the drawing, its paper and the selection
   ring are the page's own shape, and the two halves meet at the fold. Before,
   a portrait page (57px wide at 80px) sat letterboxed in an 88px box with a
   square ring round it, and a panorama page was letterboxed the other way. */
.sheet{--art-w:calc(var(--mini-h)*var(--page-ratio,1.4));--half-w:max(var(--art-w),88px)}
.sheet.portrait{--half-w:max(var(--art-w),88px)}
.sheet .half-mini{width:var(--art-w);max-width:100%}
.sheet .page-tab:nth-last-child(2) .half-mini{align-self:flex-end}
.sheet .page-tab:last-child .half-mini{align-self:flex-start}
.sheet-paper{left:calc(50% - var(--art-w));right:auto;width:calc(var(--art-w)*2)}

/* The page row, second pass (MHL review): history and file actions left, the
   pages centred under the card, the view actions - a quiet "3D" and
   fullscreen - right. Both side columns are --side-w wide (the wider group,
   measured by fitNav), so the pages sit exactly on the centre line whatever
   the format: four pages, two, or a single sheet. */
@media(min-width:761px){
  .page-nav-row{display:grid;grid-template-columns:var(--side-w,auto) minmax(0,1fr) var(--side-w,auto);
    grid-template-areas:"left tabs right";align-items:start;column-gap:12px}
  .page-nav-row .nav-left{grid-area:left;justify-self:start}
  .page-nav-row .side-tabs{grid-area:tabs;justify-content:safe center}
  .page-nav-row .side-tabs .spread-strip{flex:none;width:auto}
  .page-nav-row .nav-right{grid-area:right;justify-self:end}
  .nav-left,.nav-right{display:flex;align-items:center;flex:none;margin-top:calc((var(--mini-h) - 44px)/2 + 4px)}
  /* stacked: each group two by two / one above the other - half the width */
  .page-nav-row.tools-stack .nav-left{display:grid;grid-template-columns:repeat(2,44px);grid-auto-rows:44px;
    margin-top:calc((var(--mini-h) - 88px)/2 + 4px)}
  .page-nav-row.tools-stack .nav-right{display:grid;grid-auto-rows:44px;justify-items:end;
    margin-top:calc((var(--mini-h) - 88px)/2 + 4px)}
  /* the pages alone on the first row, the two groups under them */
  .page-nav-row.nav-split{grid-template-columns:1fr 1fr;grid-template-areas:"tabs tabs" "left right";row-gap:2px}
  .page-nav-row.nav-split .nav-left,.page-nav-row.nav-split .nav-right{margin-top:0}
}
/* The quiet view control: cube + "3D" on the flat pages, a flat card + "2D" in
   3D (MHL) - it names where it goes, as a map's 3D/2D button does. So both
   states look the same: muted, no fill or border. A pressed fill on "2D"
   would read as "2D is on". */
.view-3d-compact{display:inline-flex;align-items:center;gap:6px;min-height:44px;min-width:56px;padding:0 10px;border:0;
  border-radius:8px;background:none;color:var(--muted);font-size:13px;margin:0 2px 0 0}
.view-3d-compact .icon{width:16px;height:16px}
.view-3d-compact:hover{color:var(--ink)}
.nav-right .view-toggle{margin:0 4px 0 0}
/* B1 in a stacked row: the button takes its short label ("3D" / "Edit"),
   as on phones - the long one widened both side columns and pushed the pages
   onto a row of their own. */
.view-toggle .vt-short{display:none}
@media(min-width:761px){
  .page-nav-row.tools-stack .view-toggle .vt-long{display:none}
  .page-nav-row.tools-stack .view-toggle .vt-short{display:inline}
}

/* ── The 3D card as an object (MHL review) ─────────────────────────────────
   Cardstock thickness: faces sit ±--t from the panel's middle, and four edge
   strips close the gap, so a turned card shows its edge instead of vanishing
   into a line. --t is half the thickness: 1.4px a sheet at editor scale, about
   what 350gsm stock (~0.35mm) measures there - paper, not board. Edges are lit like the faces: the light comes
   from the upper left, so top and left edges are lighter, right and bottom
   darker. The folded card's cover sits a full thickness in front of the inside
   page it folds onto. */
.preview-object{--t:.7px}
.preview-face{transform:translateZ(var(--t))}
.preview-face.reverse{transform:rotateY(180deg) translateZ(var(--t))}
.preview-panel.cover{transform:translateZ(calc(var(--t)*2)) rotateY(var(--fold,0deg))}
.preview-edge{position:absolute;pointer-events:none;backface-visibility:hidden;-webkit-backface-visibility:hidden}
.preview-edge.e-t{left:0;width:100%;top:calc(var(--t)*-1);height:calc(var(--t)*2);transform:rotateX(90deg);
  background:color-mix(in srgb,var(--ink) 5%,var(--paper))}
.preview-edge.e-b{left:0;width:100%;top:calc(100% - var(--t));height:calc(var(--t)*2);transform:rotateX(-90deg);
  background:color-mix(in srgb,var(--ink) 22%,var(--paper))}
.preview-edge.e-l{top:0;height:100%;left:calc(var(--t)*-1);width:calc(var(--t)*2);transform:rotateY(-90deg);
  background:color-mix(in srgb,var(--ink) 9%,var(--paper))}
.preview-edge.e-r{top:0;height:100%;left:calc(100% - var(--t));width:calc(var(--t)*2);transform:rotateY(90deg);
  background:color-mix(in srgb,var(--ink) 18%,var(--paper))}
/* Where the two inside pages meet, the fold keeps a little of the light out. */
.preview-face.inner::before{content:'';position:absolute;inset:0;z-index:1;pointer-events:none;
  background:linear-gradient(90deg,color-mix(in srgb,var(--ink) 10%,transparent),transparent 16%)}
.preview-face.inner.reverse::before{background:linear-gradient(270deg,color-mix(in srgb,var(--ink) 10%,transparent),transparent 16%)}
/* Perspective, centred on the card (above the presets pill): the far edge of a
   turned card recedes, as it does on a table. Mild on purpose - a strong one
   swung the card off-centre when it was tried in v4.6 phase 9. */
.workspace.is-3d .card-layer,.review-sheet .rs-workspace .card-layer{perspective:var(--persp,2400px);
  perspective-origin:50% calc(50% - var(--pill-reserve,0px)/2)}
/* Room for perspective: the parts of a turned card that come toward you grow,
   so in 3D the card is sized a few percent smaller than without it (the
   column budget checks every preset across its whole drag range). */
.workspace.is-3d,.review-sheet .rs-workspace{--persp:3200px;--open-w:74%}
/* A panorama is width-bound, so the height term never shrinks it: its near end
   grows most when turned, so in 3D it stops at 84% of the stage width. */
.workspace.is-3d .paper-wrap.is-preview.wide{max-width:min(1100px,calc((var(--stage-height) - var(--stage-pad) - var(--pill-reserve))*var(--ratio)/var(--yaw-k)),84%)}

/* ═══ v4.7 review — the set size in the format row ════════════════════════
   The price is for a set, so the row says which: "€9.90 · 10-card set". One
   line; the set stays muted, the price carries the selection. From 761 to
   1023px four segments left 65-96px of text, so even the names were cut
   ("Folded lan..."): there the row is two by two. */
.fmt-seg-line{font-size:13px;line-height:1.3;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.fmt-seg-line .fmt-seg-price{font-size:inherit}
@media(max-width:1023px) and (min-width:761px){
  .gallery .fmt-row{grid-template-columns:repeat(2,minmax(0,1fr))}
}

/* ═══ v4.7 review — step 2's format switcher is the gallery's row ══════════
   MHL: the same compact segments with icons as in step 1, not big tiles and
   not pictures of the card. In the editor the row is a list: under the pill
   (the popover) and in the phone sheet's Format tab. (A3c - the customer's own
   front per format - was tried here in review and dropped.) */
.fmt-popover{width:min(340px,calc(100vw - 24px));padding:10px}
.fmt-row.in-popover,.fmt-row.in-sheet{display:grid;grid-template-columns:minmax(0,1fr);gap:8px;
  max-width:none;margin:0;padding:0;overflow:visible;scroll-snap-type:none}
.fmt-row.in-sheet .fmt-seg{flex:none}
/* The Change sheet is a modal, so it and its scrim sit above the pinned price
   bar and the photo bar. Below them, the fourth format (Postcard) lay under the
   price bar on every phone and could not be tapped. The toast stays above the
   scrim: switching format inside the sheet still says so. */
@media(max-width:1023px){
  .design-rail{z-index:92}
  .rail-scrim{z-index:91}
  #toast{z-index:93}
}

/* The photo bar's close button keeps its 44px: at 320px in German the
   "Zuschneiden" label squeezed it to 43. The labels give up padding instead. */
.m-photo-bar .icon-btn{flex:none}
@media(max-width:359px){.m-photo-bar .btn{padding-left:2px;padding-right:2px}}

/* ═══ v4.7 review — the open variant, one click in the reviewer bar ════════
   MHL: not a menu. The one open choice (REVIEW_MODE) sits in the thin bar as
   a label and a two-option segmented switch; a click on the other option
   applies it. Native radios under the labels, so arrows work as well. Below
   1024px it drops the "(D2)"/"(D1)" codes. */
.variant-seg{display:inline-flex;align-items:center;gap:6px;flex:none}
.variant-seg-label{font-size:10px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;color:var(--muted)}
.variant-opts{display:inline-flex;padding:2px;border:1px solid var(--line);border-radius:999px;background:var(--surface)}
.variant-opt{position:relative;display:inline-flex;align-items:center;min-height:20px;padding:0 9px;border-radius:999px;
  font-size:11px;font-weight:600;color:var(--muted);white-space:nowrap;cursor:pointer}
.variant-opt:hover{color:var(--ink)}
.variant-opt input{position:absolute;inset:0;width:100%;height:100%;margin:0;opacity:0;cursor:pointer}
.variant-opt:has(input:checked){background:var(--ink);color:var(--surface)}
.variant-opt:has(input:focus-visible){outline:2px solid var(--brand-dark);outline-offset:1px}
.variant-short{display:none}
@media(max-width:1023px){.variant-long{display:none}.variant-short{display:inline}}

/* Room for it: below 1024px the prototype note gives way (the version and
   the samples badge stay; "About" carries the rest), and below 360px the
   switch's label does ("Sheet | Page" alone; the group keeps its name). */
@media(max-width:1023px){.review-notice{display:none}}
@media(max-width:359px){.variant-seg-label{display:none}}

/* ═══ v4.7 review — the format pill follows the page's corners ════════════
   MHL: the fully round pill did not follow the page's corner radius. It is
   the compact form of the segment it opens, so it takes the segments' corners
   and their icon on its tinted tile. */
:root{--radius-seg:10px}
.fmt-seg{border-radius:var(--radius-seg)}
.fmt-pill{border-radius:var(--radius-seg);padding:4px 14px 4px 4px;gap:10px}
.fmt-pill .fmt-seg-icon{--icon-w:34px;width:44px;height:34px;border-radius:6px}


/* ═══ v4.7 review — step 1 on phones: every format in sight, no search ═════
   MHL: a sideways row is missed by people who do not know to swipe it, and
   the search box is not needed - the occasions are the way in. The four
   formats are a list; a pick collapses it to the chosen one (the summary,
   "Change" reopens), so the designs come up. Desktop keeps its row. */
.fmt-summary{display:none}
@media(max-width:760px){
  .gallery-controls{grid-template-columns:minmax(0,1fr)}
  .fmt-chooser.is-list .fmt-row{display:grid;grid-template-columns:minmax(0,1fr);gap:8px;overflow:visible;
    margin:0 0 16px;padding:0;scroll-snap-type:none}
  .fmt-chooser.is-list .fmt-seg{flex:none}
  .fmt-chooser.is-list .fmt-seg-name{white-space:normal}
  .fmt-chooser.is-collapsed .fmt-row{display:none}
  .fmt-chooser.is-collapsed .fmt-summary{display:flex;align-items:center;gap:8px;width:100%;min-height:60px;margin:0 0 16px;
    padding:4px 12px 4px 5px;text-align:left;border:2px solid var(--primary);border-radius:var(--radius-seg);
    background:var(--soft);color:var(--ink)}
  .fmt-summary .fmt-seg-meta{flex:1}
  .fmt-summary .fmt-seg-price{color:var(--ink);font-weight:600}
  .fmt-summary-change{flex:none;font-size:13px;font-weight:600;color:var(--brand-dark);text-decoration:underline;
    text-underline-offset:3px}
  .fmt-summary:focus-visible{outline:3px solid var(--brand-dark);outline-offset:2px}
}
/* 3D on phones: no arrows or dots, only "2D" (the presets are on the stage). */
.pager.is-3d{justify-content:center}
.pager.is-3d .pager-3d{margin-left:0}
/* The page row spans the column in both views - it used to shrink to its
   content - so without the pages in 3D, "2D" sits exactly where "3D" was and
   a second click toggles back. */
.page-nav-row{width:100%}

/* ═══ v4.7 review — the basket review shows the pages flat ═════════════════
   MHL: not two views of one card in the review - the 3D card with its presets
   went (CONFIG.REVIEW_3D), and the flat pages are the review, large: each
   sheet as wide as half the panel allows per page, at most 132px tall - a
   folded 10x14 keeps both sheets on one row, a landscape card one per row. */
.rs-body{container-type:inline-size}
.rs-pages.is-large{gap:16px 12px;margin:4px 0 18px}
.rs-pages.is-large .sheet{--mini-h:min(132px,calc(50cqi / var(--page-ratio) - 6px))}


/* ═══ v4.7 review — 3D: one V for a folded card (CONFIG.FOLD_3D='v') ══════
   The card is always open 140deg in 3D and turns freely; the spread turns
   about its fold, so the fold must sit on the stage's centre line. An old
   phone rule shifted an open portrait card 43% instead of 50% - 11px off
   centre, which the always-open V made visible. Phones may scroll the page
   vertically over the stage; a sideways drag turns the card. */
@media(max-width:760px){.workspace .paper-wrap.is-preview.portrait.opened{transform:scale(.64) translateX(50%)}}
.workspace.is-3d .stage{touch-action:pan-y}
/* The inside fold, three ways (CONFIG.FOLD_SHADE), for the 16% band. Each face
   carries its half: the crease line and the valley sit on the fold edge of
   both inside pages, so they meet at the spine. */
.preview-object.fold-crease .preview-face.inner::before{background:linear-gradient(90deg,
  color-mix(in srgb,var(--ink) 22%,transparent) 0 1px,transparent 1px)}
.preview-object.fold-crease .preview-face.inner.reverse::before{background:linear-gradient(270deg,
  var(--surface) 0 1.5px,transparent 1.5px)}
.preview-object.fold-soft .preview-face.inner::before{background:linear-gradient(90deg,
  color-mix(in srgb,var(--ink) 7%,transparent),color-mix(in srgb,var(--ink) 3%,transparent) 2.5%,
  color-mix(in srgb,var(--ink) 1%,transparent) 5%,transparent 8%)}
.preview-object.fold-soft .preview-face.inner.reverse::before{background:linear-gradient(270deg,
  color-mix(in srgb,var(--ink) 7%,transparent),color-mix(in srgb,var(--ink) 3%,transparent) 2.5%,
  color-mix(in srgb,var(--ink) 1%,transparent) 5%,transparent 8%)}
/* The shading ::after has been display:none!important since an early layer,
   so the two-tone uses ::before, weighted by the same light term (--yaw-shade,
   0..1) the JS already computes per face. */
.preview-object.fold-planes .preview-face.inner::before{background:color-mix(in srgb,var(--ink) 16%,transparent);
  opacity:var(--yaw-shade,0);transition:opacity 450ms cubic-bezier(.2,.7,.2,1)}
.preview-object.fold-planes.rotating .preview-face.inner::before{transition:none}

/* Flat cards turn a full circle now; edge-on, the near edge grows with the
   perspective, so the card is sized with more room (1.26 -> 1.34) - at
   1920x1080 a postcard's corner passed the stage top by 9px. */
.workspace.is-3d{--yaw-k:1.34}

/* ═══ v4.7 review — two pages as a spread (CONFIG.SPREAD_VIEW, option B) ═══
   A button on the fold of each folded sheet in the page row shows its two
   pages side by side on the stage; any page preview goes back to one page.
   32px, so it covers only the fold and never the pages' own tap area on a
   tablet (phones have no page row). */
.sheet{position:relative}
.sheet-spread{position:absolute;left:50%;top:calc(var(--mini-h,80px)/2);transform:translate(-50%,-50%);z-index:3;
  width:32px;height:32px;border-radius:50%;display:grid;place-items:center;padding:0;
  border:1px solid var(--line);background:var(--surface);color:var(--ink);
  box-shadow:0 2px 6px color-mix(in srgb,var(--ink) 18%,transparent)}
.sheet-spread .icon{width:15px;height:15px}
.sheet-spread:hover{border-color:var(--brand-dark)}
.sheet-spread:focus-visible{outline:2px solid var(--brand-dark);outline-offset:2px}
.sheet-spread.is-on{background:var(--ink);color:var(--surface);border-color:var(--ink)}
.sheet.is-spread .half-mini{box-shadow:inset 0 0 0 2px var(--brand);border-radius:4px}
/* The stage: two pages meeting at a fold line, one paper. */
.paper-wrap.is-spread{display:flex;background:var(--paper)}
.paper-wrap.is-spread .spread-page{flex:1;min-width:0;position:relative;cursor:pointer}
.paper-wrap.is-spread .spread-page.is-active{cursor:auto}
.paper-wrap.is-spread .spread-fold{flex:none;width:1px;background:var(--line)}
@media(max-width:760px){.sheet-spread{display:none}}


/* v3 · templates: every design's own pages, drawn in mm with the bleed on the stage (tpl.js) */
.paper-wrap svg[data-tpl]{background:transparent}
.spread-page svg[data-tpl]{background:transparent}
.slot-picker{display:flex;flex-wrap:wrap;gap:6px}
.slot-chip{min-width:44px;min-height:40px;padding:0 10px;border:1px solid var(--line);border-radius:8px;background:white;font-size:13px;font-variant-numeric:tabular-nums}
.slot-chip[aria-pressed=true]{border-color:var(--brand-dark);background:var(--soft);font-weight:600}
.paper-wrap [data-slot].can-pan{cursor:grab}
.paper-wrap [data-slot].can-pan:active{cursor:grabbing}
textarea.field.text-block{height:auto;min-height:118px;padding:10px 13px;line-height:1.5}
/* a light card on a white sheet needs its edge: art that runs off the trim must read as running off the card */
.page-mini:has(> svg[data-tpl]){box-shadow:0 0 0 1px #10151b1f,0 1px 3px #10151b14}


/* ═══ v3 · round 9 (2026-09-29) — backgrounds, moving, 3D tiles ════════════
   MHL: "move some elements and pick the nice background variations and also
   make those nice 3d tiles". The Layout tab lists the colours a design comes
   in (a swatch per variant, the design's own first) and the motifs of the
   page; texts and motifs are dragged on the card. The gallery shows each
   design as a 3D tile (transparent, the shadow baked in), with its colours as
   dots under the name. */
.bg-swatches{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px;margin-top:12px}
.bg-swatch{display:flex;flex-direction:column;align-items:center;gap:6px;min-height:72px;padding:10px 4px 8px;
  border:1px solid var(--line);border-radius:8px;background:white;font-size:12px;line-height:1.25;color:var(--ink);text-align:center}
.bg-swatch:hover{border-color:var(--brand)}
.bg-swatch[aria-checked=true]{border-color:var(--brand-dark);background:var(--soft);font-weight:600}
.bg-swatch:focus-visible{outline:3px solid var(--brand-dark);outline-offset:2px}
.bg-dot{width:30px;height:30px;border-radius:50%;background:var(--sw);
  box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--ink) 16%,transparent),0 1px 2px color-mix(in srgb,var(--ink) 12%,transparent)}
.bg-swatch[aria-checked=true] .bg-dot{box-shadow:0 0 0 2px white,0 0 0 4px var(--brand-dark)}
.el-fields{margin-top:12px}
.move-actions{margin-top:10px}
.paper-wrap [data-move]{cursor:grab}
.paper-wrap [data-move]:hover,.paper-wrap [data-text]:hover{stroke:var(--brand)}
.paper-wrap [data-move]:focus{outline:none;stroke:var(--brand-dark);stroke-width:4px}
body.is-moving,body.is-moving *{cursor:grabbing!important;user-select:none}
.tile-image.is-3d img{clip-path:none}
.tile-image.is-3d::after{display:none}
.tile-dots{display:flex;gap:5px;margin-top:6px}
.tile-dot{width:12px;height:12px;border-radius:50%;background:var(--sw);
  box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--ink) 18%,transparent)}
@media(max-width:760px){.bg-swatches{grid-template-columns:repeat(3,minmax(0,1fr))}.tile-dot{width:10px;height:10px}}
/* the card's own words are not page text: a drag moves them, it never selects them */
.paper-wrap svg text,.paper-wrap svg tspan{-webkit-user-select:none;user-select:none}
/* v3 · round 9 — the font picker: every font a button set in its own face */
.font-picker{display:grid;gap:8px}
.font-choices{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:6px;max-height:320px;overflow:auto;padding:2px}
.font-choice{min-height:44px;padding:6px 10px;border:1px solid var(--line);border-radius:8px;background:white;color:var(--ink);
  font-size:17px;line-height:1.1;text-align:left;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.font-choice:first-child{grid-column:1/-1;font-size:15px}
.font-choice:hover{border-color:var(--brand)}
.font-choice[aria-checked=true]{border-color:var(--brand-dark);background:var(--soft)}
.font-choice:focus-visible{outline:3px solid var(--brand-dark);outline-offset:2px}
.font-group{grid-column:1/-1;margin-top:6px;font-size:11px;letter-spacing:.06em;text-transform:uppercase;color:var(--muted)}
/* v3 · round 10 — a tile's colours (MHL 2026-09-29): one 44px strip; a tap takes the nearest dot, Enter the next colour,
   the arrows step; the tile swaps to that colour and the editor opens in it */
.tile-colours{position:relative;z-index:2;display:inline-flex;align-items:center;height:44px;min-width:44px;margin:-9px 0 -13px -5px;
  padding:0;border:0;border-radius:22px;background:none;cursor:pointer;-webkit-tap-highlight-color:transparent}
.tile-colours .tile-dot{display:grid;place-items:center;width:24px;height:44px;border-radius:0;background:none;box-shadow:none}
.tile-colours .tile-dot::before{content:'';width:14px;height:14px;border-radius:50%;background:var(--sw);
  box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--ink) 20%,transparent);transition:transform 140ms ease,box-shadow 140ms ease}
.tile-colours .tile-dot:hover::before{transform:scale(1.18)}
.tile-colours .tile-dot.on::before{box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--ink) 20%,transparent),0 0 0 2px var(--page),0 0 0 3.5px var(--ink)}
.tile-colours:focus-visible{outline:2px solid var(--brand-dark);outline-offset:-6px;box-shadow:none}
@media(max-width:760px){.tile-colours .tile-dot::before{width:12px;height:12px}}

/* ── v3 QA fixes (2026-09-29 night) ─────────────────────────────────────────
   Touch: a finger moves texts and motifs (the browser must not take the gesture
   for a scroll) and swipes pages; the card is the work surface, so on touch
   screens it does not scroll the page. */
@media(pointer:coarse){.workspace:not(.is-3d) .paper-wrap{touch-action:none}}
.workspace:not(.is-3d) .paper-wrap [data-move],.workspace:not(.is-3d) .paper-wrap [data-text],.workspace:not(.is-3d) .paper-wrap [data-pad]{touch-action:none}
/* iOS zooms into any field under 16px on focus */
@media(pointer:coarse),(max-width:760px){input.field,textarea.field,select.field,select,#text-value,.mobile-category .field,#design-category{font-size:16px}}
/* buttons: no double-tap zoom delay */
button,[data-action],.tile-colours{touch-action:manipulation}
/* the undo toast: only its button takes taps; on a phone it sits above the bottom bar, not over the card */
#toast.has-action{pointer-events:none}#toast.has-action .toast-undo{pointer-events:auto;min-height:44px;min-width:44px;padding:0 8px}
@media(max-width:760px){#toast{top:auto!important;bottom:calc(var(--bottombar-h,84px) + 10px + env(safe-area-inset-bottom,0px));left:50%!important;max-width:calc(100vw - 24px)}}
/* phone tools sheet: its handle drags it down; a little lower so more of the card shows */
@media(max-width:760px){
  .m-sheet-bar{touch-action:none;cursor:grab}
  body.m-sheet-open .sidebar{max-height:64dvh}
  body.m-sheet-open .sidebar.is-dragging{transform:translateY(var(--sheet-drag,0px));transition:none}
  /* the words being edited, shown in the sheet (the card is under it) */
  .text-peek{display:block;border-radius:8px;overflow:hidden;background:var(--surface);box-shadow:0 1px 4px color-mix(in srgb,var(--ink) 20%,transparent)}
  .text-peek svg{display:block;width:100%;height:auto;max-height:140px}
  body.m-sheet-open .panel>.text-peek{order:-3}
  body.m-sheet-open .panel>.text-edit{order:-2}
  /* the font list scrolls with the sheet, one name per row */
  .font-choices{max-height:none!important;overflow:visible!important;grid-template-columns:1fr!important}
  /* the order summary may take two lines instead of being cut */
  .editor-footer .order-summary strong,.editor-footer .order-summary small{white-space:normal;overflow:visible;text-overflow:clip;line-height:1.25}
  /* review sheet handle centred above the title */
  .rs-bar{position:relative;padding-top:16px}
  .rs-bar .sheet-handle{position:absolute;top:6px;left:50%;transform:translateX(-50%);margin:0;flex-basis:auto}
  .design-rail{max-height:76dvh}
}
/* 44px targets */
.resume .btn{min-height:44px}
@media(pointer:coarse){.slot-chip{min-height:44px;min-width:44px}input[type=range]{height:44px}}
/* 3D: the flat wrappers must not take the click meant for the page under them (the front face was unreachable) */
.workspace.is-3d .paper-wrap,.workspace.is-3d .preview-object,.workspace.is-3d .preview-panel{pointer-events:none}
.workspace.is-3d .preview-face{pointer-events:auto}
