
/* Hallmark · genre: playful · theme: custom "warm scrapbook" · design-system: design.md · designed-as-app */
:root{--paper:#FBF4EC;--paper-2:oklch(94.5% 0.025 71);--ink:#40342B;--ink2:oklch(44% 0.03 60);--coral:#E07A5F;--coral-d:#C85A44;--line:#e7ddd0;--card:#fffdf9;
--gold:oklch(76% 0.09 80);--sage:oklch(66% 0.06 150);
--shadow-s:0 1px 2px rgba(64,52,43,.05),0 6px 16px -8px rgba(64,52,43,.14);
--shadow-m:0 2px 4px rgba(64,52,43,.05),0 16px 36px -18px rgba(64,52,43,.25);
--ease-out:cubic-bezier(.16,1,.3,1);
--display:"Fredoka",system-ui,-apple-system,sans-serif;--hand:"Caveat","Segoe Print",system-ui,cursive;
--body:"Nunito",system-ui,-apple-system,"Segoe UI",sans-serif}
*{box-sizing:border-box;margin:0}
:focus-visible{outline:2px solid var(--coral-d);outline-offset:2px;border-radius:4px}
body{font-family:var(--body);color:var(--ink);background:var(--paper);line-height:1.55;-webkit-font-smoothing:antialiased;
  /* paper grain: fractal noise at ~4% alpha, flat cream becomes touchable paper */
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncA type='linear' slope='.045'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E")}
.wrap{max-width:520px;margin:0 auto;padding:48px 22px}
h1{font-family:var(--display);font-weight:600;font-size:2rem;line-height:1.1;margin-bottom:10px}
h2{font-family:var(--display);font-weight:600;font-size:1.3rem;margin-bottom:8px}
p{color:var(--ink2);margin-bottom:16px}
.card{background:var(--card);border:1px solid var(--line);border-radius:18px;padding:26px;margin-bottom:16px;box-shadow:var(--shadow-s)}
label{display:block;font-weight:700;margin-bottom:6px}
input[type=text]{width:100%;padding:12px 14px;border:1px solid var(--line);border-radius:12px;font-size:1rem;background:#fff;font-family:inherit;color:var(--ink);box-shadow:inset 0 1px 2px rgba(64,52,43,.05);transition:border-color .15s var(--ease-out),box-shadow .15s var(--ease-out)}
input[type=text]:focus{outline:none;border-color:var(--coral);box-shadow:inset 0 1px 2px rgba(64,52,43,.04),0 0 0 3px rgba(224,122,95,.18)}
/* native date + select wear the same rounded skin as text inputs, with a coral chevron
   instead of the stock system dropdown; keeps the cozy tone through every form row */
input[type=date],select{width:100%;padding:12px 14px;border:1px solid var(--line);border-radius:12px;font-size:1rem;background:#fff;font-family:inherit;color:var(--ink);box-shadow:inset 0 1px 2px rgba(64,52,43,.05)}
select{appearance:none;-webkit-appearance:none;padding-right:38px;cursor:pointer;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8'%3E%3Cpath d='M1 1.5 L6 6.5 L11 1.5' fill='none' stroke='%23c96a4e' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 14px center}
input[type=date]:focus,select:focus{outline:none;border-color:var(--coral);box-shadow:inset 0 1px 2px rgba(64,52,43,.04),0 0 0 3px rgba(224,122,95,.18)}
.check{display:flex;gap:10px;align-items:flex-start;margin:14px 0;color:var(--ink)}
.check input{margin-top:4px;width:18px;height:18px;accent-color:var(--coral)}
.btn{display:inline-block;font-weight:700;font-size:1rem;border:0;border-radius:999px;padding:12px 22px;cursor:pointer;background:var(--coral-d);color:#fff;text-decoration:none;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 2px 8px -2px rgba(200,90,68,.55);
  transition:transform .15s var(--ease-out),box-shadow .15s var(--ease-out),background .15s var(--ease-out)}
.btn:hover{background:#b34e3a;transform:translateY(-1px);box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 5px 14px -4px rgba(200,90,68,.6)}
.btn:active{transform:translateY(1px);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 3px -1px rgba(200,90,68,.5)}
.btn.ghost{background:transparent;color:var(--coral-d);border:2px solid var(--coral);box-shadow:none}
.btn.ghost:hover{background:#fdf1ec;transform:translateY(-1px);box-shadow:0 4px 12px -6px rgba(200,90,68,.35)}
.muted{font-size:.85rem;color:var(--ink2)}
.err{background:#fbe4de;color:#a13a24;border-radius:10px;padding:8px 12px;margin-bottom:12px;font-size:.9rem}
.topbar{display:flex;align-items:center;justify-content:space-between;gap:14px;margin-bottom:22px}
.brand{font-family:var(--display);font-weight:700;font-size:1.2rem;display:inline-flex;gap:.4rem;align-items:center;text-decoration:none;color:inherit;padding:8px 0}
/* app shell, mobile: single column + bottom nav; desktop: sidebar + wide main */
.appshell{width:100%}
.appmain{padding:20px 20px 96px;max-width:560px;margin:0 auto}
.mtop{display:flex;padding:14px 0 4px}
.sidebar{display:none}
@media(min-width:900px){
  .appshell{display:grid;grid-template-columns:238px minmax(0,1fr);min-height:100vh}
  .sidebar{display:flex;flex-direction:column;position:sticky;top:0;align-self:start;height:100vh;
    padding:26px 16px;gap:3px;border-right:1px solid var(--line);background:linear-gradient(180deg,#fffdf9,var(--paper))}
  /* content fills the column right of the sidebar, capped + centered on huge screens.
     width:100% matters: on a grid item, auto margins otherwise defeat stretch and
     shrink-wrap the main column to its content. */
  .appmain{width:100%;max-width:980px;margin:0 auto;padding:36px 46px 48px}
  .mtop{display:none}
  .bnav{display:none!important}
  /* keep forms/text readable on the wide desktop main; the shelf stays full-width */
  .appmain .card,.appmain .story{max-width:600px;margin-left:auto;margin-right:auto}
}
/* Big desktops: 1920px screens left ~700px unused beside a 980px column, so whole rows
   of the collection sat below the fold. Widening the container adds COLUMNS of identical
   rows (the wall's 240px row-stride / plank-pitch contract is untouched), more of the
   display fits on one screen. */
@media(min-width:1440px){
  .appmain{max-width:1340px}
  .wall{max-width:1260px}
}
.sbrand{font-size:1.32rem;margin:0 0 20px;padding:0 10px}
.snav{display:flex;flex-direction:column;gap:3px}
.snav-i{display:flex;align-items:center;gap:12px;padding:11px 12px;border-radius:12px;text-decoration:none;color:var(--ink2);font-weight:600;font-size:.98rem;transition:background .14s,color .14s}
.snav-i svg{width:22px;height:22px;flex:none}
.snav-i:hover{background:#fff;color:var(--ink)}
.snav-i[aria-current]{background:#fdeee9;color:var(--coral-d);box-shadow:inset 0 0 0 1px rgba(224,122,95,.28)}
.snav-i:focus-visible{outline:2px solid var(--coral);outline-offset:1px}
.snav-add{margin-top:14px;text-align:center;font-size:.95rem;padding:11px 12px}
.sfoot{margin-top:auto}
.snav-out{background:none;border:0;color:var(--ink2);font-weight:600;font-size:.9rem;cursor:pointer;padding:11px 12px;width:100%;text-align:left;border-radius:12px}
.snav-out:hover{background:#fff;color:var(--ink)}
.snav-out:focus-visible{outline:2px solid var(--coral);outline-offset:1px}
form{margin:0}
.row{display:flex;gap:10px;align-items:center;flex-wrap:wrap}
textarea,select,input[type=date]{width:100%;padding:12px 14px;border:1px solid var(--line);border-radius:12px;font-size:1rem;background:#fff;font-family:inherit;color:var(--ink);box-shadow:inset 0 1px 2px rgba(64,52,43,.05)}
textarea:focus,select:focus,input[type=date]:focus{outline:none;border-color:var(--coral);box-shadow:inset 0 1px 2px rgba(64,52,43,.04),0 0 0 3px rgba(224,122,95,.18)}
textarea{min-height:82px;resize:vertical}
.field{margin-bottom:14px}
.hint{font-size:.8125rem;color:var(--ink2);margin:5px 0 0}
.hint.err{color:#a13a24}
.btn.block{display:block;width:100%;text-align:center;margin-top:6px}
.btn[disabled]{opacity:.5;cursor:default}
.toolbar{display:flex;justify-content:space-between;align-items:center;gap:10px;margin-bottom:6px}
/* title block: page title + the little count caption; the action button never wraps */
.tbtitle{min-width:0}
.shelfcount{margin:2px 0 0;font-size:.85rem}
.toolbar .btn{white-space:nowrap;flex:none}
/* shelf toolbar actions: balanced pair, comfortable thumb targets, never crowd the title */
.tbbtns{display:flex;gap:8px;flex-shrink:0}
.tbbtns .btn{padding:11px 20px;font-size:.95rem}
@media(max-width:400px){.tbbtns .btn{padding:11px 16px}}
/* add-a-plushie: photo picker + cutout preview */
.picker{display:block;border:2px dashed var(--line);border-radius:16px;padding:22px;text-align:center;background:#fff;cursor:pointer;font-weight:700}
.picker:hover{border-color:var(--coral)}
.pickrow{display:flex;gap:10px}
.pickrow .picker{flex:1;min-width:0;padding:18px 12px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px}
/* both photo lanes weigh the same at rest, coral is reserved for a REAL selection,
   so "Take a photo" no longer reads as pre-picked next to a "placeholder" library lane */
.picker.cam{border-style:dashed}
.picker .hint{font-size:.8125rem;color:var(--ink2);margin-top:4px}
.picker:focus-within{border-color:var(--coral);box-shadow:0 0 0 3px rgba(224,122,95,.25)}
/* visually hidden but still focusable/tab-reachable (keyboard + screen readers can open the picker) */
.vhidden{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0}
.preview{background-color:#f3ece2;background-image:linear-gradient(45deg,#e7ddd0 25%,transparent 25%),linear-gradient(-45deg,#e7ddd0 25%,transparent 25%),linear-gradient(45deg,transparent 75%,#e7ddd0 75%),linear-gradient(-45deg,transparent 75%,#e7ddd0 75%);background-size:16px 16px;background-position:0 0,0 8px,8px -8px,-8px 0;border-radius:16px;padding:14px;align-items:center;justify-content:center;min-height:200px}
.preview img{max-width:100%;max-height:260px;object-fit:contain;filter:drop-shadow(0 8px 14px rgba(64,52,43,.22))}
.status{font-size:.9rem;margin:10px 0 0;min-height:1.2em;color:var(--ink2)}
.status.ok{color:#2f7d4f}.status.note{color:#a15a2a}.status.err{color:#a13a24}
.spin{display:inline-block;width:14px;height:14px;border:2px solid var(--coral);border-top-color:transparent;border-radius:50%;animation:sp .7s linear infinite;vertical-align:-2px;margin-right:6px}
@keyframes sp{to{transform:rotate(360deg)}}
@media (prefers-reduced-motion:reduce){.spin{animation:none}}
/* manual cutout editor, draw the outline (finger-friendly, full-screen) */
.editor{position:fixed;inset:0;z-index:100;background:var(--paper);display:flex;flex-direction:column;overscroll-behavior:none}
.editor[hidden]{display:none}
.editor-bar{display:flex;align-items:center;gap:10px;padding:12px 14px;border-bottom:1px solid var(--line);background:var(--card)}
.editor-title{font-family:var(--hand);font-weight:700;font-size:1.25rem;color:var(--coral-d);text-align:center;flex:1;min-width:0}
.btn.small{padding:8px 14px;font-size:.9rem}
.editor-stage{flex:1;display:flex;align-items:center;justify-content:center;overflow:hidden;padding:12px;touch-action:none;overscroll-behavior:none;
  background-color:#f3ece2;background-image:linear-gradient(45deg,#e7ddd0 25%,transparent 25%),linear-gradient(-45deg,#e7ddd0 25%,transparent 25%),linear-gradient(45deg,transparent 75%,#e7ddd0 75%),linear-gradient(-45deg,transparent 75%,#e7ddd0 75%);background-size:18px 18px;background-position:0 0,0 9px,9px -9px,-9px 0}
#edCanvas{max-width:100%;max-height:100%;touch-action:none;cursor:crosshair;border-radius:8px;box-shadow:0 10px 22px -8px rgba(64,52,43,.42)}
/* magnifier: on a phone your fingertip covers the exact edge you are aiming at, so mirror
   that patch of the clean photo just above it. content-box because the global
   *{box-sizing:border-box} would otherwise shrink the canvas behind the rim. */
.loupe{position:fixed;z-index:110;box-sizing:content-box;width:130px;height:130px;border-radius:50%;overflow:hidden;display:none;pointer-events:none;border:4px solid #fff;box-shadow:0 8px 24px rgba(64,52,43,.4)}
.loupe::after{content:"";position:absolute;left:50%;top:50%;width:20px;height:20px;transform:translate(-50%,-50%);border:2px solid var(--coral);border-radius:50%;box-shadow:0 0 0 1px rgba(255,255,255,.7)}
.loupe canvas{display:block;width:130px;height:130px}
.etool:disabled{opacity:.4;cursor:default} /* nothing to undo yet reads as "you have not slipped" */
.editor-tools{display:flex;align-items:center;gap:8px;padding:10px 12px;border-top:1px solid var(--line);background:var(--card)}
.etool{font-family:var(--display);font-weight:600;font-size:1rem;min-width:46px;height:46px;padding:0 12px;border-radius:13px;border:2px solid var(--line);background:#fff;color:var(--ink);cursor:pointer;touch-action:manipulation}
.etool:hover{border-color:var(--coral)}
.etool:active{transform:translateY(1px)}
.etool.wide{min-width:auto;flex:0 1 auto}
.editor-tools .btn.done{margin-left:auto}
.editor-hint2{font-size:.8125rem;line-height:1.4;color:var(--ink2);margin:0;padding:8px 14px calc(10px + env(safe-area-inset-bottom));background:var(--card);text-align:center}
.editor-hint2 b{color:var(--coral-d);font-weight:700}
.handlechips{display:flex;flex-wrap:wrap;gap:8px;margin:12px 0 2px}
.hchip{font-family:var(--display);font-weight:600;font-size:.82rem;padding:9px 13px;min-height:40px;border-radius:999px;cursor:pointer;background:#fff;border:2px solid var(--line);color:var(--ink);display:inline-flex;align-items:center;touch-action:manipulation;transition:transform .15s var(--ease-out),border-color .15s var(--ease-out),background .15s var(--ease-out)}
.hchip:hover{border-color:var(--coral);transform:translateY(-1px)} .hchip.sel{border-color:var(--coral);background:#fdeee9;color:var(--coral-d)}
/* ===== collectible pack card (a plushie in blister packaging), themed by --pk ===== */
.viewtoggle{display:flex;gap:6px;justify-content:center;margin:10px 0 4px}
.vt{font-family:var(--display);font-weight:600;font-size:.85rem;padding:9px 16px;border-radius:999px;border:2px solid var(--line);background:#fff;color:var(--ink);cursor:pointer;transition:transform .15s var(--ease-out),border-color .15s var(--ease-out),background .15s var(--ease-out)}
.vt:hover{border-color:var(--coral)} .vt.active{border-color:var(--coral);background:#fdeee9;color:var(--coral-d)}
.packpane{display:flex;flex-direction:column;align-items:center;margin:6px 0 8px}
.packpane .panectl{display:flex;flex-direction:column;align-items:center;width:100%}
/* The editor hero sits in a narrow sticky column with the details panel beside it, so the
   preview and its controls STACK (preview on top, edge/aura/pack controls below). The old
   "controls beside preview" 2-col needed a full-width packview it no longer gets here — forced
   into this column it collapsed the preview and overlapped the swatches. */
.panectl .stkopt{text-align:center}
@media(min-width:960px){
  .packpane .panectl{max-width:430px;margin:0 auto}
}
.herosticker[hidden],.packpane[hidden]{display:none}
.packcard{--ink:#43291b;--pk:#e07a5f;
  --accent:var(--pk);--body:color-mix(in srgb,var(--pk) 20%,#fff);--win:color-mix(in srgb,var(--pk) 50%,#fff);--shadow:color-mix(in srgb,var(--pk) 66%,#3a2416);
  position:relative;width:min(320px,86vw);aspect-ratio:1/1.16;background:var(--body);border:5px solid var(--ink);border-radius:28px;overflow:hidden;container-type:inline-size;
  box-shadow:9px 11px 0 0 var(--shadow),9px 11px 0 5px var(--ink),16px 20px 24px rgba(67,41,27,.22)}
.pk-head{position:relative;background:var(--accent);border-bottom:5px solid var(--ink);padding:14px 16px 12px;display:flex;justify-content:space-between;align-items:flex-start;gap:8px;min-height:66px}
.pk-logo{font-family:var(--display);font-weight:700;font-size:clamp(16px,7cqw,24px);line-height:.9;color:var(--ink);text-transform:uppercase;letter-spacing:.3px;text-shadow:0 1.5px 0 rgba(255,255,255,.3);max-width:62%;overflow-wrap:anywhere}
.pk-brand{text-align:right;line-height:1.1;flex:none}
.pk-url{font-size:clamp(9px,3cqw,12px);font-weight:600;color:var(--ink);background:rgba(255,255,255,.35);border:2px solid var(--ink);border-radius:20px;padding:1px 8px;display:inline-block;max-width:120px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pk-stars{margin-top:4px;font-size:12px;letter-spacing:3px;color:#f7c948;-webkit-text-stroke:.6px var(--ink)}
.pk-window{position:absolute;left:20px;right:20px;top:86px;bottom:20px;border:5px solid var(--ink);border-radius:22px;overflow:hidden;
  background:radial-gradient(120% 100% at 50% 12%, color-mix(in srgb,var(--win) 78%,#fff), var(--win));
  box-shadow:inset 0 4px 10px rgba(255,255,255,.55), inset 0 -14px 24px rgba(0,0,0,.12)}
.pk-window::before{content:"";position:absolute;inset:0;pointer-events:none;z-index:4;border-radius:inherit;
  background:linear-gradient(122deg, transparent 30%, rgba(255,255,255,.5) 37%, rgba(255,255,255,.08) 43%, transparent 49%, transparent 63%, rgba(255,255,255,.36) 69%, rgba(255,255,255,.05) 74%, transparent 79%),radial-gradient(130% 70% at 12% 6%, rgba(255,255,255,.5), transparent 44%)}
.pk-content{position:absolute;inset:0;z-index:2;display:flex;align-items:flex-end;justify-content:center}
.pk-content img.char{max-width:82%;max-height:88%;object-fit:contain;margin-bottom:5%;filter:drop-shadow(0 6px 5px rgba(67,41,27,.32))}
.pk-content span.char{font-size:clamp(70px,30cqw,120px);line-height:1}
/* plush scale + position inside the pack (grows from the feet; drag to move) */
.pk-content{transform:translate(calc(var(--px,0)*100%),calc(var(--py,0)*100%))}
.pk-content img.char,.pk-content span.char{transform:scale(var(--pz,1));transform-origin:50% 96%;transition:transform .25s var(--ease-out);cursor:grab}
@media(prefers-reduced-motion:reduce){.pk-content img.char,.pk-content span.char{transition:none}}
/* hang slit, a punched euro-slot showing the backdrop through the top */
.pk-hang{position:absolute;top:4px;left:50%;transform:translateX(-50%);z-index:7;width:54px;height:26px;pointer-events:none}
.pk-hang svg{display:block;width:100%;height:100%;filter:drop-shadow(0 1.5px 1px rgba(0,0,0,.14))}
/* corner sticker inside the display window (a badge on the packaging). Positioned by its
   CENTRE via left/top % (inline --sx/--sy from the pack config), so the owner can drag it
   anywhere in the window. Defaults sit in the top-right corner. */
.pk-sticker{position:absolute;left:88%;top:10%;transform:translate(-50%,-50%);z-index:6;font-size:1.55rem;line-height:1;filter:drop-shadow(0 2px 2px rgba(67,41,27,.26));cursor:grab;touch-action:none;-webkit-user-select:none;user-select:none}
/* window backdrop patterns (subtle, tiled over the window tint). Selector is
   .packcard .pk-window.pkbg-* (0,3,0) on purpose: the .pks-box/.pks-bag rules below use
   the background: shorthand at (0,2,0), which would otherwise silently wipe the pattern
   image, the picker looked dead in box/bag shapes. */
.pk-window{background-repeat:repeat;background-position:center}
.packcard .pk-window.pkbg-flowers{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='46' height='46'%3E%3Cg fill='%23ffffff' fill-opacity='.5'%3E%3Cg transform='translate(11 11)'%3E%3Ccircle cx='0' cy='-5' r='3'/%3E%3Ccircle cx='5' cy='-1.5' r='3'/%3E%3Ccircle cx='3' cy='4' r='3'/%3E%3Ccircle cx='-3' cy='4' r='3'/%3E%3Ccircle cx='-5' cy='-1.5' r='3'/%3E%3Ccircle cx='0' cy='0' r='2.4' fill='%23f7c948' fill-opacity='.7'/%3E%3C/g%3E%3Cg transform='translate(34 33) scale(.7)'%3E%3Ccircle cx='0' cy='-5' r='3'/%3E%3Ccircle cx='5' cy='-1.5' r='3'/%3E%3Ccircle cx='3' cy='4' r='3'/%3E%3Ccircle cx='-3' cy='4' r='3'/%3E%3Ccircle cx='-5' cy='-1.5' r='3'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E")}
.packcard .pk-window.pkbg-leaves{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='44' height='44'%3E%3Cg fill='%23ffffff' fill-opacity='.45'%3E%3Cpath d='M11 4 C4 8 4 16 11 18 C13 11 13 11 18 8 C15 5 13 4 11 4 Z'/%3E%3Cpath d='M33 26 C26 30 26 38 33 40 C35 33 35 33 40 30 C37 27 35 26 33 26 Z'/%3E%3C/g%3E%3C/svg%3E")}
.packcard .pk-window.pkbg-sparkles{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='40' height='40'%3E%3Cg fill='%23ffffff' fill-opacity='.6'%3E%3Cpath d='M10 3 L11.5 8.5 L17 10 L11.5 11.5 L10 17 L8.5 11.5 L3 10 L8.5 8.5 Z'/%3E%3Cpath d='M30 22 L31 26 L35 27 L31 28 L30 32 L29 28 L25 27 L29 26 Z'/%3E%3C/g%3E%3C/svg%3E")}
.packcard .pk-window.pkbg-gingham{background-image:linear-gradient(rgba(255,255,255,.28) 50%,transparent 50%),linear-gradient(90deg,rgba(255,255,255,.28) 50%,transparent 50%);background-size:16px 16px,16px 16px}
.packcard .pk-window.pkbg-paws{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='46' height='46'%3E%3Cg fill='%23ffffff' fill-opacity='.5'%3E%3Cg transform='translate(12 14)'%3E%3Cellipse cx='0' cy='2' rx='4' ry='3.4'/%3E%3Ccircle cx='-4' cy='-3' r='1.7'/%3E%3Ccircle cx='0' cy='-4.5' r='1.7'/%3E%3Ccircle cx='4' cy='-3' r='1.7'/%3E%3C/g%3E%3Cg transform='translate(33 34) scale(.8)'%3E%3Cellipse cx='0' cy='2' rx='4' ry='3.4'/%3E%3Ccircle cx='-4' cy='-3' r='1.7'/%3E%3Ccircle cx='0' cy='-4.5' r='1.7'/%3E%3Ccircle cx='4' cy='-3' r='1.7'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E")}
.packcard .pk-window.pkbg-hearts{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='40' height='40'%3E%3Cg fill='%23ffffff' fill-opacity='.5'%3E%3Cpath d='M11 8 C11 5 6 4 6 9 C6 12 11 15 11 15 C11 15 16 12 16 9 C16 4 11 5 11 8 Z'/%3E%3Cpath d='M30 27 C30 25 26 24 26 28 C26 30 30 33 30 33 C30 33 34 30 34 28 C34 24 30 25 30 27 Z'/%3E%3C/g%3E%3C/svg%3E")}
.pk-sparkle{position:absolute;z-index:3;width:20px;height:20px;pointer-events:none;background:#fff;filter:drop-shadow(0 0 3px rgba(255,255,255,.95));clip-path:polygon(50% 0,58% 42%,100% 50%,58% 58%,50% 100%,42% 58%,0 50%,42% 42%)}
.pk-rarity{position:absolute;top:10px;left:50%;transform:translateX(-50%) rotate(-3deg);z-index:5;
  font-family:var(--display);font-weight:700;font-size:clamp(11px,3.4cqw,14px);letter-spacing:.5px;color:#fff;
  background:var(--accent);border:2.5px solid var(--ink);border-radius:999px;padding:2px 12px;white-space:nowrap;
  box-shadow:0 2px 0 var(--ink)}
.packwrap{display:flex;flex-direction:column;align-items:center;gap:2px}
/* ===== pack styles: 📦 window box · 🍬 candy bag ===== */
.pks-box{border-radius:10px}
.pks-box .pk-head{border-radius:0}
.pks-box .pk-window{left:26px;right:26px;top:94px;bottom:26px;border-radius:9px;
  background:radial-gradient(120% 100% at 50% 10%, #fffdf8, color-mix(in srgb,var(--win) 42%,#fff))}
.pks-box .pk-window::before{background:linear-gradient(115deg, transparent 38%, rgba(255,255,255,.4) 44%, rgba(255,255,255,.06) 50%, transparent 56%)}
.pks-bag{border-radius:12px 12px 30px 30px}
.pks-bag .pk-head{background:repeating-linear-gradient(90deg, var(--accent) 0 12px, color-mix(in srgb,var(--accent) 82%,#40342B) 12px 24px);min-height:56px;padding:10px 16px 8px}
.pks-bag .pk-window{left:26px;right:26px;top:78px;bottom:24px;border-radius:50%/44%;
  background:radial-gradient(115% 95% at 50% 8%, color-mix(in srgb,var(--win) 70%,#fff), var(--win))}
/* ===== plush page hero card, the plushie on a changeable gradient stage ===== */
.hcard{display:flex;flex-direction:column;align-items:center;padding:10px 0 2px}
.hc-stage{position:relative;display:flex;align-items:center;justify-content:center;
  width:min(74vw,320px);aspect-ratio:1/1.06;border-radius:30px;
  box-shadow:inset 0 0 0 1px rgba(64,52,43,.05),inset 0 2px 12px rgba(255,255,255,.5),0 20px 44px -24px rgba(64,52,43,.4)}
.hc-stage::after{content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;
  background:linear-gradient(120deg,transparent 44%,rgba(255,255,255,.28) 51%,transparent 60%)}
.hc-cut{position:relative;z-index:2;width:112%;max-width:none;max-height:126%;object-fit:contain;
  filter:drop-shadow(0 18px 18px rgba(64,52,43,.3));transform:translateY(-5%) rotate(-6deg);
  user-select:none;-webkit-user-select:none;-webkit-touch-callout:none}
.hc-cut.hc-emoji{font-size:120px;line-height:1;width:auto}
.hc-shadow{position:absolute;z-index:1;bottom:7%;left:50%;width:56%;height:16px;border-radius:50%;
  background:radial-gradient(ellipse at center,rgba(46,38,30,.32),transparent 68%);transform:translateX(-50%);pointer-events:none}
.hc-sw{margin-top:16px}
/* sticker view controls, outline swatches + aura, inside the pane */
.stkopt{margin-top:2px;text-align:center}
.stkdots{display:flex;gap:11px;justify-content:center;flex-wrap:wrap}
.stk-sw{width:32px;height:32px;border-radius:11px;border:0;cursor:pointer;padding:0;position:relative;
  box-shadow:inset 0 0 0 1px rgba(64,52,43,.14),inset 0 1px 0 rgba(255,255,255,.4);transition:transform .15s var(--ease-out),box-shadow .15s;touch-action:manipulation}
.stk-sw::after{content:"";position:absolute;inset:-6px;border-radius:14px} /* 44px hit area */
.stk-sw:hover{transform:scale(1.08)}
.stk-sw.on{box-shadow:0 0 0 2px var(--paper),0 0 0 4px var(--coral-d),inset 0 0 0 1px rgba(64,52,43,.14)}
.stkc-white{background:#fff}.stkc-cream{background:#fffdf9}.stkc-black{background:#4a4640}.stkc-pink{background:#f4b8cc}
.stkc-mint{background:#b7ddc6}.stkc-sky{background:#aecbe6}.stkc-coral{background:#f0a48a}
.hero-cutout.stc-white{filter:url(#pbst-white) var(--glow,drop-shadow(0 0 0 transparent)) drop-shadow(0 16px 18px rgba(64,52,43,.26))}
.hero-cutout.stc-black{filter:url(#pbst-black) var(--glow,drop-shadow(0 0 0 transparent)) drop-shadow(0 16px 18px rgba(64,52,43,.26))}
.hero-cutout.stc-pink{filter:url(#pbst-pink) var(--glow,drop-shadow(0 0 0 transparent)) drop-shadow(0 16px 18px rgba(64,52,43,.26))}
.hero-cutout.stc-mint{filter:url(#pbst-mint) var(--glow,drop-shadow(0 0 0 transparent)) drop-shadow(0 16px 18px rgba(64,52,43,.26))}
.hero-cutout.stc-sky{filter:url(#pbst-sky) var(--glow,drop-shadow(0 0 0 transparent)) drop-shadow(0 16px 18px rgba(64,52,43,.26))}
.hero-cutout.stc-coral{filter:url(#pbst-coral) var(--glow,drop-shadow(0 0 0 transparent)) drop-shadow(0 16px 18px rgba(64,52,43,.26))}
/* whole-photo plushies sit in the pack window as a rounded print, not a hard rectangle */
.pk-content img.char.charwhole{border-radius:14px}
/* pack customizer controls (owner), cute toy-shop chips + a size slider */
.packopts{margin-top:14px;width:min(340px,90vw);background:var(--card);border:1px solid var(--line);border-radius:18px;padding:6px 16px 16px;box-shadow:var(--shadow-s)}
.packopts>summary{list-style:none;cursor:pointer;position:relative;font-family:var(--display);font-weight:600;color:var(--coral-d);text-align:center;padding:10px 0 4px}
.packopts>summary::-webkit-details-marker{display:none}
.packopts[open]>summary::after{content:"✕";position:absolute;right:2px;top:50%;transform:translateY(-50%);
  font:800 .85rem/1 var(--body);color:var(--ink2);width:32px;height:32px;display:grid;place-items:center}
/* sectioned customizer sheet, a soft tab rail, one pane at a time (design-inspo/package.png) */
.pktabs{display:flex;gap:3px;justify-content:center;flex-wrap:wrap;margin:8px 0 12px;
  background:var(--paper);border:1px solid rgba(64,52,43,.12);border-radius:999px;padding:4px}
.pktabb{border:0;background:transparent;font-family:var(--body);font-weight:800;font-size:.79rem;color:var(--ink2);
  padding:8px 11px;min-height:36px;border-radius:999px;cursor:pointer;-webkit-tap-highlight-color:transparent;
  transition:background .15s var(--ease-out),color .15s var(--ease-out)}
.pktabb.active{background:#fdeee9;color:var(--coral-d)}
@media(max-width:460px){
  .pktabs{display:grid;grid-template-columns:repeat(4,1fr);border-radius:18px}
  .pktabb{padding:8px 2px;font-size:.72rem;border-radius:14px}
}
.pkpane{min-height:64px;display:flex;flex-direction:column;justify-content:center}
.pkpane[hidden]{display:none}
.pkoptlbl{font-size:.72rem;text-transform:uppercase;letter-spacing:.06em;color:var(--ink2);font-weight:700;margin:12px 0 6px;text-align:center}
.pkstyles{display:flex;gap:8px;flex-wrap:wrap;justify-content:center}
.pkchip{font-family:var(--display);font-weight:600;font-size:.85rem;padding:9px 13px;border-radius:14px;cursor:pointer;
  background:#fff;border:2px solid var(--line);color:var(--ink);transition:transform .15s var(--ease-out),border-color .15s,background .15s;touch-action:manipulation}
.pkchip.small{font-size:.78rem;padding:7px 11px}
.pkchip:hover{border-color:var(--coral);transform:translateY(-1px)}
.pkchip:active{transform:translateY(1px)}
.pkchip.active{border-color:var(--coral);background:#fdeee9;color:var(--coral-d)}
/* colour swatches, full-bleed rounded squares, ONE ring (gap + coral) when picked */
.pkcolor{width:38px;height:38px;border-radius:12px;border:0;cursor:pointer;position:relative;padding:0;
  box-shadow:inset 0 0 0 1px rgba(64,52,43,.14),inset 0 1px 0 rgba(255,255,255,.4);transition:transform .15s var(--ease-out),box-shadow .15s;touch-action:manipulation}
.pkcolor::after{content:"";position:absolute;inset:-5px;border-radius:14px} /* 48px hit area */
.pkcolor:hover{transform:scale(1.08)}
.pkcolor:active{transform:scale(1.02)}
.pkcolor.active{box-shadow:0 0 0 2px var(--paper),0 0 0 4px var(--coral-d),inset 0 0 0 1px rgba(64,52,43,.14)}
.pkc-aura{border-radius:50%} /* the "match my aura" rainbow stays a disc, it's the odd one out on purpose */
.pkc-aura{background:conic-gradient(from 0deg,#ff78aa,#f5be5a,#82cd9b,#78aaff,#be96f0,#ff78aa)}
.pkc-coral{background:#e07a5f}.pkc-pink{background:#ff9ec4}.pkc-green{background:#9cc77e}
.pkc-purple{background:#b99ce0}.pkc-blue{background:#7fb2e6}.pkc-yellow{background:#f2c94c}
/* corner-sticker picker */
.pkstk{width:42px;height:42px;border-radius:12px;border:2px solid var(--line);background:#fff;cursor:pointer;font-size:1.2rem;line-height:1;
  display:flex;align-items:center;justify-content:center;transition:transform .15s var(--ease-out),border-color .15s;touch-action:manipulation}
.pkstk:hover{border-color:var(--coral);transform:translateY(-1px)}
.pkstk:active{transform:translateY(1px)}
.pkstk.active{border-color:var(--coral);background:#fdeee9;box-shadow:0 0 0 2px rgba(224,122,95,.25)}
.sizerow{display:flex;align-items:center;gap:10px;width:100%;font-size:1.1rem;margin:0}
.sizerow input[type=range]{flex:1;accent-color:var(--coral-d);height:44px;cursor:pointer}
/* bulk add grid */
.bulkgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:12px;margin:16px 0}
.bulkcard{position:relative;background:var(--card);border:1px solid var(--line);border-radius:14px;padding:8px;box-shadow:var(--shadow-s)}
.bulkcard img{width:100%;aspect-ratio:1;object-fit:contain;background:#f6efe6;border-radius:10px;display:block}
.bulkcard input{width:100%;margin-top:8px;padding:8px 10px;font-size:16px;border:1px solid var(--line);border-radius:9px;background:#fff;color:var(--ink)}
.bulkcard input:focus{outline:none;border-color:var(--coral);box-shadow:0 0 0 3px rgba(224,122,95,.18)}
.bulkdel{position:absolute;top:-8px;right:-8px;z-index:2;width:30px;height:30px;border-radius:50%;border:2px solid #e6b9ae;background:#fff;color:#a13a24;cursor:pointer;font-size:.85rem;box-shadow:var(--shadow-s)}
.bulkdel:hover{background:#fbe4de}.bulkdel:active{transform:translateY(1px)}
.pk-tagline{margin-top:12px;max-width:320px;text-align:center;font-family:var(--hand);font-weight:700;font-size:1.3rem;color:var(--ink);line-height:1.15}
/* plush page */
.tag{display:inline-block;font-size:.78rem;background:#f4e7df;color:#a15a2a;border-radius:999px;padding:4px 12px;margin-top:6px;font-weight:700}
.specsheet{padding:6px 20px;margin:12px auto;max-width:400px}
.specrow{display:flex;justify-content:space-between;gap:14px;padding:9px 0;border-bottom:1px dashed var(--line)}
.specrow:last-child{border-bottom:0}
.speck{font-weight:700;color:var(--ink2);font-size:.9rem;flex:none}
.specv{color:var(--ink);text-align:right;overflow-wrap:anywhere}
.detailform label{font-size:.9rem}
.detailform .field{margin-bottom:12px}
.factsug{display:flex;flex-wrap:wrap;gap:7px;margin:0 0 10px}
.factrow{display:flex;gap:8px;align-items:center;margin-bottom:8px}
.factrow input{flex:1;min-width:0}
.factrow input:first-child{flex:0 0 40%}
.factdel{flex:none;width:40px;height:40px;border-radius:9px;border:2px solid #e6b9ae;background:#fff;color:#a13a24;cursor:pointer;font-size:.9rem}
.factdel:hover{background:#fbe4de}
.hand{font-family:var(--hand);font-weight:700;font-size:2.7rem;line-height:1;margin:16px 0 8px}
.chips{display:flex;gap:8px;flex-wrap:wrap;margin:8px 0}
.chip{background:#fff;border:2px solid var(--line);border-radius:999px;padding:5px 12px;font-size:.85rem;font-weight:600;color:var(--ink2)}
.namecard{margin:12px 0 6px}
.suggestions{display:flex;flex-wrap:wrap;gap:8px;margin-top:12px}
.chip.pick{cursor:pointer;background:#fff;border:2px solid var(--line);color:var(--ink);font-weight:700}
.chip.pick:hover{border-color:var(--coral);background:#fff6f2}
.linkbox{flex:1;min-width:0;overflow:auto;padding:9px 12px;background:#fff;border:2px solid var(--line);border-radius:10px;font-family:ui-monospace,SFMono-Regular,monospace;font-size:.85rem;color:var(--coral-d);text-decoration:none;white-space:nowrap}
.gotcha{color:var(--ink2);font-weight:600;margin:8px 0 16px}
.story{margin-top:16px}
.story h3{font-family:var(--display);font-weight:600;font-size:1.05rem;margin-bottom:6px}
.story p{color:var(--ink);margin:0;white-space:pre-line}
.btn.danger{background:transparent;color:#a13a24;border:2px solid #e6b9ae;box-shadow:none}
.btn.danger:hover{transform:none;box-shadow:none}
.btn.danger:hover{background:#fbe4de}
/* ===== display wall: each plushie hangs as its pack from a metal bracket seated in an
   undercut groove between panel planks. The back-panel design is themeable, a .wt-*
   class sets --panel1/2, --groove, --grain. Depth = drop-shadow + translateZ (no mirror
   reflection on packaging). ===== */
/* --gapy: the phase of the plank-gap pattern against the PADDING box, i.e. a gap covers
   --gapy + n*--pitch .. +12px. The drag gap-guides read this same var, so the guides and
   the painted gaps can't drift apart (it shifts on narrow screens, see the 560px query). */
/* --maskh: height of the plaque mask (layer 1). A var, not a background-size list, because
   --grain is 1 layer on most themes and 2 on Cork — any background-* list short of the real
   layer count REPEATS onto the extras (CSS Backgrounds 3 §3.10), so the narrow-screen
   override used to hand the base panel fill a 208px tile and seam it across the planks. */
.wall{--gapy:46px;--maskh:290px;
  --panel1:#f6efe0;--panel2:#eee4cf;--groove:rgba(122,96,60,.30);--gap:#71583f;--grain:linear-gradient(rgba(0,0,0,0),rgba(0,0,0,0));--pitch:60px;
  display:grid;grid-template-columns:repeat(auto-fill,minmax(min(150px,44%),1fr));gap:58px 14px;
  margin:16px auto 6px;max-width:900px;padding:40px 16px 42px;border-radius:22px;overflow:hidden;
  position:relative; /* containing block for .gapguide, which is placed in wall coords */
  /* horizontal slat planks with real dark gaps between them (see slat-inspo). The maths:
     row stride = 22 padding + 160.08 card + 58 row-gap ≈ 240px, and --pitch is only ever
     a divisor of 240 (40/48/60/80/120), so a gap lands behind EVERY row's hooks whatever
     panel size the user picks. Gap height is FIXED at 12px (the hook clamp is built for
     it). Period order is gap → lit lip → plank face → shade, phased so a gap centres on
     y52 of each row, starting the period on the gap means the wall's top edge can never
     show an orphan highlight line. */
  background:
    /* top mask: the whole plaque zone (padding 40 + 182 plaque row) is clean panel, no
       partial gap slivers behind or beside the plaque, whatever the pitch. The first
       visible gap is the one the first row of hooks clamps into. */
    linear-gradient(var(--panel1),var(--panel1)) 0 0/100% var(--maskh) no-repeat,
    repeating-linear-gradient(to bottom,
      var(--gap) 0 12px,
      rgba(255,255,255,.4) 12px 14px,
      transparent 14px calc(var(--pitch) - 2px),
      rgba(0,0,0,.16) calc(var(--pitch) - 2px) var(--pitch)) 0 var(--gapy),
    var(--grain),
    linear-gradient(var(--panel1),var(--panel2));
  /* mask covers the side padding, no stripe slivers at the edges. Five values for four
     layers: the spare is ignored on normal themes and catches Cork's second grain layer,
     which would otherwise cycle back to border-box. */
  background-origin:border-box,padding-box,padding-box,padding-box,padding-box;
  box-shadow:inset 0 2px 14px rgba(64,52,43,.16),inset 0 -3px 10px rgba(64,52,43,.08);
  border:1px solid rgba(64,52,43,.14)}
/* keychains hang at a normal, readable size in Auto (the plush isn't tiny). Users who want
   more per row pick an explicit count (.wall-cpr, below). ONLY the column axis changes; the
   58px row-gap and the 182px keychain row height are untouched, so hooks land on their gaps. */
.wall.at-keychain{grid-template-columns:repeat(auto-fill,minmax(min(112px,30%),1fr));column-gap:8px}
.wall.at-keychain .charm-cut{max-width:96px;max-height:106px}
.wall.at-keychain .charm-emoji{font-size:76px}
/* acrylic cases pack the same 5-per-row on a phone (column axis only; the 182px case row
   height and plank stride are untouched, so hooks still land on their gaps) */
.wall.at-case{grid-template-columns:repeat(auto-fill,minmax(min(66px,18%),1fr));column-gap:5px}
.wall.at-case .cs-cut{max-width:64px;max-height:80px}
.wall.at-case .cs-emoji{font-size:52px}
/* user-chosen "per row": an exact column count overrides the per-type auto grid. The
   cutouts switch to a % of their cell so they scale with the column width (bigger when
   fewer per row, smaller when more), capped so they never balloon past their old size. */
.wall.wall-cpr{grid-template-columns:repeat(var(--cpr,3),minmax(0,1fr))!important}
.wall.wall-cpr.at-keychain .charm-cut{max-width:min(112px,86%)}
.wall.wall-cpr.at-case .cs-cut{max-width:min(118px,88%)}
.wallpack{position:relative;display:block;text-decoration:none;color:inherit;padding-top:22px;
  -webkit-tap-highlight-color:transparent;
  /* long-press arms the reorder drag, don't let iOS pop the link preview sheet */
  -webkit-touch-callout:none;user-select:none;-webkit-user-select:none}
/* wall images must be pointer-transparent so a long-press lands on the <a> (which has
   touch-callout:none), not the <img>, which would pop the browser's "save/copy image"
   menu and block dragging the plushie around. Applies to every format (keychain + packs). */
.wall img{pointer-events:none;-webkit-touch-callout:none;-webkit-user-drag:none;user-select:none;-webkit-user-select:none}
/* the shop plaque is MOUNTED ON the wall (top row, exactly 182px = one pack row), so it
   travels with the wall when shared. The first pack row then starts one full 240px
   stride below and every hook still lands on a plank gap. */
.wallsignrow{grid-column:1/-1;height:182px;display:flex;align-items:center;justify-content:center}
.wallsign{--sg1:#f6aebf;--sg2:#ee9ab0;--trim:linear-gradient(rgba(0,0,0,0),rgba(0,0,0,0));--wood:linear-gradient(rgba(0,0,0,0),rgba(0,0,0,0));
  position:relative;display:flex;align-items:center;gap:18px;
  width:min(700px,97%);min-height:128px;padding:16px 28px;border:3px solid #43291b;border-radius:20px;
  background:var(--trim),var(--wood),linear-gradient(180deg,var(--sg1),var(--sg2));
  box-shadow:0 4px 0 rgba(67,41,27,.32),0 12px 22px -8px rgba(64,52,43,.35),inset 0 2px 0 rgba(255,255,255,.35)}
/* ── free-form fastener pieces: pinned anywhere on the banner by inline left/top %, added
   + dragged by the owner while the drawer is open. The graphics reuse the swappable
   plaque-fastener look above, but each is its own draggable piece (--fr = tilt). A
   transparent pad gives every piece a comfortable touch target; ::before is the visual. */
.ws-fast{position:absolute;transform:translate(-50%,-50%) rotate(var(--fr,0deg)) scale(var(--fsc,1));
  transform-origin:50% 50%;z-index:3;padding:13px;line-height:0;pointer-events:none;
  -webkit-user-select:none;user-select:none;transition:opacity .15s var(--ease-out)}
.ws-fast::before{content:"";display:block}
/* the small round pieces need extra pad to keep a ≥44px drag target (parity with the
   emoji badges); tape/ribbon are already wide enough at the base 13px pad */
.fk-screw,.fk-tack{padding:17px}
.fk-screw::before{width:10px;height:10px;border-radius:50%;
  background:radial-gradient(circle at 35% 30%,#e8ebf0,#8b919c);
  box-shadow:inset 0 -1px 1px rgba(0,0,0,.35),0 1px 1px rgba(255,255,255,.4)}
.fk-tack::before{width:15px;height:15px;border-radius:50%;
  background:radial-gradient(circle at 34% 30%,#ff9aa8,#d94b60 68%);
  box-shadow:0 2px 3px rgba(64,52,43,.42),inset 0 -2px 2px rgba(150,20,40,.5),inset 0 2px 2px rgba(255,255,255,.5)}
.fk-tape::before{width:64px;height:26px;
  background:repeating-linear-gradient(45deg,rgba(255,255,255,.62) 0 7px,rgba(255,255,255,.42) 7px 14px);
  border:1px solid rgba(255,255,255,.5);box-shadow:0 1px 3px rgba(64,52,43,.24)}
.fk-ribbon::before{width:74px;height:40px;
  background:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 74 40'><defs><linearGradient id='lp' x1='0' x2='0' y1='0' y2='1'><stop offset='0' stop-color='%23f0977f'/><stop offset='.55' stop-color='%23e07a5f'/><stop offset='1' stop-color='%23c85a44'/></linearGradient><linearGradient id='tl' x1='0' x2='0' y1='0' y2='1'><stop offset='0' stop-color='%23e07a5f'/><stop offset='1' stop-color='%23b34e3a'/></linearGradient></defs><path d='M34 19 C27 26 22 32 17 38 L24 38 C28 33 32 27 36 21 Z' fill='url(%23tl)'/><path d='M40 19 C47 26 52 32 57 38 L50 38 C46 33 42 27 38 21 Z' fill='url(%23tl)'/><path d='M36 15 C28 4 12 2 8 10 C4 18 16 24 34 19 Z' fill='url(%23lp)' stroke='%23a84531' stroke-width='1'/><path d='M38 15 C46 4 62 2 66 10 C70 18 58 24 40 19 Z' fill='url(%23lp)' stroke='%23a84531' stroke-width='1'/><path d='M33 16 C26 9 16 7.5 12 11' fill='none' stroke='rgba(255,255,255,.4)' stroke-width='1.6' stroke-linecap='round'/><path d='M41 16 C48 9 58 7.5 62 11' fill='none' stroke='rgba(255,255,255,.4)' stroke-width='1.6' stroke-linecap='round'/><rect x='32.4' y='13.4' width='9.2' height='9.4' rx='3.2' fill='%23c85a44' stroke='%23a84531' stroke-width='1'/><rect x='34' y='14.6' width='3' height='3.4' rx='1.4' fill='rgba(255,255,255,.42)'/></svg>") center/contain no-repeat;
  filter:drop-shadow(0 2px 2px rgba(64,52,43,.35))}
body.wtopen .ws-fast{pointer-events:auto;cursor:grab;touch-action:none}
body.wtopen .ws-fast:active{cursor:grabbing}
.ws-fast.bye{--fsc:.7;opacity:.5}
.ws-mid{flex:1;min-width:0;display:flex;flex-direction:column;align-items:center;gap:7px;text-align:center;
  padding:0 40px} /* keep long titles clear of the emoji badge */
.ws-title{font-family:var(--display);font-weight:700;font-size:clamp(1.5rem,5.4vw,2.5rem);line-height:1.05;
  /* break-word, not anywhere: 'anywhere' shrinks min-content to one glyph and the flex
     column happily wraps PHOEB/E'S, break-word only breaks a word that truly overflows */
  letter-spacing:.04em;color:#43291b;overflow-wrap:break-word}
.ws-by{background:#fffdf6;border:2px solid rgba(67,41,27,.45);border-radius:999px;padding:3px 13px;
  font-family:var(--body);font-weight:800;font-size:.85rem;color:#43291b}
/* emoji badges are pinned anywhere on the sign by inline left/top % (dragged by the
   owner while the design drawer is open); translate keeps each centred on its pin */
.ws-emoji{position:absolute;transform:translate(-50%,-50%);font-size:2.1rem;line-height:1;z-index:4;
  padding:10px; /* ≥44px touch target at every width, translate keeps the glyph on its pin */
  filter:drop-shadow(0 2px 2px rgba(67,41,27,.3));-webkit-user-select:none;user-select:none}
/* badges are draggable ONLY while the design drawer is open, otherwise a swipe that
   lands on one must scroll the page, not silently move the badge */
body.wtopen .ws-emoji{cursor:grab;touch-action:none}
body.wtopen .ws-emoji:active{cursor:grabbing;filter:drop-shadow(0 4px 4px rgba(67,41,27,.36))}
/* dragging a badge over the bin: it shrinks back as a "let go and it's gone" preview */
.ws-emoji.bye{opacity:.5;transform:translate(-50%,-50%) scale(.7)}
/* the drop-to-remove pill, hidden until a badge is actually moving, so it never sits
   in the way of the wall. Fixed to the viewport: the plaque can be scrolled anywhere. */
.embin{position:fixed;left:50%;bottom:calc(26px + env(safe-area-inset-bottom));z-index:230;display:flex;align-items:center;gap:8px; /* above the wall-design sheet (220) or it's an invisible drop target */
  padding:11px 18px;border-radius:999px;background:var(--card);color:var(--ink2);
  border:2px dashed rgba(64,52,43,.32);box-shadow:0 10px 24px rgba(64,52,43,.22);
  font-family:var(--body);font-weight:800;font-size:.86rem;white-space:nowrap;
  opacity:0;pointer-events:none;transform:translate(-50%,16px);
  transition:opacity .18s var(--ease-out),transform .18s var(--ease-out),background .15s,border-color .15s}
.embin .embin-i{font-size:1.15rem;line-height:1}
.embin.on{opacity:1;transform:translate(-50%,0)}
.embin.hot{background:#ffe6df;border-color:var(--coral-d);border-style:solid;color:var(--coral-d);
  transform:translate(-50%,0) scale(1.07)}
@media(prefers-reduced-motion:reduce){.embin{transition:opacity .01s}}
/* on phones the bottom tab bar owns the bottom edge, lift the bin clear of it */
@media(max-width:899px){.embin{bottom:calc(76px + env(safe-area-inset-bottom))}}
@media(max-width:560px){.ws-emoji{font-size:1.5rem}.wallsign{gap:10px;padding:12px 16px;min-height:110px}
  /* tighter plaque zone: padding 40→20 + sign row 182→140 = 62px reclaimed. The plank
     pattern phase (46px) and the top mask (250px) shift by the SAME 62 so every hook
     still clamps onto a plank gap at every pitch. */
  .wall{padding-top:20px;--gapy:-16px;--maskh:208px}
  .wallsignrow{height:140px}}
/* Gap guides: while a pack is being dragged, every plank gap its hook can clamp into
   lights up down its own column, and the one the current drop height would pick lights
   up solid. The gaps are the whole affordance and nothing pointed at them before.
   Ladder length + spacing come from --pitch, so it tracks the panel-size slider live.
   z:0 keeps it painted on the WALL, behind every pack (restack gives those 1..N). */
.gapguide{position:absolute;pointer-events:none;z-index:0;border-radius:4px;
  background:repeating-linear-gradient(to bottom,rgba(255,255,255,.5) 0 12px,transparent 12px var(--pitch,60px));
  box-shadow:0 0 0 1px rgba(224,122,95,.25) inset}
/* keep the 12px band height in step with the wall's own gap height above */
.gapguide::after{content:"";position:absolute;left:0;right:0;top:var(--sel,0);height:12px;border-radius:4px;
  background:var(--coral-d);opacity:0;box-shadow:0 0 0 2px rgba(255,255,255,.6),0 2px 9px rgba(224,122,95,.65);
  transition:top .12s var(--ease-out),opacity .12s}
.gapguide.lit::after{opacity:.92}
@media (prefers-reduced-motion:reduce){.gapguide::after{transition:none}}
/* sign colourways */
.wsc-pink{--sg1:#ffd6e6;--sg2:#f49ec0}
.wsc-coral{--sg1:#ffc9ae;--sg2:#f08a6c}
.wsc-sunny{--sg1:#ffefad;--sg2:#ffce68}
.wsc-mint{--sg1:#d2f2e2;--sg2:#9ddcbe}
.wsc-sage{--sg1:#e2efc9;--sg2:#b2d49e}
.wsc-sky{--sg1:#c8e6fb;--sg2:#9ec9ef}
.wsc-lilac{--sg1:#e7d7fa;--sg2:#c6aded}
.wsc-cream{--sg1:#fdf4dc;--sg2:#f3dfae}
.wsc-snow{--sg1:#ffffff;--sg2:#eee7db}
/* a wooden plank sign, horizontal grain over warm wood. Kept a few shades lighter
   than the dark wall themes (walnut/charcoal) so the plaque reads on them. */
.wsc-cocoa{--sg1:#d9ab74;--sg2:#bd8a50}
.wsc-cocoa .ws-by{background:#f7ecd8}
/* sign trims, overlays that work on any colourway */
.wst-stitch{outline:2.5px dashed rgba(67,41,27,.45);outline-offset:-9px}
.wst-dots{--trim:radial-gradient(rgba(255,255,255,.5) 2.4px,transparent 2.9px) 4px 4px/24px 24px}
.wst-gingham{--trim:repeating-linear-gradient(0deg,rgba(255,255,255,.22) 0 10px,transparent 10px 24px),repeating-linear-gradient(90deg,rgba(255,255,255,.22) 0 10px,transparent 10px 24px)}
/* a deliberately empty spot on the wall, invisible at rest, a drop target mid-drag.
   Rest outline is TRANSPARENT and transitions in: mode classes fade the targets in/out
   instead of flashing them, and the dz fold/unfold glides instead of snapping the wall
   182px taller/shorter at the start and end of every phone drag. */
.wallcell{min-height:182px;border-radius:16px;outline:2.5px dashed transparent;outline-offset:-10px;
  transition:outline-color .18s ease,background-color .18s ease}
/* CONSTANT GEOMETRY: the drop-room cells hold a small strip at ALL times (rest, drag,
   place), they used to be 0 at rest and unfold on drag, which grew the wall ~one row
   the instant you grabbed a plushie and slid the whole page ("the panels are scrolling").
   Reserving the strip permanently means the wall never changes height, so a drag can't
   move anything. Only the outline/glow toggles on drag; height stays put. */
.wallcell.dz{min-height:44px}
.wall.reordering .wallcell{outline-color:rgba(64,52,43,.28)}
.celltarget{outline:3px dashed var(--coral-d) !important;outline-offset:-8px;border-radius:16px;background:rgba(224,122,95,.08)}
/* placing mode (wall tray armed or tray drag in flight): every empty spot glows coral so
   legal targets are visible WITHOUT hover (mobile). No height change, the reserved dz
   strip is already a tappable target, and growing it here slid the page too.
   STATIC outline: an infinite pulse on the whole wall reads as "flashing" on a phone. */
.wall.placing .wallcell{outline-color:var(--coral-d);background:rgba(224,122,95,.07)}
@media (prefers-reduced-motion:reduce){.wallcell{transition:none}}
/* just-added pack: a coral ring pulses three times, then fades away (reduced-motion: steady halo) */
.wp-new{position:relative}
.wp-new::after{content:"";position:absolute;inset:-7px;z-index:6;pointer-events:none;border:3px solid var(--coral-d);border-radius:20px;animation:wpnew 1.1s ease-in-out 3,wpnewfade .6s ease 3.5s forwards}
@keyframes wpnew{0%,100%{opacity:.45;transform:scale(.985)}50%{opacity:1;transform:scale(1.015)}}
@keyframes wpnewfade{to{opacity:0}}
@media (prefers-reduced-motion:reduce){.wp-new::after{animation:none;opacity:.85}}
/* ---- wall tray: storage plushies waiting for a spot (under the Display wall) ---- */
.wtray{margin:16px 0 0;padding:10px 12px 12px;border-radius:18px;background:var(--card);border:1px solid var(--line);box-shadow:var(--shadow-m)}
.wtray[hidden]{display:none}
.wtray-head{display:flex;justify-content:space-between;align-items:baseline;gap:4px 12px;flex-wrap:wrap;font:700 .84rem var(--body);color:var(--ink)}
.wtray-tip{font:600 .74rem var(--body);color:var(--ink2)}
/* the inline desktop tray needs no close; the mobile bottom-sheet gets a persistent X
   pinned top-right so it's reachable even after the storage row is scrolled. */
.wtray-close{display:none;align-items:center;justify-content:center;width:30px;height:30px;border:0;border-radius:50%;
  background:var(--paper);color:var(--ink2);font-size:.85rem;cursor:pointer;box-shadow:0 1px 3px rgba(64,52,43,.2);-webkit-tap-highlight-color:transparent}
.wtray-close:hover{background:#ffe6df;color:var(--coral-d)}
@media(max-width:719px){.wtray-close{display:flex;position:absolute;top:12px;right:12px;z-index:3}.wtray-head{padding-right:40px}}
.wtray-row{display:flex;gap:10px;overflow-x:auto;padding:10px 2px 2px;-webkit-overflow-scrolling:touch;scrollbar-width:thin}
.wtray-item{flex:0 0 auto;width:76px;min-height:96px;display:flex;flex-direction:column;align-items:center;gap:5px;padding:8px 6px;
  border:2px dashed rgba(64,52,43,.18);border-radius:16px;background:var(--paper);cursor:pointer;
  touch-action:pan-x;-webkit-tap-highlight-color:transparent;font-family:inherit;color:inherit;
  transition:transform .15s var(--ease-out),border-color .15s,background .15s,box-shadow .15s}
.wtray-item:active{transform:scale(.96)}
.wtray-pic{width:56px;height:56px;display:grid;place-items:center}
.wtray-pic img{max-width:100%;max-height:100%;object-fit:contain;filter:drop-shadow(0 3px 4px rgba(64,52,43,.22));
  pointer-events:none;user-select:none;-webkit-user-select:none;-webkit-touch-callout:none}
.wtray-emoji{font-size:34px;line-height:1}
.wtray-name{max-width:100%;font:700 .68rem var(--body);color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.wtray-item.lift{border-style:solid;border-color:var(--coral-d);background:#fff;box-shadow:0 8px 18px -8px rgba(200,90,68,.55)}
.wtghost{position:fixed;z-index:99999;width:64px;height:64px;object-fit:contain;pointer-events:none;transform:translate(-50%,-72%);filter:drop-shadow(0 10px 14px rgba(64,52,43,.4))}
/* ---- mobile: the tray becomes a bottom drawer (same pattern as the wall-design
   picker). The wall is tall; a strip at its foot means scrolling past every row to
   reach storage, and placing into a high spot was near-impossible. Now: a floating
   "🧺 N in storage" pill opens the drawer over the page; tapping a friend collapses
   it to a "Placing {name}" chip so the WHOLE wall stays scrollable + tappable. ---- */
.wtrayfab{position:fixed;right:14px;bottom:calc(14px + env(safe-area-inset-bottom));z-index:110;
  display:none;align-items:center;gap:7px;padding:11px 15px;min-height:44px;border-radius:999px;
  border:1px solid var(--line);background:var(--card);box-shadow:0 10px 24px rgba(64,52,43,.3);
  font:800 .85rem var(--body);color:var(--ink);cursor:pointer;-webkit-tap-highlight-color:transparent}
.wtrayfab b{color:var(--coral-d)}
.wtrayscrim{position:fixed;inset:0;z-index:115;background:rgba(43,32,23,.34);opacity:0;pointer-events:none;transition:opacity .22s ease}
.wtrayscrim.show{opacity:1;pointer-events:auto}
@media (min-width:720px){.wtrayfab,.wtrayscrim{display:none !important}}
@media (max-width:719px){
  .wtray{position:fixed;left:0;right:0;bottom:0;z-index:120;margin:0;max-height:48vh;overflow-y:auto;
    border-radius:20px 20px 0 0;border-bottom:0;padding:8px 12px calc(14px + env(safe-area-inset-bottom));
    transform:translateY(106%);transition:transform .24s var(--ease-out);box-shadow:0 -12px 34px rgba(64,52,43,.28)}
  .wtray.open{transform:none}
  .wtray::before{content:"";display:block;width:44px;height:5px;border-radius:3px;background:var(--line);margin:0 auto 8px} /* grab handle */
  .wtrayfab.show{display:inline-flex}
  /* the fixed bottom nav owns the bottom ~64px+safe-area, the fab and placing chip
     must float above it, not on top of the Saved/Profile tabs */
  .wtrayfab{bottom:calc(88px + env(safe-area-inset-bottom))}
  .wallpane{padding-bottom:140px} /* fab clearance, ONLY the wall pane, not the toolbar (it made a huge top gap) */
}
.wallpack:focus-visible{outline:none}
.wallpack:focus-visible .packcard{outline:3px solid var(--coral-d);outline-offset:5px;border-radius:28px}
.wallpack .packcard{width:300px;zoom:.46;margin:0 auto;position:relative;top:11px;z-index:1;transform:translateZ(0); /* sits low enough that the hook visibly hooks the euro-slot */
  transform-origin:50% 17px; /* the prong through the hang hole, the pendulum fulcrum */
  transition:transform .26s var(--ease-out);
  filter:drop-shadow(0 13px 15px rgba(64,52,43,.34))}
.wallpack .pk-tagline{display:none}
.wallpack .pk-content img.char,.wallpack .pk-content span.char{cursor:inherit}
/* touch/hover physics: a damped pendulum swing about the hook (no lift, a hung pack
   can't float off its groove, it can only swing) */
@keyframes pkswing{
  0%{transform:translateZ(0) rotate(0)}
  14%{transform:translateZ(0) rotate(6.5deg)}
  34%{transform:translateZ(0) rotate(-4.8deg)}
  54%{transform:translateZ(0) rotate(3deg)}
  72%{transform:translateZ(0) rotate(-1.6deg)}
  87%{transform:translateZ(0) rotate(.7deg)}
  100%{transform:translateZ(0) rotate(0)}
}
.wallpack .packcard.swing{animation:pkswing 1.5s ease-in-out}
.wallpack:active .packcard{transform:translateZ(0) translateY(1px)}
@media(prefers-reduced-motion:reduce){.wallpack .packcard.swing{animation:none}}
/* the display hook, like a real slat-wall peg (see shelf-inspo refs): a folded metal
   clamp grips the plank lip at the groove, and its prong runs down BEHIND the pack,
   so the strap is hidden by the packaging (z below the card) while .peg-tip shows the
   prong passing THROUGH the punched hang hole (z above the card, sized to the hole). */
.peg{position:absolute;top:3px;left:50%;transform:translateX(-50%);width:22px;height:38px;z-index:0;pointer-events:none;
  background:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 38'><defs><linearGradient id='f' x1='0' x2='1' y1='0' y2='0'><stop offset='0' stop-color='%23eef1f5'/><stop offset='.45' stop-color='%23c3c8d1'/><stop offset='1' stop-color='%23a4abb6'/></linearGradient><linearGradient id='s' x1='0' x2='1' y1='0' y2='0'><stop offset='0' stop-color='%23dfe3e9'/><stop offset='.5' stop-color='%23b6bcc6'/><stop offset='1' stop-color='%23979ea9'/></linearGradient></defs><rect x='4' y='4' width='14' height='13' rx='2.5' fill='url(%23f)' stroke='%236b7280' stroke-width='1'/><rect x='3' y='1.5' width='16' height='4' rx='2' fill='%23b9bfc9' stroke='%236b7280' stroke-width='1'/><circle cx='11' cy='10.5' r='1.7' fill='%23848b96'/><rect x='8.6' y='16' width='4.8' height='21' rx='2.2' fill='url(%23s)' stroke='%236b7280' stroke-width='.8'/></svg>") center/contain no-repeat;
  filter:drop-shadow(0 2px 1.5px rgba(64,52,43,.28))}
/* on the wall, the punched hang hole is a REAL hole, you see the chosen back
   panel through it (theme vars cascade down from .wall), not paper */
.wallpack .pk-hang path{fill:var(--panel2,#eee4cf)}
/* the bit of prong visible through the pack's euro-slot hole */
/* the hook rests AT the rounded upper border of the hole: a small nub hooked over the
   top inner edge (not a prong running to the bottom of the slot). z:8 so it sits in front
   of the hole's back-panel fill. */
.peg-tip{position:absolute;top:31px;left:50%;transform:translateX(-50%);width:8px;height:7px;z-index:8;pointer-events:none;border-radius:4px 4px 5px 5px;
  background:linear-gradient(90deg,#dfe3e9,#b6bcc6 50%,#979ea9);box-shadow:0 0 0 .8px #6b7280,0 1.5px 2px rgba(0,0,0,.3)}
/* hook finishes, same clamp-into-gap + prong-through-hole geometry, different metal */
.hk-noir .peg{background-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 38'><defs><linearGradient id='f' x1='0' x2='1' y1='0' y2='0'><stop offset='0' stop-color='%23555962'/><stop offset='.45' stop-color='%2333363d'/><stop offset='1' stop-color='%2320222a'/></linearGradient><linearGradient id='s' x1='0' x2='1' y1='0' y2='0'><stop offset='0' stop-color='%234a4d55'/><stop offset='.5' stop-color='%232b2d34'/><stop offset='1' stop-color='%23191b20'/></linearGradient></defs><rect x='4' y='4' width='14' height='13' rx='1.2' fill='url(%23f)' stroke='%230c0d10' stroke-width='1'/><rect x='3' y='1.5' width='16' height='4' rx='1' fill='%232e3138' stroke='%230c0d10' stroke-width='1'/><circle cx='11' cy='10.5' r='1.7' fill='%23111318'/><rect x='8.6' y='16' width='4.8' height='21' rx='2.2' fill='url(%23s)' stroke='%230c0d10' stroke-width='.8'/></svg>")}
.hk-noir .peg-tip{background:linear-gradient(90deg,#4a4d55,#2b2d34 50%,#191b20);box-shadow:0 0 0 .8px #0c0d10,0 1px 1.5px rgba(0,0,0,.35)}
.hk-brass .peg{background-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 38'><defs><linearGradient id='f' x1='0' x2='1' y1='0' y2='0'><stop offset='0' stop-color='%23f7e6b0'/><stop offset='.45' stop-color='%23d9b45e'/><stop offset='1' stop-color='%23b08c34'/></linearGradient><linearGradient id='s' x1='0' x2='1' y1='0' y2='0'><stop offset='0' stop-color='%23eed9a0'/><stop offset='.5' stop-color='%23caa54d'/><stop offset='1' stop-color='%23a17d2c'/></linearGradient></defs><rect x='4' y='4' width='14' height='13' rx='2.5' fill='url(%23f)' stroke='%23705a14' stroke-width='1'/><rect x='3' y='1.5' width='16' height='4' rx='2' fill='%23cfa953' stroke='%23705a14' stroke-width='1'/><circle cx='11' cy='10.5' r='1.7' fill='%23907022'/><rect x='8.6' y='16' width='4.8' height='21' rx='2.2' fill='url(%23s)' stroke='%23705a14' stroke-width='.8'/></svg>")}
.hk-brass .peg-tip{background:linear-gradient(90deg,#eed9a0,#caa54d 50%,#a17d2c);box-shadow:0 0 0 .8px #705a14,0 1px 1.5px rgba(0,0,0,.25)}
.hk-coral .peg{background-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 38'><defs><linearGradient id='f' x1='0' x2='1' y1='0' y2='0'><stop offset='0' stop-color='%23ffc0ab'/><stop offset='.45' stop-color='%23e8886b'/><stop offset='1' stop-color='%23c85a44'/></linearGradient><linearGradient id='s' x1='0' x2='1' y1='0' y2='0'><stop offset='0' stop-color='%23f8b09a'/><stop offset='.5' stop-color='%23dd7457'/><stop offset='1' stop-color='%23b34e3a'/></linearGradient></defs><rect x='4' y='4' width='14' height='13' rx='2.5' fill='url(%23f)' stroke='%237c3323' stroke-width='1'/><rect x='3' y='1.5' width='16' height='4' rx='2' fill='%23e08a6d' stroke='%237c3323' stroke-width='1'/><circle cx='11' cy='10.5' r='1.7' fill='%23a04530'/><rect x='8.6' y='16' width='4.8' height='21' rx='2.2' fill='url(%23s)' stroke='%237c3323' stroke-width='.8'/></svg>")}
.hk-coral .peg-tip{background:linear-gradient(90deg,#f8b09a,#dd7457 50%,#b34e3a);box-shadow:0 0 0 .8px #7c3323,0 1px 1.5px rgba(0,0,0,.25)}
/* ── keychain mode: the plushie leaves the package and hangs as a plush keychain,
   a metal split ring (the wall hook passes THROUGH it) → a fabric strap sewn to the
   plushie → the plushie itself, with a soft drop-shadow so it reads as hanging under a
   light from above. No die-cut outline. Swing pivots at the ring/hook. ── */
.pk-charm{display:none}
.at-keychain .packcard,.at-keychain .peg-tip{display:none} /* hide the blister pack */
/* keep the SAME 182px row box as hook mode so the plank gaps stay behind EVERY hook,
   on every row; the plushie is free to dangle past the box into the gap below */
.at-keychain .wallpack{height:182px;padding-top:0;overflow:visible}
.at-keychain .pk-charm{display:flex;flex-direction:column;align-items:center;width:100%;position:relative;
  transform-origin:50% 44px; /* the ring the hook passes through, the pendulum fulcrum */
  transition:transform .26s var(--ease-out)}
/* the wall hook sits IN the plank gap (peg unchanged from hook mode) and is drawn in
   FRONT of the keychain so it clearly holds the ring */
.at-keychain .peg{z-index:8}
/* metal split ring, hanging on the hook, fat, glossy boutique hardware (see
   design-inspo/keychaindesigns.png): thick band, bright top-left specular, split tab */
.charm-ring{margin-top:28px;width:33px;height:33px;flex-shrink:0;z-index:1;position:relative;
  background:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><defs><linearGradient id='r' x1='0' x2='1' y1='0' y2='1'><stop offset='0' stop-color='%23f7f9fc'/><stop offset='.45' stop-color='%23c9cfd8'/><stop offset='1' stop-color='%238b93a0'/></linearGradient></defs><circle cx='16' cy='16' r='11' fill='none' stroke='url(%23r)' stroke-width='5.2'/><circle cx='16' cy='16' r='11' fill='none' stroke='rgba(255,255,255,.5)' stroke-width='1.1'/><circle cx='10.2' cy='8.4' r='1.7' fill='rgba(255,255,255,.9)'/><rect x='19.8' y='3.4' width='2.8' height='7.4' rx='1.4' fill='%23848c98' transform='rotate(32 16 16)'/></svg>") center/contain no-repeat;
  filter:drop-shadow(0 2px 1.5px rgba(64,52,43,.34))}
.hk-brass .charm-ring{filter:drop-shadow(0 2px 1.5px rgba(64,52,43,.34)) sepia(.7) saturate(2.4) hue-rotate(2deg)}
.hk-noir .charm-ring{filter:drop-shadow(0 2px 1.5px rgba(64,52,43,.34)) brightness(.42)}
.hk-coral .charm-ring{filter:drop-shadow(0 2px 1.5px rgba(64,52,43,.34)) sepia(.5) saturate(3) hue-rotate(-18deg)}
/* fabric strap: a named tag at the top + a thin tail (::after) that runs down BEHIND the
   plushie, so however the cutout was framed the strap always reaches and reads as sewn on */
.charm-strap{margin-top:-9px;width:26px;min-height:50px;display:flex;align-items:flex-start;justify-content:center;padding:11px 0 8px;z-index:1;position:relative;
  background:
    repeating-linear-gradient(90deg,rgba(58,43,31,.42) 0 2.5px,transparent 2.5px 5px) center top 7px/68% 1.5px no-repeat,
    repeating-linear-gradient(180deg,rgba(255,255,255,.55) 0 3px,transparent 3px 7px) left 3px top/1.5px 100% no-repeat,
    repeating-linear-gradient(180deg,rgba(255,255,255,.55) 0 3px,transparent 3px 7px) right 3px top/1.5px 100% no-repeat,
    linear-gradient(90deg,rgba(0,0,0,.08),rgba(255,255,255,.16) 48%,rgba(0,0,0,.08)),var(--oc,#aecbe6);
  border-radius:5px 5px 4px 4px;box-shadow:inset 0 0 0 1px rgba(255,255,255,.28),0 1px 2px rgba(64,52,43,.26)}
.charm-strap::after{content:"";position:absolute;top:100%;left:50%;transform:translateX(-50%);width:15px;height:var(--tail,52px);
  background:
    repeating-linear-gradient(180deg,rgba(255,255,255,.45) 0 3px,transparent 3px 7px) left 2px top/1.2px 100% no-repeat,
    repeating-linear-gradient(180deg,rgba(255,255,255,.45) 0 3px,transparent 3px 7px) right 2px top/1.2px 100% no-repeat,
    linear-gradient(90deg,rgba(0,0,0,.08),rgba(255,255,255,.16) 48%,rgba(0,0,0,.08)),var(--oc,#aecbe6);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.2)}
/* ── the "strap loops through the ring" illusion, done as THREE LAYERS (no bent
   fabric anywhere): back = the whole hardware (z1, behind the strap) · middle = the
   strap with its rounded cap reaching into the opening (z above the back) · front =
   ONLY the hardware's bottom arc, repainted on the charm's pseudo and clipped below
   the split line (z4). The cap visibly descends into the hole and vanishes behind
   the front arc exactly where the metal band starts. ── */
.pk-charm.att-strap{--hw-art:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><defs><linearGradient id='r' x1='0' x2='1' y1='0' y2='1'><stop offset='0' stop-color='%23f7f9fc'/><stop offset='.45' stop-color='%23c9cfd8'/><stop offset='1' stop-color='%238b93a0'/></linearGradient></defs><circle cx='16' cy='16' r='11' fill='none' stroke='url(%23r)' stroke-width='5.2'/><circle cx='16' cy='16' r='11' fill='none' stroke='rgba(255,255,255,.5)' stroke-width='1.1'/><circle cx='10.2' cy='8.4' r='1.7' fill='rgba(255,255,255,.9)'/><rect x='19.8' y='3.4' width='2.8' height='7.4' rx='1.4' fill='%23848c98' transform='rotate(32 16 16)'/></svg>");--hw-w:33px;--hw-h:33px;--hw-top:28px;--hw-split:72%}
.pk-charm.att-ring{--hw-art:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 42'><defs><linearGradient id='g' x1='0' x2='1' y1='0' y2='1'><stop offset='0' stop-color='%23f7f9fc'/><stop offset='.45' stop-color='%23c9cfd8'/><stop offset='1' stop-color='%238b93a0'/></linearGradient></defs><circle cx='16' cy='13' r='9.6' fill='none' stroke='url(%23g)' stroke-width='4.8'/><circle cx='16' cy='13' r='9.6' fill='none' stroke='rgba(255,255,255,.5)' stroke-width='1.1'/><circle cx='11' cy='7.6' r='1.6' fill='rgba(255,255,255,.9)'/><rect x='13.9' y='24.4' width='4.2' height='5.6' rx='1.8' fill='url(%23g)'/><rect x='14.9' y='25.2' width='1' height='4' rx='.5' fill='rgba(255,255,255,.55)'/><circle cx='16' cy='35.4' r='4' fill='none' stroke='url(%23g)' stroke-width='2.8'/></svg>");--hw-w:36px;--hw-h:47px;--hw-top:23px;--hw-split:88%}
.pk-charm.att-heart{--hw-art:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 42'><defs><linearGradient id='h' x1='0' x2='1' y1='0' y2='1'><stop offset='0' stop-color='%23f7f9fc'/><stop offset='.45' stop-color='%23c9cfd8'/><stop offset='1' stop-color='%238b93a0'/></linearGradient></defs><path d='M16 25.5 C10.8 21 5 16.4 5 10.4 C5 6.3 8 3.9 10.9 3.9 C13.2 3.9 15 5.4 16 7.6 C17 5.4 18.8 3.9 21.1 3.9 C24 3.9 27 6.3 27 10.4 C27 16.4 21.2 21 16 25.5 Z' fill='none' stroke='url(%23h)' stroke-width='4.8' stroke-linejoin='round' stroke-linecap='round'/><path d='M16 25.5 C10.8 21 5 16.4 5 10.4 C5 6.3 8 3.9 10.9 3.9 C13.2 3.9 15 5.4 16 7.6 C17 5.4 18.8 3.9 21.1 3.9 C24 3.9 27 6.3 27 10.4 C27 16.4 21.2 21 16 25.5 Z' fill='none' stroke='rgba(255,255,255,.5)' stroke-width='1.1' stroke-linejoin='round'/><circle cx='10.6' cy='8.2' r='1.6' fill='rgba(255,255,255,.9)'/><rect x='13.9' y='26.2' width='4.2' height='5.6' rx='1.8' fill='url(%23h)'/><rect x='14.9' y='27' width='1' height='4' rx='.5' fill='rgba(255,255,255,.55)'/><circle cx='16' cy='36.4' r='4' fill='none' stroke='url(%23h)' stroke-width='2.8'/></svg>");--hw-w:36px;--hw-h:47px;--hw-top:23px;--hw-split:90%}
.pk-charm.att-strap::after,.pk-charm.att-ring::after,.pk-charm.att-heart::after{content:"";position:absolute;
  top:var(--hw-top);left:50%;transform:translateX(-50%);width:var(--hw-w);height:var(--hw-h);z-index:4;pointer-events:none;
  background:var(--hw-art) center/contain no-repeat;clip-path:inset(var(--hw-split) 0 0 0);
  filter:drop-shadow(0 2px 1.5px rgba(64,52,43,.34))}
/* the front arc wears the same metal tint as the back */
.pk-charm.kr-gold::after{filter:drop-shadow(0 2px 1.5px rgba(64,52,43,.34)) sepia(.8) saturate(3) hue-rotate(4deg)}
.pk-charm.kr-noir::after{filter:drop-shadow(0 2px 1.5px rgba(64,52,43,.34)) brightness(.42)}
.pk-charm.kr-rose::after{filter:drop-shadow(0 2px 1.5px rgba(64,52,43,.34)) sepia(.6) saturate(2.4) hue-rotate(-26deg) brightness(1.06)}
/* the FOLD: a narrow dome of fabric hanging LOW in the opening, most of the loop is
   implied behind the front arc, so only this peek is visible. Same material as the
   strap (the dome runs down behind the arc and meets the strap body with overlap,
   no gap), with a light top edge for thickness and a shadowed base where it dives
   under the rim (occlusion). Plenty of clearance: it never fills the hole. */
.charm-strap::before{content:"";position:absolute;bottom:calc(100% - 1px);left:50%;transform:translateX(-50%);
  width:calc(8px * var(--ksw,1));height:12px;border-radius:100px 100px 0 0; /* smooth bend, not a pill */
  background:linear-gradient(180deg,
    color-mix(in srgb, var(--oc,#aecbe6) 86%, #fff) 0%,          /* lit crest of the bend */
    var(--oc,#aecbe6) 34%,
    color-mix(in srgb, var(--oc,#aecbe6) 78%, #4a3620) 78%,      /* falling into the rim's shade */
    color-mix(in srgb, var(--oc,#aecbe6) 62%, #4a3620) 100%);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.35)}
/* the wide strap starts BEHIND the front arc, it must never show inside the hole
   beside the fold (that reads as "glued on top of the ring") */
.att-strap .charm-strap{margin-top:-4px}
/* clips end in a SMALL link, the fold narrows to thread it, strap tucks under the link */
.att-ring .charm-strap,.att-heart .charm-strap{margin-top:-2px}
.att-ring .charm-strap::before,.att-heart .charm-strap::before{width:calc(4px * var(--ksw,1));height:10px}
.charm-strap>span{writing-mode:vertical-rl;transform:rotate(180deg);font-family:var(--body);font-weight:800;font-size:.56rem;
  letter-spacing:.05em;color:#3a2b1f;white-space:nowrap;max-height:30px;overflow:hidden;text-transform:uppercase}
.pk-charm.oc-black .charm-strap>span{color:#faf4e2} /* scoped: a legacy wall-level oc-black must not recolour every charm's label */
/* the plushie: no outline; a soft drop-shadow (light from top → shadow below) sells the hang.
   It sits IN FRONT of the strap tail and tucks just under the tag so the strap reads as attached */
.charm-cut{margin-top:-6px;width:auto;max-width:122px;height:auto;max-height:132px;object-fit:contain;z-index:2;position:relative;
  filter:drop-shadow(0 11px 9px rgba(64,52,43,.36))}
.charm-emoji{font-size:100px;line-height:1;margin-top:-6px;z-index:2;position:relative;filter:drop-shadow(0 11px 9px rgba(64,52,43,.32))}
/* per-plushie charm customization: strap thickness (--ksw), ring colour (kr-*).
   No per-plushie size, every charm hangs at one scale so the wall stays consistent. */
.charm-strap{width:calc(26px * var(--ksw,1))}
.charm-strap::after{width:calc(15px * var(--ksw,1))}
.charm-strap>span{max-height:82px}
.pk-charm.kr-silver .charm-ring{filter:drop-shadow(0 2px 1.5px rgba(64,52,43,.34))}
.pk-charm.kr-gold .charm-ring{filter:drop-shadow(0 2px 1.5px rgba(64,52,43,.34)) sepia(.8) saturate(3) hue-rotate(4deg)}
.pk-charm.kr-noir .charm-ring{filter:drop-shadow(0 2px 1.5px rgba(64,52,43,.34)) brightness(.42)}
.pk-charm.kr-rose .charm-ring{filter:drop-shadow(0 2px 1.5px rgba(64,52,43,.34)) sepia(.6) saturate(2.4) hue-rotate(-26deg) brightness(1.06)}
/* ── attachment hardware: strap (default) · ring clip · heart clip. The named fabric
   strap is part of EVERY style, the clip is the hardware between hook and strap. ── */
.charm-heart{display:none}
.att-heart .charm-ring{display:none}
.att-heart .charm-heart{display:block}
/* ring clip: same clip anatomy as the heart (ring → swivel barrel → link) but a circle;
   the strap hangs from the link below */
.att-ring .charm-ring{width:36px;height:47px;margin-top:23px;
  background:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 42'><defs><linearGradient id='g' x1='0' x2='1' y1='0' y2='1'><stop offset='0' stop-color='%23f7f9fc'/><stop offset='.45' stop-color='%23c9cfd8'/><stop offset='1' stop-color='%238b93a0'/></linearGradient></defs><circle cx='16' cy='13' r='9.6' fill='none' stroke='url(%23g)' stroke-width='4.8'/><circle cx='16' cy='13' r='9.6' fill='none' stroke='rgba(255,255,255,.5)' stroke-width='1.1'/><circle cx='11' cy='7.6' r='1.6' fill='rgba(255,255,255,.9)'/><rect x='13.9' y='24.4' width='4.2' height='5.6' rx='1.8' fill='url(%23g)'/><rect x='14.9' y='25.2' width='1' height='4' rx='.5' fill='rgba(255,255,255,.55)'/><circle cx='16' cy='35.4' r='4' fill='none' stroke='url(%23g)' stroke-width='2.8'/></svg>") center/contain no-repeat}
/* heart CLIP at the top, fat open heart ring like real boutique hardware, with the
   swivel barrel + small link ring underneath (design-inspo/keychaindesigns.png) */
/* margin-top mirrors the split ring's hang: the ring sits at 28px with its hole centred
   on the hook tip (~44px, the pendulum fulcrum), the heart's top loop must land on the
   same tip, so it starts at 31px and the hook visibly passes through the loop */
.charm-heart{width:36px;height:47px;margin-top:23px;flex-shrink:0;z-index:1;position:relative; /* hook prong tip (y≈41) lands mid-opening, the clip reads as hooked ON, not floating under */
  background:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 42'><defs><linearGradient id='h' x1='0' x2='1' y1='0' y2='1'><stop offset='0' stop-color='%23f7f9fc'/><stop offset='.45' stop-color='%23c9cfd8'/><stop offset='1' stop-color='%238b93a0'/></linearGradient></defs><path d='M16 25.5 C10.8 21 5 16.4 5 10.4 C5 6.3 8 3.9 10.9 3.9 C13.2 3.9 15 5.4 16 7.6 C17 5.4 18.8 3.9 21.1 3.9 C24 3.9 27 6.3 27 10.4 C27 16.4 21.2 21 16 25.5 Z' fill='none' stroke='url(%23h)' stroke-width='4.8' stroke-linejoin='round' stroke-linecap='round'/><path d='M16 25.5 C10.8 21 5 16.4 5 10.4 C5 6.3 8 3.9 10.9 3.9 C13.2 3.9 15 5.4 16 7.6 C17 5.4 18.8 3.9 21.1 3.9 C24 3.9 27 6.3 27 10.4 C27 16.4 21.2 21 16 25.5 Z' fill='none' stroke='rgba(255,255,255,.5)' stroke-width='1.1' stroke-linejoin='round'/><circle cx='10.6' cy='8.2' r='1.6' fill='rgba(255,255,255,.9)'/><rect x='13.9' y='26.2' width='4.2' height='5.6' rx='1.8' fill='url(%23h)'/><rect x='14.9' y='27' width='1' height='4' rx='.5' fill='rgba(255,255,255,.55)'/><circle cx='16' cy='36.4' r='4' fill='none' stroke='url(%23h)' stroke-width='2.8'/></svg>") center/contain no-repeat;
  filter:drop-shadow(0 2px 1.5px rgba(64,52,43,.34))}
/* the ring colour tints every metal part */
.pk-charm.kr-gold .charm-heart{filter:drop-shadow(0 2px 1.5px rgba(64,52,43,.34)) sepia(.8) saturate(3) hue-rotate(4deg)}
.pk-charm.kr-noir .charm-heart{filter:drop-shadow(0 2px 1.5px rgba(64,52,43,.34)) brightness(.42)}
.pk-charm.kr-rose .charm-heart{filter:drop-shadow(0 2px 1.5px rgba(64,52,43,.34)) sepia(.6) saturate(2.4) hue-rotate(-26deg) brightness(1.06)}
/* keychain editor: a live, standalone charm preview + its controls */
.keychain-preview{display:flex;justify-content:center;align-items:flex-start;height:clamp(190px,34vh,240px);margin:6px 0 2px;padding:18px 0 8px;
  background:linear-gradient(#efe6d4,#e6d9bf);border-radius:14px;overflow:hidden}
.kcfit{transform-origin:50% 0;will-change:transform} /* JS scales this to keep the whole charm inside the box */
.keychain-preview .pk-charm{display:flex;flex-direction:column;align-items:center;position:relative;width:auto;transition:none}
/* plushie picker in the wall editor's keychain section */
.kcpick{display:flex;gap:6px;flex-wrap:wrap;margin:2px 0 8px}
.kcthumb{width:44px;height:44px;border-radius:12px;border:2px solid var(--line);background:#fff;padding:2px;cursor:pointer;overflow:hidden;display:flex;align-items:center;justify-content:center;font-size:22px;flex:none}
.kcthumb img{width:100%;height:100%;object-fit:contain;pointer-events:none}
.kcthumb.on{border-color:var(--coral-d)}
.krcolor{width:34px;height:34px;border-radius:11px;border:0;cursor:pointer;padding:0;
  box-shadow:inset 0 0 0 1px rgba(64,52,43,.14),inset 0 1px 0 rgba(255,255,255,.4);transition:transform .15s var(--ease-out),box-shadow .15s}
.krcolor:hover{transform:scale(1.08)}
.krcolor.active{box-shadow:0 0 0 2px var(--paper),0 0 0 4px var(--coral-d),inset 0 0 0 1px rgba(64,52,43,.14)}
.krc-silver{background:linear-gradient(135deg,#f1f3f6,#c3c9d2 55%,#969da9)}
.krc-gold{background:linear-gradient(135deg,#f7e6b0,#d9b45e 55%,#b08c34)}
.krc-noir{background:linear-gradient(135deg,#5a5d64,#33363d 55%,#1c1e24)}
.krc-rose{background:linear-gradient(135deg,#f6d6cf,#e3a89b 55%,#c98074)}
.at-keychain .wallpack:focus-visible .pk-charm{transform:rotate(-3.5deg)} /* hover swing is physics now */
.wallpack .pk-charm.swing{animation:pkswing 1.5s ease-in-out}
@media(prefers-reduced-motion:reduce){.wallpack .pk-charm.swing{animation:none}}
/* ── acrylic case mode: the cutout run through the #cshell SVG filter (molded clear
   rim + sheen) hanging from a gold heart clasp, rendered live, nothing stored ── */
.at-case .packcard,.at-case .peg-tip{display:none}
.at-case .wallpack{height:182px;padding-top:0;overflow:visible}
.at-case .peg{z-index:8} /* hook in front, it holds the case's clasp loop */
.case-shell{display:none}
.at-case .case-shell{display:flex;flex-direction:column;align-items:center;width:100%;position:relative;z-index:1;
  transform-origin:50% 36px; /* the clasp loop on the hook, the pendulum fulcrum */
  transform:rotate(-1.6deg); /* acrylic-keychain-gpt.md: nothing hangs perfectly flat */
  transition:transform .26s var(--ease-out)}
/* the acrylic clasp tints with the ring colour (shared with the keychain), so the acrylic
   editor's "Clasp" picker is meaningful. Default gold SVG, retinted per kr-*. */
.case-shell.kr-silver .cs-clasp{filter:saturate(.06) brightness(1.14) drop-shadow(0 2px 1.5px rgba(64,52,43,.34))}
.case-shell.kr-noir .cs-clasp{filter:brightness(.42) drop-shadow(0 2px 1.5px rgba(64,52,43,.34))}
.case-shell.kr-rose .cs-clasp{filter:sepia(.6) saturate(2.4) hue-rotate(-26deg) brightness(1.06) drop-shadow(0 2px 1.5px rgba(64,52,43,.34))}
/* per-plushie keychain + acrylic editor previews on the plushie page */
.kcase-prev{display:flex;justify-content:center;align-items:flex-start;height:clamp(190px,34vh,240px);margin:6px 0 2px;padding:18px 0 8px}
.kced .kcrow,.acred .kcrow{display:flex;align-items:center;gap:10px;margin:8px 0 0;flex-wrap:wrap}
.kced .kcrow .pkoptlbl,.acred .kcrow .pkoptlbl{margin:0;min-width:44px}
.cs-clasp{margin-top:25px;width:30px;height:46px;flex:none;position:relative;z-index:2;
  background:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 46'><defs><linearGradient id='g' x1='0' x2='1' y1='0' y2='1'><stop offset='0' stop-color='%23f7e6b0'/><stop offset='.5' stop-color='%23d9b45e'/><stop offset='1' stop-color='%23a1772a'/></linearGradient></defs><path d='M15 10 C15 5.5 11.5 3 8.5 5 C5.5 7 5.5 11.5 8.5 14.5 L15 21 L21.5 14.5 C24.5 11.5 24.5 7 21.5 5 C18.5 3 15 5.5 15 10 Z' fill='none' stroke='url(%23g)' stroke-width='3.4' stroke-linejoin='round'/><rect x='12.4' y='21.5' width='5.2' height='7' rx='2.4' fill='url(%23g)' stroke='%238a6420' stroke-width='.8'/><circle cx='15' cy='36.5' r='7' fill='none' stroke='url(%23g)' stroke-width='3.2'/></svg>") center/contain no-repeat;
  filter:drop-shadow(0 2px 1.5px rgba(64,52,43,.34))}
.cs-cut{margin-top:-12px;width:auto;height:auto;max-width:124px;max-height:126px;object-fit:contain;position:relative;
  /* raw (uncut) photos become rounded acrylic photo blocks; true cutouts already have
     transparent corners, so the radius changes nothing for them */
  border-radius:14px;
  /* acrylic hangs OFF the wall, the doc's two-layer shadow: dark+sharp near, soft far */
  filter:url(#cshell) drop-shadow(0 3px 5px rgba(40,32,26,.22)) drop-shadow(0 14px 18px rgba(64,52,43,.24))}
.cs-emoji{font-size:92px;line-height:1}
/* an uncut (whole) photo can't be a die-cut charm, in keychain mode it falls back to
   its acrylic photo block, hanging from the same hook as everyone else */
.at-keychain .wallpack.uncut .pk-charm{display:none}
.at-keychain .wallpack.uncut .case-shell{display:flex;flex-direction:column;align-items:center;width:100%;position:relative;z-index:1;
  transform-origin:50% 36px;transition:transform .26s var(--ease-out)}
.at-keychain .wallpack.uncut{height:182px;padding-top:0;overflow:visible}
.at-case .wallpack:focus-visible .case-shell{transform:rotate(-3.5deg)} /* hover swing is physics now */
.wallpack .case-shell.swing{animation:pkswing 1.5s ease-in-out}
@media(prefers-reduced-motion:reduce){.wallpack .case-shell.swing{animation:none}}
/* ===== Vitrine wall: cubby boxes on a 12-col grid (port of artifacts/vitrine-wall.html).
   Cells carry desktop rect vars (--c1..--r2) AND mobile rect vars (--mc1..--mr2); the
   media query flips which set the grid uses. Six colourways; "crossing" turns the whole
   wall into AC-style wooden cubbies with five toon palettes (data-pal). ===== */
.pvit{position:relative;margin-top:14px}
.pvgrid{position:relative;display:grid;grid-template-columns:repeat(12,1fr);grid-auto-rows:var(--rh,120px);
  gap:8px;padding:10px;border-radius:20px;touch-action:pan-y;
  background:var(--vf,#e7e4dd);box-shadow:0 24px 50px rgba(64,52,43,.16), inset 0 1px 0 #fff, inset 0 0 0 1px var(--vl,#cdc9c0)}
.vc{position:relative;grid-column:var(--c1)/var(--c2);grid-row:var(--r1)/var(--r2)}
@media(max-width:719px){
  .pvgrid{grid-auto-rows:var(--rhm,96px);gap:6px;padding:7px}
  .vc{grid-column:var(--mc1)/var(--mc2);grid-row:var(--mr1)/var(--mr2)}
}
/* colourways (prototype values) */
.pvit[data-vth=ivory]{--vf:#e7e4dd;--vl:#cdc9c0;--vb:#fffdf7;--vp:#e3ded3;--vled:#fff3d8}
.pvit[data-vth=blush]{--vf:#f2dad9;--vl:#dcb3b1;--vb:#f7cbc7;--vp:#f5e0df;--vled:#ffd2c8}
.pvit[data-vth=nude]{--vf:#e8dac9;--vl:#d2bda4;--vb:#f2e2cf;--vp:#ecdfce;--vled:#ffe6bf}
.pvit[data-vth=slate]{--vf:#d9dde1;--vl:#bcc2c8;--vb:#eef2f6;--vp:#e0e5ea;--vled:#d9e9ff}
.pvit[data-vth=sage]{--vf:#dce3d7;--vl:#bfc9b8;--vb:#ebf1e7;--vp:#e1e8dc;--vled:#e4f2d6}
.pvit[data-vth=butter]{--vf:#f2e8c9;--vl:#dccf9f;--vb:#faf1d6;--vp:#f0e6c4;--vled:#fff0b8}
.pvit[data-vth=lavender]{--vf:#e4ddef;--vl:#c8bcdd;--vb:#f0eaf9;--vp:#e6dff1;--vled:#e9dcff}
.pvit[data-vth=peach]{--vf:#f6e0d2;--vl:#e3bda6;--vb:#fce9dc;--vp:#f4dfd0;--vled:#ffdfc2}
.pvit[data-vth=mist]{--vf:#dde5e4;--vl:#bccbc9;--vb:#ecf3f2;--vp:#e2eae9;--vled:#d8f2ee}
/* realistic niches: lit back panel + soft bevel + strip light; panels: lacquered solids */
.vc-n{border-radius:10px;overflow:hidden;
  background:radial-gradient(120% 90% at 50% 0%, rgba(255,255,255,.85), rgba(255,255,255,.25) 46%, transparent 78%), var(--vb);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.8), inset 0 0 0 1px rgba(120,110,90,.18), inset 0 -2px 3px -1px rgba(90,80,60,.14)}
.vc-led::before{content:"";position:absolute;z-index:1;left:6%;right:6%;top:2px;height:4px;border-radius:3px;
  background:var(--vled);box-shadow:0 2px 12px 2px var(--vled);pointer-events:none}
.vc-p{border-radius:10px;
  background:repeating-linear-gradient(90deg, rgba(255,255,255,.28) 0 1px, transparent 1px 3px),
    linear-gradient(160deg, color-mix(in srgb, var(--vp) 84%, #fff), var(--vp) 62%, color-mix(in srgb, var(--vp) 82%, #000));
  box-shadow:0 7px 15px rgba(60,50,35,.30), inset 0 1.5px 0 rgba(255,255,255,.9), inset 0 -3px 6px -2px rgba(90,78,58,.20)}
.vc-arch{border-radius:48% 48% 10px 10px / 30% 30% 10px 10px}
.vc-hit{position:absolute;inset:0;z-index:2;display:grid;place-items:center;touch-action:pan-y;
  -webkit-tap-highlight-color:transparent;text-decoration:none} /* pan-y: a filled cubby must not trap page scroll (drags arm via press-and-hold) */
.vc-plush{max-width:84%;max-height:80%;pointer-events:none;user-select:none;-webkit-user-select:none;-webkit-touch-callout:none;
  filter:drop-shadow(0 4px 5px rgba(60,50,35,.35))}
.vc-plush.vc-emoji{font-size:46px;line-height:1}
.vc-n.over{outline:3px solid var(--gold,#e8b84b);outline-offset:-3px;z-index:3}
@media(hover:hover) and (prefers-reduced-motion:no-preference){
  .vc-hit:hover .vc-plush{transform:translateY(-3px)}
}
/* --- crossing: toon wooden cubbies (toon mode owns the style; realism layers off).
   --tf* frame wood · --tc* cubby interior · --tpa/b/c the candy-lined alt cubbies --- */
.pvit.toon{--tf1:#8a5a33;--tf2:#7c4f2e;--tf3:#6b4224;--tc1:#bd8358;--tc2:#9c6539;--tc3:#7a4a26;--tglow:rgba(255,220,170,.28);
  --tpa:#ffe9f2;--tpb:#ffd9e8;--tpc:#f0b8cd}
.pvit.toon[data-pal=sakura]{--tf1:#d98a9c;--tf2:#c4738a;--tf3:#a95c74;--tc1:#f4bcc8;--tc2:#e394a8;--tc3:#cd7892;--tglow:rgba(255,235,240,.35);
  --tpa:#fff9ef;--tpb:#fdeed6;--tpc:#ecd3ae}
.pvit.toon[data-pal=ocean]{--tf1:#6a94b8;--tf2:#527a9e;--tf3:#40648a;--tc1:#a8cbe0;--tc2:#82aacb;--tc3:#6490b4;--tglow:rgba(225,244,255,.35);
  --tpa:#f2fbf8;--tpb:#daf3ea;--tpc:#b2dccf}
.pvit.toon[data-pal=matcha]{--tf1:#8aa860;--tf2:#75904c;--tf3:#5f7a3c;--tc1:#bcd698;--tc2:#a3c17c;--tc3:#87a960;--tglow:rgba(244,255,225,.35)}
.pvit.toon[data-pal=honey]{--tf1:#c99a4a;--tf2:#b38436;--tf3:#96692a;--tc1:#f0cd8a;--tc2:#e0b268;--tc3:#c99a4e;--tglow:rgba(255,240,205,.4);
  --tpa:#fffdf6;--tpb:#fdf3dd;--tpc:#f0dcb0}
.pvit.toon[data-pal=berry]{--tf1:#9b7bb8;--tf2:#8a68a8;--tf3:#755590;--tc1:#cbb3e0;--tc2:#b295cf;--tc3:#9678b4;--tglow:rgba(240,230,255,.35);
  --tpa:#fdeff6;--tpb:#f8d9ea;--tpc:#e5b4cf}
.pvit.toon[data-pal=vanilla]{--tf1:#cfbfa8;--tf2:#bfae94;--tf3:#a8957c;--tc1:#f2e7d4;--tc2:#e4d4bb;--tc3:#cbb99d;--tglow:rgba(255,250,235,.45)}
.pvit.toon[data-pal=night]{--tf1:#4a5578;--tf2:#3d4766;--tf3:#303852;--tc1:#7482a8;--tc2:#5d6b92;--tc3:#49577e;--tglow:rgba(200,215,255,.25);
  --tpa:#e8e6f8;--tpb:#d5d2ef;--tpc:#b0abd8}
.pvit.toon .pvgrid{border:3px solid #4a2f17;border-radius:22px;
  background:
    radial-gradient(130% 90% at 24% 0%, var(--tglow), transparent 55%),
    repeating-linear-gradient(0deg, rgba(58,32,14,.16) 0 2px, transparent 2px 30px),
    repeating-linear-gradient(90deg, rgba(58,32,14,.10) 0 2px, transparent 2px 90px),
    linear-gradient(180deg,var(--tf1) 0%,var(--tf2) 55%,var(--tf3) 100%);
  box-shadow:inset 0 4px 0 rgba(255,220,170,.30), inset 0 -10px 0 rgba(50,28,12,.35),
             0 10px 0 rgba(40,24,12,.35), 0 24px 44px rgba(64,52,43,.4)}
.pvit.toon .vc-n{border:3px solid #4a2f17;border-radius:16px;
  background:
    radial-gradient(75% 55% at 50% 20%, rgba(255,224,178,.30), transparent 70%),
    url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='90' height='90' viewBox='0 0 90 90'><circle cx='16' cy='20' r='1.3' fill='%23e8c29a' opacity='.5'/><circle cx='70' cy='12' r='1.1' fill='%23e8c29a' opacity='.4'/><circle cx='44' cy='72' r='1.2' fill='%23e8c29a' opacity='.45'/><path d='M64 44 l1.6 3.3 3.3 1.6 -3.3 1.6 -1.6 3.3 -1.6-3.3 -3.3-1.6 3.3-1.6 z' fill='%23eec9a0' opacity='.5'/></svg>") 0 0/90px 90px,
    radial-gradient(120% 105% at 50% 26%, var(--tc1) 0%, var(--tc2) 52%, var(--tc3) 100%);
  box-shadow:inset 0 6px 12px rgba(50,28,12,.42), inset 0 -3px 0 rgba(255,214,164,.14),
             0 5px 0 rgba(50,28,12,.5), 0 12px 18px rgba(30,17,8,.35)}
.pvit.toon .vc:nth-child(3n+1) .vc-n::after{content:"";position:absolute;z-index:1;right:6px;top:6px;width:20px;height:20px;pointer-events:none;
  background:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M12 1.5 L14.6 9.4 L22.5 12 L14.6 14.6 L12 22.5 L9.4 14.6 L1.5 12 L9.4 9.4 Z' fill='%23ffd76a' stroke='%234a2f17' stroke-width='1.7' stroke-linejoin='round'/></svg>") center/contain no-repeat;
  filter:drop-shadow(0 2px 0 rgba(50,28,12,.4))}
.pvit.toon .vc-led::before{display:none}
.pvit.toon .vc-p{border:3px solid #4a2f17;border-radius:16px;
  background:
    url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='46' height='46' viewBox='0 0 46 46'><circle cx='9' cy='11' r='1.4' fill='%23ffffff' opacity='.7'/><circle cx='37' cy='7' r='1.2' fill='%23ffffff' opacity='.7'/><circle cx='24' cy='38' r='1.3' fill='%23ffffff' opacity='.7'/><path d='M31 24 l1.8 3.7 3.7 1.8 -3.7 1.8 -1.8 3.7 -1.8-3.7 -3.7-1.8 3.7-1.8 z' fill='%23ffffff' opacity='.55'/></svg>") 0 0/46px 46px,
    linear-gradient(180deg,var(--tpa,#ffe9f2),var(--tpb,#ffd9e8) 55%,var(--tpc,#f0b8cd));
  box-shadow:inset 0 4px 0 rgba(255,255,255,.55), inset 0 -6px 0 rgba(74,47,23,.14),
             0 5px 0 rgba(50,28,12,.5), 0 12px 16px rgba(30,17,8,.32)}
/* candy-lined ALT cubbies: the old pink panels, but open, a real box a plushie can sit in */
.pvit.toon .vc-n.vc-alt{
  background:
    url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='46' height='46' viewBox='0 0 46 46'><circle cx='9' cy='11' r='1.4' fill='%23ffffff' opacity='.7'/><circle cx='37' cy='7' r='1.2' fill='%23ffffff' opacity='.7'/><circle cx='24' cy='38' r='1.3' fill='%23ffffff' opacity='.7'/><path d='M31 24 l1.8 3.7 3.7 1.8 -3.7 1.8 -1.8 3.7 -1.8-3.7 -3.7-1.8 3.7-1.8 z' fill='%23ffffff' opacity='.55'/></svg>") 0 0/46px 46px,
    radial-gradient(120% 105% at 50% 26%, var(--tpa,#ffe9f2) 0%, var(--tpb,#ffd9e8) 52%, var(--tpc,#f0b8cd) 100%);
  box-shadow:inset 0 6px 12px rgba(50,28,12,.28), inset 0 -3px 0 rgba(255,255,255,.30),
             0 5px 0 rgba(50,28,12,.5), 0 12px 18px rgba(30,17,8,.35)}
/* realism themes: alt cubbies get a soft tinted lining (same panel colour, still usable) */
.vc-n.vc-alt{background:radial-gradient(120% 90% at 50% 0%, rgba(255,255,255,.85), rgba(255,255,255,.25) 46%, transparent 78%), color-mix(in srgb, var(--vp,#e3ded3) 72%, #fff)}
.pvit.toon .vc-arch{border-radius:46% 46% 16px 16px / 26% 26% 16px 16px}
.pvit.toon .vc-plush{filter:drop-shadow(0 3px 0 rgba(50,28,12,.35))}
.pvit.toon .vc-n.over{outline-color:#ffd76a}
@media(hover:hover) and (prefers-reduced-motion:no-preference){
  .pvit.toon .vc-hit:hover .vc-plush{transform:rotate(-3deg)}
}
/* --- owner strip (unplaced plushies) + drag ghost + style bar --- */
.pvstrip{display:flex;align-items:center;gap:10px;margin-top:10px;padding:8px 10px;border-radius:14px;
  background:rgba(120,110,90,.10);box-shadow:inset 0 0 0 1px rgba(120,110,90,.18);
  overflow-x:auto;-webkit-overflow-scrolling:touch}
.pvstrip.over{box-shadow:inset 0 0 0 2px var(--gold,#e8b84b)}
.pvs-hint{flex:0 0 auto;color:#8f857a;font:500 11px system-ui}
.pvs-item{flex:0 0 auto;width:52px;height:52px;display:grid;place-items:center;border-radius:12px;
  background:#fffdf7;box-shadow:0 2px 5px rgba(64,52,43,.18), inset 0 0 0 1px rgba(120,110,90,.16);
  touch-action:pan-x;-webkit-tap-highlight-color:transparent} /* pan-x: the strip must stay swipe-scrollable on touch */
.pvs-item img{max-width:86%;max-height:86%;pointer-events:none;user-select:none;-webkit-user-select:none;-webkit-touch-callout:none}
.pvs-emoji{font-size:30px;line-height:1}
/* storage friends ride along in the strip, solid border + 🧺 badge says "not out yet";
   dragging one into a box places AND displays them */
.pvs-item{position:relative}
.pvs-item.pvs-stored{background:#fbf6ec;box-shadow:0 2px 5px rgba(64,52,43,.18), inset 0 0 0 2px rgba(64,52,43,.24)}
.pvs-tag{position:absolute;right:-4px;bottom:-4px;font-size:14px;line-height:1;filter:drop-shadow(0 1px 1px rgba(64,52,43,.3))}
.pvghost{position:fixed;z-index:100;width:72px;height:72px;object-fit:contain;pointer-events:none;
  transform:translate(-50%,-50%);filter:drop-shadow(0 10px 14px rgba(0,0,0,.45))}
.pvbar{margin:0 0 8px}
.pvbar>summary{display:inline-block;list-style:none;cursor:pointer}
.pvbar>summary::-webkit-details-marker{display:none}
.pvbar-body{display:grid;grid-template-columns:auto 1fr;gap:6px 10px;align-items:center;max-width:340px;
  margin-top:8px;padding:10px 12px;border-radius:12px;background:rgba(120,110,90,.10);
  box-shadow:inset 0 0 0 1px rgba(120,110,90,.18)}
.pvbar-body .lbl{margin:0}
.pvbar-body select{width:100%;padding:6px 8px;border-radius:8px;border:1px solid rgba(120,110,90,.3);background:#fffdf7;font:600 12px system-ui}
.pv-palwrap{display:contents}
.pv-palwrap[hidden]{display:none} /* display:contents defeats the hidden attribute, restore it */

/* ===== Shelf view: plushies on cushions under glass cases, standing on wooden boards.
   PERSPECTIVE CONTRACT: --sv-squash is the foreshortening of EVERY horizontal surface here
   (board, cushion top, glass lid), so they can never disagree about the camera angle.
   LIGHT CONTRACT: one direction drives every highlight/shadow, baked from angle 278 /
   height 16, a low raking light from the left. Unlike the dark mock-up, this sits on the
   app's cream paper, so the glass reads through DARK edges rather than bright speculars. */
.shelfrows{--sv-squash:.085;--sv-taper:7%;
  --sv-sheen:98deg;--sv-lit-t:.139;--sv-lit-b:0;--sv-lit-l:.99;--sv-lit-r:0;--sv-elev:.178;--sv-li:1;
  --sv-sx:22.51;--sv-sy:3.16;
  --sv-cdepth:30px;--sv-gh:118px;--sv-pfh:17px;--sv-cush-top:8px;--sv-sit:13px;--sv-cushion:#efdcc2;
  --sv-row:182px;
  /* stated the way the demo states them: a board --sv-depth deep renders depth*squash
     tall, and --sv-floor is how much of it stays in FRONT of the cases */
  --sv-depth:188px;--sv-floor:3px;
  --sv-board:calc(var(--sv-depth) * var(--sv-squash));   /* 188 * .085 = 16px */
  --sv-seat:calc(var(--sv-board) - var(--sv-floor));     /* 16 - 3 = 13px */
  --sv-base:12px;    /* cushion bottom above the card's bottom edge */
  --sv-pad:6px;      /* the container's own padding-top, which the boards must clear */
  display:grid;grid-template-columns:repeat(auto-fill,minmax(138px,1fr));gap:0 18px;
  padding:6px 4px 0;
  /* the boards ARE the background: one band per --sv-row, pitched so every cushion lands on
     one by construction. --sv-seat pulls the band up so cases sit onto the surface. */
  /* four stops: surface back -> surface front -> edge top -> edge bottom, PLUS a bright
     back-edge catchlight and a rounded-lip shade under the front edge so the board reads
     as thick timber, not a stripe. A material class swaps colours; geometry never changes. */
  background-image:linear-gradient(to bottom,
    rgba(255,255,255,.30) 0,rgba(255,255,255,0) 2px,
    transparent calc(var(--sv-board) + 3px),rgba(255,255,255,.14) calc(var(--sv-board) + 3px),
    rgba(255,255,255,0) calc(var(--sv-board) + 5px),transparent calc(var(--sv-board) + 5px)),
    linear-gradient(to bottom,
    var(--sv-w1) 0,var(--sv-w2) var(--sv-board),
    var(--sv-w3) var(--sv-board),var(--sv-w4) calc(var(--sv-board) + 4px),
    var(--sv-wsh) calc(var(--sv-board) + 4px),transparent calc(var(--sv-board) + 16px));
  background-size:100% var(--sv-row),100% var(--sv-row);
  /* band top = where a cushion sits, pulled up by --sv-seat so the case stands ON the
     surface with --sv-seat of board behind it and the rest in front */
  background-position:0 calc(var(--sv-pad) + var(--sv-row) - var(--sv-base) - var(--sv-seat));
  background-clip:content-box}
/* ---- the cabinet ----
   Rather than darkening the whole app, the shelf sits in its own recessed case. That is
   what a display cabinet is anyway, and it gives the glass a dark ground to read against
   (white rims on cream paper are nearly invisible; on night they carry the whole effect). */
/* bottom padding clears the LAST board's front edge + its lip shadow, or the bottom shelf
   gets sliced off by the cabinet's own rounded corner */
.shelfroom{border-radius:18px;padding:12px 12px 18px;transition:background .3s}
.shelfroom.night{--sv-grgb:255,255,255;--sv-gb:.10;--sv-gs:.5;--sv-gtop:.55;--sv-name:#f4ebdf;
  --sv-brgb:255,238,214;--sv-bb:.13;   /* back wall: a warm lit panel behind each plushie */
  /* dark-walnut cabinet interior: warm top-lit gradient with a corner vignette, not a
     flat black rectangle */
  background:
    radial-gradient(140% 100% at 50% 108%,transparent 55%,rgba(0,0,0,.4) 100%),
    radial-gradient(120% 90% at 50% 0,#2b2119 0,#191310 62%,#120e0b 100%);
  box-shadow:inset 0 3px 22px rgba(0,0,0,.55),inset 0 -14px 30px rgba(0,0,0,.35),0 12px 26px rgba(64,52,43,.2)}
.shelfroom.paper{--sv-grgb:64,52,43;--sv-gb:.09;--sv-gs:.2;--sv-gtop:.7;--sv-name:var(--ink);
  /* NO back wall on paper. It exists so silhouettes don't dissolve into a near-black
     cabinet; over cream there's nothing to solve, and a shaded panel just prints a grey
     rectangle behind every friend. */
  --sv-brgb:64,52,43;--sv-bb:0;
  background:transparent}
.shelfroom.night .shelfrows{background-clip:border-box}
/* NIGHT ONLY: a warm bloom spilling from under each board's front edge, the strip light a
   real cabinet has. Its own layer so the board gradient stack above stays untouched, and
   it repeats on the same --sv-row pitch, so it lands under every shelf by construction. */
.shelfroom.night .shelfrows::before{content:"";position:absolute;inset:0;pointer-events:none;z-index:0;
  background-image:linear-gradient(to bottom,
    transparent calc(var(--sv-board) + 4px),
    rgba(255,226,178,.20) calc(var(--sv-board) + 6px),
    rgba(255,226,178,0) calc(var(--sv-board) + 32px));
  background-size:100% var(--sv-row);
  background-position:0 calc(var(--sv-pad) + var(--sv-row) - var(--sv-base) - var(--sv-seat))}

/* shelf materials, the default is walnut, in the family of the app's .wt-walnut wall */
.shelfrows,.shelfrows.sm-walnut{--sv-w1:#6f4a2c;--sv-w2:#9a6b42;--sv-w3:#5b3a20;--sv-w4:#4a2e18;--sv-wsh:rgba(35,22,10,.45)}
.shelfrows.sm-oak{--sv-w1:#a97a45;--sv-w2:#d2a469;--sv-w3:#875d2f;--sv-w4:#6d4a25;--sv-wsh:rgba(60,38,14,.4)}
.shelfrows.sm-birch{--sv-w1:#cbb392;--sv-w2:#eaddc2;--sv-w3:#ad9370;--sv-w4:#8f7757;--sv-wsh:rgba(80,60,32,.32)}
.shelfrows.sm-charcoal{--sv-w1:#35353a;--sv-w2:#55555c;--sv-w3:#26262a;--sv-w4:#1a1a1e;--sv-wsh:rgba(0,0,0,.5)}
.shelfrows.sm-marble{--sv-w1:#cfcbc4;--sv-w2:#f1efeb;--sv-w3:#aba69e;--sv-w4:#918c84;--sv-wsh:rgba(60,52,43,.32)}
.shelfmats{display:flex;gap:6px;align-items:center}
.smchip{width:24px;height:24px;padding:0;border-radius:50%;border:2px solid var(--line);cursor:pointer;
  background:linear-gradient(160deg,var(--c2) 0 52%,var(--c3) 52% 100%)}
.smchip.on{border-color:var(--coral);box-shadow:0 0 0 2px var(--paper),0 0 0 4px var(--coral)}
.smchip.sm-walnut{--c2:#9a6b42;--c3:#5b3a20}
.smchip.sm-oak{--c2:#d2a469;--c3:#875d2f}
.smchip.sm-birch{--c2:#eaddc2;--c3:#ad9370}
.smchip.sm-charcoal{--c2:#55555c;--c3:#26262a}
.smchip.sm-marble{--c2:#f1efeb;--c3:#aba69e}

.shelfcard{position:relative;z-index:1;height:var(--sv-row);display:block;text-decoration:none;color:inherit;
  -webkit-user-drag:none}   /* z-index: stay above the shelf-light bloom layer */
/* The case's BACK WALL. Without it a plushie sits against the raw cabinet gradient and the
   dark ones dissolve into it; a plane behind them gives every silhouette something to read
   against. Lit from the same --sv-sheen direction as every other surface here. */
.sc-back{position:absolute;left:0;right:0;bottom:var(--sv-pfh);height:var(--sv-gh);z-index:0;
  border-radius:6px 6px 4px 4px;
  background:linear-gradient(var(--sv-sheen),
    rgba(var(--sv-brgb),var(--sv-bb)) 0,rgba(var(--sv-brgb),calc(var(--sv-bb) * .35)) 62%,rgba(var(--sv-brgb),0) 100%)}
/* absolutely placed, never flex-shrunk, the cushion's bottom edge is the contact point
   and must line up with the board band by construction */
.scase{position:absolute;left:50%;bottom:var(--sv-base);transform:translateX(-50%);
  width:86%;height:calc(var(--sv-pfh) + var(--sv-gh))}
/* soft square cushion: square footprint, domed squishy top the plush settles into */
.sc-face{position:absolute;left:0;right:0;bottom:0;height:var(--sv-pfh);z-index:4;overflow:hidden;
  border-radius:3px 3px 7px 7px;
  background:linear-gradient(180deg,#fffdf7,var(--sv-cushion)); /* matte-ivory pedestal, not flat cream */
  box-shadow:0 3px 7px rgba(64,52,43,.34)}
.sc-face::before{content:"";position:absolute;inset:0;
  background:linear-gradient(180deg,rgba(255,255,255,.5) 0,rgba(0,0,0,.05) 34%,rgba(0,0,0,.26) 100%)}
.sc-face::after{content:"";position:absolute;inset:0;
  background:linear-gradient(var(--sv-sheen),rgba(255,255,255,.55) 0,rgba(255,255,255,0) 72%);
  opacity:calc(var(--sv-li) * (.35 + .45 * var(--sv-elev)))}
.sc-top{position:absolute;left:0;right:0;bottom:var(--sv-pfh);z-index:1;height:var(--sv-cush-top);
  background:var(--sv-cushion);border-radius:42% 42% 3px 3px / 82% 82% 10% 10%;
  box-shadow:inset 0 2px 3px rgba(255,255,255,.6)}
.sc-dimple{position:absolute;left:50%;bottom:calc(var(--sv-sit) - 5px);z-index:1;width:46%;height:9px;
  transform:translateX(-50%);
  background:radial-gradient(ellipse at 50% 50%,rgba(64,52,43,.3),transparent 72%)}
/* --sv-scale is the plushie's REAL size (from their recorded size, see sizeScale), so a
   16" Squishmallow towers over a 4" keychain instead of both filling the case. 1 when
   nobody recorded a size, which is exactly the old fixed cap. */
.sc-plush{position:absolute;left:50%;bottom:var(--sv-sit);z-index:2;transform:translateX(-50%);
  /* 100/90 not 92/82: the case is 118px of glass and the old cap left a band of dead air
     over every plushie's head. The tallest still clears the lid (13px sit + 100 < 129). */
  max-height:calc(100px * var(--sv-scale,1));max-width:calc(90% * var(--sv-scale,1));
  width:auto;height:auto;object-fit:contain;
  filter:drop-shadow(calc(var(--sv-sx) * .22px) calc(var(--sv-sy) * .22px) 4px rgba(64,52,43,.4));
  transition:transform .3s var(--ease-out)}
/* a brown shadow is invisible on a near-black cabinet, so night gets its own, or every
   friend floats a few millimetres above their cushion */
.shelfroom.night .sc-plush{filter:drop-shadow(calc(var(--sv-sx) * .22px) calc(var(--sv-sy) * .22px) 5px rgba(0,0,0,.62))}
.sc-emoji{font-size:calc(64px * var(--sv-scale,1));line-height:1}
/* an uncut (whole) photo stands in the case / vitrine box as a little framed print */
.sc-plush.framed,.vc-plush.framed{border:5px solid #fffdf9;border-bottom-width:14px;border-radius:3px;
  background:#fffdf9;box-shadow:0 4px 9px rgba(64,52,43,.35),inset 0 0 0 1px rgba(64,52,43,.1)}
/* the case. On cream paper glass reads as DARK edges plus a soft sheen, not white rims. */
.sc-glass{position:absolute;left:0;right:0;bottom:var(--sv-pfh);height:var(--sv-gh);z-index:3;
  transition:transform .45s cubic-bezier(.485,-.34,.635,1.33),opacity .45s}
.sc-front{position:absolute;inset:0;border-radius:6px 6px 4px 4px;
  /* layered acrylic (glass-case-gpt-ideas): the light-contract sheen, PLUS a narrow
     diagonal streak (position varies per case via --sv-strx) and a faint horizontal
     falloff, three gradients read as reflections on real material, one reads as tint */
  background:
    linear-gradient(105deg,transparent calc(var(--sv-strx,18%) - 12%),rgba(255,255,255,.16) var(--sv-strx,18%),transparent calc(var(--sv-strx,18%) + 10%)),
    linear-gradient(var(--sv-sheen),rgba(255,255,255,.4) 0,rgba(255,255,255,.26) 8%,rgba(255,255,255,.15) 17%,
    rgba(255,255,255,.08) 28%,rgba(255,255,255,.045) 42%,rgba(255,255,255,.03) 62%,
    rgba(255,255,255,.1) 82%,rgba(255,255,255,.26) 100%);
  /* NO backdrop blur: it fuzzed every plushie behind the glass, the sheen gradients
     alone read as acrylic while the friends inside stay pin-sharp */
  /* On PAPER the glass reads through dark edges; on NIGHT through bright speculars.
     --sv-grgb flips which, --sv-gb is the ambient edge and --sv-gs the lit-edge gain. */
  border:1px solid;
  border-top-color:rgba(var(--sv-grgb),calc(var(--sv-gb) + var(--sv-gs) * var(--sv-lit-t)));
  border-bottom-color:rgba(var(--sv-grgb),calc(var(--sv-gb) + var(--sv-gs) * .85 * var(--sv-lit-b)));
  border-left-color:rgba(var(--sv-grgb),calc(var(--sv-gb) + var(--sv-gs) * var(--sv-lit-l)));
  border-right-color:rgba(var(--sv-grgb),calc(var(--sv-gb) + var(--sv-gs) * var(--sv-lit-r)));
  /* thick-edge glow: lit side catches a soft inner wash, far side shades, 6–8mm walls */
  box-shadow:inset 0 1px 0 rgba(255,255,255,var(--sv-gtop)),
    inset 7px 0 16px rgba(255,255,255,calc(.05 * var(--sv-li))),
    inset -7px 0 16px rgba(0,0,0,.12),
    0 2px 6px rgba(35,22,10,.16)}
/* every case is subtly its own: streak position + glass height drift per position,
   the way no two acrylic boxes catch a room's light identically */
.shelfcard:nth-child(3n) .sc-front{--sv-strx:34%}
.shelfcard:nth-child(3n+1) .sc-front{--sv-strx:16%}
.shelfcard:nth-child(4n+2) .sc-front{--sv-strx:58%}
.shelfcard:nth-child(4n+1){--sv-gh:124px}
.shelfcard:nth-child(5n+3){--sv-gh:112px}
.sc-lid{position:absolute;left:0;right:0;bottom:100%;height:calc(var(--sv-cdepth) * var(--sv-squash));
  background:linear-gradient(180deg,rgba(255,255,255,.66),rgba(255,255,255,.30));
  clip-path:polygon(var(--sv-taper) 0,calc(100% - var(--sv-taper)) 0,100% 100%,0 100%);
  border-top:1px solid rgba(var(--sv-grgb),calc(var(--sv-gb) + .18))}
/* the label sits ON the cushion front, so it travels with the case when it moves.
   .09em of tracking costs ~15% of the width, which is what was ellipsing the long names,
   so a long name buys its letters back by giving up tracking and a little size. */
.sc-plate{position:absolute;left:3%;right:3%;bottom:3px;z-index:5;text-align:center;
  font-size:.55rem;font-weight:800;letter-spacing:.07em;text-transform:uppercase;
  color:#6d4f30;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;pointer-events:none}
.sc-plate.long{font-size:.48rem;letter-spacing:.015em}
.sc-rar{margin-left:4px;color:#c9962e;letter-spacing:.02em;text-shadow:0 1px 1px rgba(255,255,255,.5)}
/* museum spotlight: a warm pool from the shelf lighting above, night mode only, where
   there is darkness for it to read against */
.shelfroom.night .scase::before{content:"";position:absolute;left:-12%;right:-12%;top:-16px;height:74%;
  z-index:0;pointer-events:none;
  background:radial-gradient(62% 58% at 50% 0%,rgba(255,238,204,.15),transparent 72%)}

/* an empty pitch = a real, empty glass case with a + button waiting to be filled */
.shelfcard.empty{cursor:pointer}
.shelfcard.empty .sc-glass{opacity:.72}
.sc-add{position:absolute;left:50%;top:42%;transform:translate(-50%,-50%);z-index:6;
  width:40px;height:40px;border-radius:50%;border:none;cursor:pointer;
  font:700 24px/1 system-ui;color:var(--sv-name);
  background:rgba(var(--sv-grgb),.15);box-shadow:inset 0 0 0 1px rgba(var(--sv-grgb),.3);
  transition:background .15s,transform .15s}
.sc-add:hover{background:rgba(var(--sv-grgb),.28);transform:translate(-50%,-50%) scale(1.08)}
.shelfrows.reorderable .shelfcard.empty .sc-add{opacity:.4}   /* in reorder mode the card is a handle */
/* remove-this-case button, always available on an empty case (no need for reorder mode) */
.sc-del{position:absolute;top:6px;right:9px;z-index:7;width:22px;height:22px;border-radius:50%;
  border:none;cursor:pointer;font:700 15px/1 system-ui;color:var(--sv-name);
  display:flex;align-items:center;justify-content:center;
  background:rgba(var(--sv-grgb),.16);box-shadow:inset 0 0 0 1px rgba(var(--sv-grgb),.3);
  transition:background .15s,color .15s,opacity .15s}
.sc-del:hover{background:var(--coral);color:#fff;box-shadow:none}
/* parked in the corner of a dark cabinet, a always-on × reads as "close the shelf". Hide
   it until the case is hovered — but ONLY where hover exists, or touch loses the control. */
@media(hover:hover){
  .sc-del{opacity:0}
  .shelfcard.empty:hover .sc-del,.sc-del:focus-visible{opacity:1}
}

/* pick-a-plushie sheet, opened from an empty case's + button */
.shelfpick{position:fixed;inset:0;z-index:60;display:flex;align-items:flex-end;justify-content:center;
  background:rgba(20,15,10,.5)}
.shelfpick[hidden]{display:none}
.sp-sheet{background:var(--card);border-radius:18px 18px 0 0;width:min(560px,100%);max-height:76vh;
  overflow:auto;padding:16px 16px 26px;box-shadow:0 -8px 30px rgba(64,52,43,.28)}
.sp-head{display:flex;align-items:center;justify-content:space-between;font-weight:800;color:var(--ink);margin-bottom:12px}
.sp-head button{background:none;border:none;font-size:22px;line-height:1;cursor:pointer;color:var(--ink2)}
.sp-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(94px,1fr));gap:10px}
.sp-item{display:flex;flex-direction:column;align-items:center;gap:6px;padding:9px 4px;
  border:1px solid var(--line);border-radius:12px;background:var(--paper);cursor:pointer;
  font-size:.72rem;font-weight:700;color:var(--ink)}
.sp-item img{width:58px;height:58px;object-fit:contain}
.sp-item span{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.sp-item:hover{border-color:var(--coral)}
.sp-empty{grid-column:1/-1;text-align:center;color:var(--ink2);padding:22px 8px;font-size:.9rem;line-height:1.5}
/* open the case on hover, same gesture as the mock-up, and the whole case leans in a
   touch (scale + deeper ground shadow) so hovering feels like picking it up */
.scase{transition:transform .3s var(--ease-out)}
/* :focus-visible gets the SAME opening as :hover — the wall already pairs them this way,
   and without it a keyboard user can never see into a case. */
.shelfcard:hover .scase,.shelfcard:focus-visible .scase{transform:translateX(-50%) scale(1.025)}
.shelfcard:hover .sc-face{box-shadow:0 6px 13px rgba(64,52,43,.42)}
.shelfcard:hover .sc-glass,.shelfcard:focus-visible .sc-glass{transform:translateY(-116%);opacity:0}
.shelfcard:hover .sc-plush,.shelfcard:focus-visible .sc-plush{transform:translateX(-50%) scale(1.05)}
.shelfcard:focus-visible{outline:none}
.shelfcard:focus-visible .scase{outline:3px solid var(--coral-d);outline-offset:5px;border-radius:10px}
/* touch has no hover, so the case never opened on a phone: nudge the glass on press so a
   tap still feels like lifting the lid before the plushie's card takes over */
@media(hover:none){
  .shelfcard:active .sc-glass{transform:translateY(-14%);opacity:.5}
  .shelfcard:active .scase{transform:translateX(-50%) scale(1.02)}
}
.shelfrows.reorderable .shelfcard:hover .scase{transform:translateX(-50%)}
.shelfrows.reorderable{touch-action:none}
.shelfrows.reorderable .shelfcard{cursor:grab;-webkit-user-select:none;user-select:none}
.shelfrows.reorderable .shelfcard *{pointer-events:none}   /* the card is the drag handle */
.shelfrows.reorderable .shelfcard:hover .sc-glass{transform:none;opacity:1}
.shelfcard.dragging{opacity:.4;pointer-events:none}
@media(prefers-reduced-motion:reduce){.sc-glass,.sc-plush{transition:none}}
/* strap fabric colour presets (set --oc) */
.oc-white{--oc:#f2efe8}.oc-cream{--oc:#efe1c2}.oc-black{--oc:#4a4640}.oc-pink{--oc:#f4b8cc}
.oc-mint{--oc:#b7ddc6}.oc-sky{--oc:#aecbe6}.oc-coral{--oc:#f0a48a}
/* strap colour swatches, the chip IS the fabric colour (no dot-in-a-pill), one ring when picked */
.oc-sw{width:38px;height:38px;padding:0;border:0;border-radius:11px;background:var(--oc,#efe1c2);flex:none;
  box-shadow:inset 0 0 0 1px rgba(64,52,43,.14),inset 0 1px 0 rgba(255,255,255,.4);transition:transform .15s var(--ease-out),box-shadow .15s}
.oc-sw:hover{transform:scale(1.08);border:0;background:var(--oc)}
.oc-sw.active,.oc-sw[aria-pressed=true]{border:0;background:var(--oc);
  box-shadow:0 0 0 2px var(--paper),0 0 0 4px var(--coral-d),inset 0 0 0 1px rgba(64,52,43,.14)}
/* back-panel designs, each sets the vars the wall + swatch read (woods, colours, materials, botanical) */
.wt-birch{--panel1:#f6efe0;--panel2:#eee4cf;--groove:rgba(122,96,60,.30);--gap:#71583f}
.wt-oak{--panel1:#e9d2a9;--panel2:#dcbf92;--groove:rgba(92,62,30,.42);--gap:#4a2f16}
.wt-walnut{--panel1:#7c563a;--panel2:#684125;--groove:rgba(24,14,6,.55);--gap:#1d0e04}
.wt-honey{--panel1:#f1daa6;--panel2:#e7c67f;--groove:rgba(120,78,26,.42);--gap:#5c3d15}
.wt-cream{--panel1:#faf4e8;--panel2:#f1e8d5;--groove:rgba(64,52,43,.2);--gap:#8a7a64}
.wt-sage{--panel1:#dce6d2;--panel2:#cad9b9;--groove:rgba(70,92,52,.32);--gap:#4c5c38}
.wt-blush{--panel1:#f7dee2;--panel2:#efccd3;--groove:rgba(150,80,92,.28);--gap:#7e4a55}
.wt-sky{--panel1:#d7e7f3;--panel2:#c3ddef;--groove:rgba(52,88,120,.3);--gap:#3c5872}
.wt-lilac{--panel1:#e6ddf2;--panel2:#d8cbea;--groove:rgba(96,72,132,.3);--gap:#584672}
.wt-charcoal{--panel1:#48443f;--panel2:#3a3732;--groove:rgba(10,8,6,.55);--gap:#14110d}
.wt-cork{--panel1:#dcbc95;--panel2:#d0aa7c;--groove:rgba(110,74,38,.3);--gap:#5c3e20;--grain:radial-gradient(rgba(120,84,44,.22) 1px,transparent 1.6px) 0 0/8px 8px,radial-gradient(rgba(150,110,66,.15) 1px,transparent 1.6px) 4px 5px/11px 11px}
/* drag a pack along the pegs to reorder, same lift/wiggle mechanic as the icon grid */
.wall.reordering{touch-action:none}
.wall.reordering .wallpack{touch-action:none}
.wallpack.dragging{opacity:.22}
/* NO pack wiggle while .reordering: every pack animating at once for the duration of a
   phone drag is the "flashing" users feel. The ghost + hot-cell outline already say
   what's happening. Wiggle stays in .editing only, a deliberate, static mode. */
.wall-ghost{position:fixed;z-index:999;margin:0;padding-top:18px;pointer-events:none;transform:translate(-50%,-52%) scale(1.05);opacity:.97}
/* drop-to-storage bar: invisible until a wall drag is live, then slides up from the
   bottom edge, drop a pack on it to move that friend off the display */
.walldrop{position:fixed;left:10px;right:10px;bottom:calc(10px + env(safe-area-inset-bottom));transform:translateY(150%);z-index:220;
  display:flex;align-items:center;justify-content:center;min-height:64px;text-align:center;
  font-family:var(--body);font-weight:800;font-size:1.02rem;color:var(--ink);
  background:var(--card);border:3px dashed var(--line);border-radius:22px;padding:10px 18px;
  box-shadow:0 10px 26px -8px rgba(64,52,43,.4);pointer-events:none;opacity:0;
  transition:transform .2s var(--ease-out),opacity .2s var(--ease-out),border-color .15s,background .15s}
body.walldragging .walldrop{transform:translateY(0);opacity:1;pointer-events:auto}
.walldrop.hot{border-color:var(--coral-d);background:#fdeee9;color:var(--coral-d);transform:translateY(0) scale(1.02)}
@media(prefers-reduced-motion:reduce){.walldrop{transition:opacity .2s}}
@media(prefers-reduced-motion:reduce){.wallpack .packcard{transition:none}}
/* Wall / Grid view toggle */
.homehead{display:flex;align-items:center;justify-content:space-between;gap:10px 12px;flex-wrap:wrap;margin:0 0 10px}
/* the wall-design picker + Edit button dock into the header row (one row of chrome,
   not three); hidden in storage view via [data-homeview] */
.homehead .displaytop{margin:0;max-width:none;flex:none}
.homehead .displaytop .walldesign{margin:0}
.displaytop[hidden]{display:none} /* display:flex above would otherwise defeat the hidden attribute */
/* footer shortcuts: three equal pills on one row at every width */
.footlinks{display:flex;gap:10px;max-width:560px;margin:14px auto 16px}
.footlinks .btn{flex:1 1 0;white-space:nowrap;padding:12px 8px;font-size:.92rem;text-align:center}
/* mobile: slim the header controls so view toggle + wall design + Edit share one row */
@media(max-width:560px){
  .hvbtn{font-size:.8rem;padding:7px 11px;min-height:32px}
  .homehead .walldesign>summary{padding:7px 11px;font-size:.85rem;min-height:44px}
  /* glass-case controls (mat chips + Case/Night/Reorder) can't fit one row, wrap, don't overflow */
  .homehead .displaytop{flex:1 1 100%;flex-wrap:wrap;justify-content:flex-start}
}
.homeactions{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.homeview{display:inline-flex;background:var(--paper);border:1px solid rgba(64,52,43,.14);border-radius:999px;padding:3px;box-shadow:inset 0 1px 2px rgba(64,52,43,.06)}
.hvbtn{border:0;background:transparent;font-family:var(--body);font-weight:800;font-size:.86rem;color:var(--ink);
  padding:7px 14px;min-height:34px;border-radius:999px;cursor:pointer;-webkit-tap-highlight-color:transparent;
  transition:background .16s var(--ease-out),color .16s var(--ease-out),transform .12s var(--ease-out)}
.hvbtn.on,.hvbtn[aria-pressed=true]{background:var(--coral);color:#fff;box-shadow:0 1px 3px rgba(224,122,95,.4)}
.hvbtn:active{transform:translateY(1px)}
/* pin the view your shelf opens on (and what visitors land on). Quiet until it's set. */
.hvpin{flex:none;white-space:nowrap}
.hvpin.pinned{border-color:var(--coral);color:var(--coral-d);background:#fdeee9}
.hvpin[hidden]{display:none}
.tiny{font-size:.82rem}
/* Display top row: the wall-design trigger */
.displaytop{display:flex;align-items:center;justify-content:space-between;gap:8px;max-width:900px;margin:0 auto}
.displaytop .walldesign{margin:0 0 8px}
.wallpack.wp-off{display:none} /* storage-only pack kept in the owner's wall DOM for instant show/hide */
/* ===== Storage: friends OFF display only (on-display cards hide, one home at a time) ===== */
/* every friend shows here, the tag badge says who's out on display vs resting */
.stgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:12px;max-width:780px;margin:0 auto 8px}
@media(max-width:560px){.stgrid{grid-template-columns:repeat(2,1fr);gap:10px}}
.stcard{position:relative;display:flex;flex-direction:column;align-items:center;gap:6px;padding:12px 10px 11px;border:0;cursor:pointer;
  background:linear-gradient(180deg,#fffdf9,var(--paper));border-radius:18px;-webkit-tap-highlight-color:transparent;
  box-shadow:var(--shadow-s),inset 0 0 0 1px rgba(64,52,43,.06);transition:transform .15s var(--ease-out),box-shadow .15s var(--ease-out)}
.stcard:active{transform:translateY(1px)}
.stcard.sel{box-shadow:0 0 0 2.5px var(--coral-d),var(--shadow-m)}
.stcard-pic{position:relative;width:100%;aspect-ratio:1;display:flex;align-items:center;justify-content:center;border-radius:14px;overflow:hidden;
  background:radial-gradient(120% 100% at 50% 8%,rgba(255,255,255,.55),rgba(64,52,43,.05))}
.stcard-pic img{max-width:88%;max-height:88%;width:auto;height:auto;object-fit:contain;filter:drop-shadow(0 4px 5px rgba(64,52,43,.22))}
.stemoji{font-size:54px;line-height:1}
.stcard-name{font-family:var(--body);font-weight:800;font-size:.92rem;color:var(--ink);max-width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.stcard-tag{font-family:var(--body);font-weight:800;font-size:.66rem;padding:2px 10px;border-radius:999px;
  background:rgba(64,52,43,.09);color:var(--ink2)}
.stcard.on .stcard-tag{background:#e3f4ea;color:#1f8a3b}
.stcard-check{position:absolute;top:8px;right:8px;width:24px;height:24px;border-radius:50%;display:flex;align-items:center;justify-content:center;
  background:var(--coral-d);color:#fff;font-size:.78rem;font-weight:800;opacity:0;transform:scale(.5);transition:opacity .14s,transform .14s}
.stcard.sel .stcard-check{opacity:1;transform:none}
/* open → plush page (re-cut lives there) */
.stopen{position:absolute;top:7px;left:7px;z-index:2;width:26px;height:26px;border-radius:50%;display:flex;align-items:center;justify-content:center;
  background:var(--paper);color:var(--ink2);font-size:.9rem;font-weight:800;text-decoration:none;box-shadow:0 1px 3px rgba(64,52,43,.22);opacity:.8}
.stopen:hover{opacity:1;color:var(--coral-d)}
.stdel{position:absolute;top:7px;right:7px;z-index:2;width:26px;height:26px;border-radius:50%;display:flex;align-items:center;justify-content:center;
  border:0;cursor:pointer;background:var(--paper);font-size:.8rem;box-shadow:0 1px 3px rgba(64,52,43,.22);opacity:.8;-webkit-tap-highlight-color:transparent}
.stdel:hover{opacity:1;background:#ffe6df}
/* ── the "say goodbye" confirm, one cute card on a soft scrim, nothing scary ── */
/* shared cute popup, sticker-book card (slime-maker recipe) in PlushBase's readable font */
.byebox,.cutepop{position:fixed;inset:0;z-index:300;display:flex;align-items:center;justify-content:center;padding:20px;
  background:rgba(43,32,23,.4);-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}
.byebox[hidden],.cutepop[hidden]{display:none}
.cutepop-scrim{position:absolute;inset:0}
.bye-card,.cutepop-card{position:relative;width:min(340px,92vw);text-align:center;
  background:#fff radial-gradient(rgba(244,158,192,.12) 2.5px,transparent 2.5px) 0 0/22px 22px;
  border:3px solid #5A4A5E;border-radius:24px;padding:22px 22px 18px;
  box-shadow:6px 6px 0 #5A4A5E,0 18px 44px rgba(43,32,23,.3);animation:byepop .28s var(--ease-out)}
@keyframes byepop{0%{transform:scale(.88) translateY(8px);opacity:0}100%{transform:none;opacity:1}}
@media(prefers-reduced-motion:reduce){.bye-card,.cutepop-card{animation:none}}
.bye-card b,.cutepop-card b{font-family:var(--display);font-weight:600;font-size:1.2rem;color:#5A4A5E}
.bye-pic,.cutepop-pic{display:flex;align-items:center;justify-content:center;width:84px;height:84px;margin:0 auto 10px;border-radius:50%;
  font-size:44px;overflow:hidden;background:#FFF8FB;border:2.5px solid #5A4A5E;box-shadow:2.5px 2.5px 0 rgba(90,74,94,.25)}
.bye-pic img,.cutepop-pic img{width:80%;height:80%;object-fit:contain}
/* ── desktop editor: hero on the left, all editor cards in a scrollable right panel ── */
@media(min-width:960px){
  .pedit-layout{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.05fr);gap:26px;align-items:start;max-width:1000px;margin:0 auto}
  .pedit-hero{position:sticky;top:14px}
  .pedit-panel{max-height:calc(100vh - 40px);overflow-y:auto;overscroll-behavior:contain;padding-right:6px;scrollbar-width:thin}
  .pedit-panel>.card,.pedit-panel>form{margin-bottom:14px}
}
/* the gentle "saved" toast, floats above the bottom nav, fades away on its own */
#pbtoast{position:fixed;left:50%;bottom:calc(88px + env(safe-area-inset-bottom));z-index:240;
  transform:translate(-50%,8px);opacity:0;pointer-events:none;
  background:rgba(43,32,23,.88);color:#fff8ee;font:800 .85rem var(--body);padding:9px 16px;border-radius:999px;
  box-shadow:0 8px 20px rgba(43,32,23,.3);white-space:nowrap;
  transition:opacity .25s var(--ease-out),transform .25s var(--ease-out)}
#pbtoast.show{opacity:1;transform:translate(-50%,0)}
@media(min-width:900px){#pbtoast{bottom:26px}}
/* ── Photo & cutout card on the plush page ── */
.photocard>summary{cursor:pointer;font-weight:800;color:var(--ink);list-style:none}
.photocard>summary::-webkit-details-marker{display:none}
.photocard>summary::after{content:" ›";opacity:.5}
.photorow{display:flex;gap:14px;justify-content:center;margin:12px 0 2px}
.photocol{margin:0;display:flex;flex-direction:column;align-items:center;gap:6px}
.photocol figcaption{font-family:var(--body);font-weight:700;font-size:.76rem;color:var(--ink2)}
.photothumb{width:132px;height:132px;object-fit:contain;border-radius:14px;background:#fff;box-shadow:inset 0 0 0 1px rgba(64,52,43,.08)}
.photocol .photocut{display:flex;align-items:center;justify-content:center;width:132px;height:132px;border-radius:14px;
  background:repeating-conic-gradient(#f0ece4 0% 25%,#fff 0% 50%) 50%/18px 18px} /* checkerboard = transparency */
.photocol .photocut .photothumb{width:100%;height:100%;background:transparent;box-shadow:none}
.stbar{position:sticky;bottom:14px;z-index:40;display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;
  max-width:600px;margin:14px auto 0;padding:12px 16px;border-radius:18px;background:var(--paper);
  box-shadow:0 10px 26px -8px rgba(64,52,43,.42),inset 0 0 0 1px rgba(64,52,43,.1)}
.stbar[hidden]{display:none}
/* on mobile the fixed bottom nav owns the bottom ~64px+safe-area, lift the sticky
   move bar above it so it's never hidden behind the nav */
@media(max-width:899px){.stbar{bottom:calc(76px + env(safe-area-inset-bottom))}}
.stbar-count{font-family:var(--body);font-weight:800;color:var(--ink)}
.stbar-acts{display:flex;gap:8px;flex-wrap:wrap}
/* Wall design docks as a panel and the wall REFLOWS beside it so edits stay visible.
   Desktop: right drawer; the left nav collapses and the main content shifts left so the
   wall sits fully in the space beside the panel. Mobile: a bottom sheet, wall above it. */
.walldesign[open] #wtpanel{position:fixed;z-index:220;background:var(--paper);
  overflow-y:auto;-webkit-overflow-scrolling:touch}
/* desktop right drawer + reflow */
@media(min-width:900px){
  .walldesign[open] #wtpanel{top:0;right:0;bottom:0;width:340px;
    border-left:1.5px solid rgba(64,52,43,.14);box-shadow:-14px 0 36px rgba(64,52,43,.28);
    padding:14px 16px 24px;animation:wtslide .22s var(--ease-out)}
  .appshell,.appmain{transition:grid-template-columns .24s var(--ease-out),padding .24s var(--ease-out)}
  .sidebar{transition:opacity .18s var(--ease-out)}
  body.wtopen .appshell{grid-template-columns:0 minmax(0,1fr)}
  body.wtopen .sidebar{opacity:0;pointer-events:none}
  body.wtopen .appmain{padding-right:372px}
}
/* mobile bottom sheet + reflow (wall sits in the space above the sheet) */
@media(max-width:899px){
  /* half-sheet: covers ~48% of the screen so the wall + banner stay visible above it and
     edits show live (Reddit-style bottom sheet). The panel scrolls internally. */
  .walldesign[open] #wtpanel{left:0;right:0;bottom:0;top:auto;height:48vh;max-height:48vh;
    border-top:1.5px solid rgba(64,52,43,.14);border-radius:20px 20px 0 0;
    box-shadow:0 -14px 36px rgba(64,52,43,.3);
    padding:8px 16px calc(20px + env(safe-area-inset-bottom));animation:wtsheet .24s var(--ease-out)}
  .walldesign[open] #wtpanel::before{content:"";position:sticky;top:0;display:block;width:38px;height:4px;margin:2px auto 8px;
    border-radius:999px;background:rgba(64,52,43,.22)} /* grabber */
  /* lift the shelf just enough to clear the half-sheet, no giant empty gap above it */
  body.wtopen .wrap,body.wtopen .appmain{padding-bottom:50vh}
}
@keyframes wtslide{from{transform:translateX(40px);opacity:.4}to{transform:translateX(0);opacity:1}}
@keyframes wtsheet{from{transform:translateY(40px);opacity:.5}to{transform:translateY(0);opacity:1}}
@media(prefers-reduced-motion:reduce){.walldesign[open] #wtpanel{animation:none}.appshell,.appmain,.sidebar{transition:none}}
.wtpanel-head{display:flex;align-items:center;justify-content:space-between;gap:10px;margin:0 0 10px;
  font-family:var(--body);font-size:1rem;color:var(--ink)}
#wtsaved{margin-left:auto;font-size:.72rem;white-space:nowrap}
/* chunk the long option list into three scannable groups: wall · hanging · plaque */
.wtsect{font-family:var(--display);font-weight:600;font-size:.95rem;color:var(--coral-d);
  margin:16px 0 6px;padding-top:12px;border-top:1px dashed var(--line)}
.wtnav+.wtsect{margin-top:2px;padding-top:0;border-top:0}
/* sticky section jumper, the drawer is long; one tap lands on Looks/Wall/Hang/Plaque */
/* banner title promoted to the very top of the panel for one-tap access */
.wtbanner-top{margin:0 0 8px}
.wtnav{position:sticky;top:0;z-index:6;display:flex;gap:6px;padding:6px 0 8px;margin:0 -4px;
  background:linear-gradient(var(--paper) 82%,transparent)}
.wtnav-b{flex:1 1 0;font-family:var(--body);font-weight:800;font-size:.78rem;padding:8px 4px;min-height:36px;
  border:1.5px solid var(--line);border-radius:999px;background:var(--card);color:var(--ink);cursor:pointer;white-space:nowrap;
  -webkit-tap-highlight-color:transparent}
.wtnav-b:hover{border-color:var(--coral)}
.wtnav-b.on{background:var(--coral);border-color:var(--coral-d);color:#fff}
.wtnav-b:active{transform:translateY(1px)}
/* active Popular look wears a badge, like a chosen sticker */
.wpreset{position:relative}
.wpreset[aria-pressed=true]::after{content:"✓";content:"✓" / "";position:absolute;top:-7px;right:-7px;width:22px;height:22px;
  display:grid;place-items:center;font-size:.8rem;font-weight:800;color:#fff;background:var(--coral-d);
  border-radius:50%;box-shadow:0 1px 3px rgba(64,52,43,.4),0 0 0 2px var(--paper)}
/* trim chips carry a live mini-preview strip of the pattern on the current plaque colour */
.trimchip{display:inline-flex;align-items:center;gap:7px}
.trimprev{width:36px;height:15px;border-radius:4px;flex:none;border:1px solid rgba(67,41,27,.5);
  background:var(--trim,linear-gradient(rgba(0,0,0,0),rgba(0,0,0,0))),linear-gradient(180deg,var(--sg1,#f6aebf),var(--sg2,#ee9ab0))}
.trimprev.wst-stitch{outline:1.5px dashed rgba(67,41,27,.55);outline-offset:-4px}
/* one-tap bundled looks: each card is a live mini board, wall gradient (wt-* vars),
   a plaque strip in the look's sign colour (wsc-* vars), its emoji, and a name */
/* 20 looks would push the rest of the drawer off-screen, same capped scroller the
   emoji grid uses, so Wall/Hang/Plaque stay one flick away */
.wpresets{display:grid;grid-template-columns:repeat(4,1fr);gap:8px;max-height:310px;overflow-y:auto;
  padding:8px 8px 4px 2px;scrollbar-width:thin;overscroll-behavior:contain; /* top/right padding: the ✓ badge hangs -7px outside its tile */
  /* fade the last sliver of tiles so the cut row reads as "scroll for more", not breakage */
  -webkit-mask-image:linear-gradient(180deg,#000 calc(100% - 22px),transparent);
  mask-image:linear-gradient(180deg,#000 calc(100% - 22px),transparent)}
@media(max-width:390px){.wpresets{grid-template-columns:repeat(3,1fr)}}
.wpreset{min-width:0;border:2px solid rgba(64,52,43,.16);border-radius:13px;background:var(--card);cursor:pointer;
  padding:4px 4px 6px;display:flex;flex-direction:column;gap:4px;-webkit-tap-highlight-color:transparent;
  transition:transform .15s var(--ease-out),border-color .15s var(--ease-out)}
.wpreset:hover{border-color:var(--coral);transform:translateY(-1px)}
.wpreset:active{transform:translateY(1px)}
.wpreset[aria-pressed=true]{border-color:var(--coral-d);box-shadow:0 0 0 2px rgba(224,122,95,.4)}
.wpr-board{position:relative;height:44px;border-radius:9px;overflow:hidden;
  background:var(--grain,linear-gradient(rgba(0,0,0,0),rgba(0,0,0,0))),linear-gradient(var(--panel1,#f6efe0),var(--panel2,#eee4cf));
  box-shadow:inset 0 -5px 7px -5px rgba(0,0,0,.25),inset 0 5px 7px -5px rgba(255,255,255,.35)}
.wpr-em{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:.9rem;line-height:1;
  letter-spacing:1px;filter:drop-shadow(0 1px 1px rgba(64,52,43,.3))}
/* two lines, so "🍄 Cottage Woods" reads as itself instead of "Cottag…", and
   overflow-wrap so a long single word ("Marshmallow") breaks instead of clipping mid-glyph */
.wpr-name{font-family:var(--body);font-weight:800;font-size:.66rem;line-height:1.2;text-align:center;color:var(--ink);
  overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;min-height:2.4em;overflow-wrap:anywhere}
@media(prefers-reduced-motion:reduce){.wpreset,.wpreset:hover{transition:none;transform:none}}
.wtclose{border:1.5px solid rgba(64,52,43,.2);background:var(--paper);color:var(--ink);width:38px;height:38px;
  border-radius:50%;font-size:1rem;font-weight:800;cursor:pointer;-webkit-tap-highlight-color:transparent}
.wtclose:active{transform:translateY(1px)}
/* inside the drawer the theme swatches wrap instead of side-scrolling */
.walldesign[open] .wtrow{flex-wrap:wrap;overflow-x:visible;padding-bottom:4px}
.walldesign[open] .wtslider{max-width:100%}
/* back-panel design picker */
.walldesign{max-width:900px;margin:0 auto 8px}
/* the Decorate button, coral pill with a pen so it clearly reads as "edit the wall" */
.walldesign>summary{cursor:pointer;font-family:var(--body);font-weight:800;font-size:.9rem;color:#fff;list-style:none;
  display:inline-flex;align-items:center;gap:6px;padding:8px 16px;min-height:40px;border-radius:999px;
  background:var(--coral);border:1px solid var(--coral-d);box-shadow:0 3px 8px -2px rgba(224,122,95,.5);-webkit-tap-highlight-color:transparent}
.walldesign>summary:hover{background:var(--coral-d)}
.walldesign>summary .wd-pen{font-size:.95rem}
.walldesign>summary::-webkit-details-marker{display:none}
.walldesign[open]>summary{background:var(--coral-d)}
/* keep the Decorate button hugging the RIGHT of the header row (not full-width below) */
.homehead .displaytop[data-homeview=wall]{flex:0 0 auto;margin-left:auto}
.walldesign[open]>summary{margin-bottom:10px}
.wtrow{display:flex;gap:10px;overflow-x:auto;padding:4px 2px 10px;scrollbar-width:thin;-webkit-overflow-scrolling:touch}
.wtsw{flex:0 0 auto;width:76px;height:58px;border-radius:13px;border:2px solid rgba(64,52,43,.16);cursor:pointer;position:relative;overflow:hidden;padding:0;
  display:flex;align-items:flex-end;justify-content:center;-webkit-tap-highlight-color:transparent;
  background:var(--grain,linear-gradient(rgba(0,0,0,0),rgba(0,0,0,0))),linear-gradient(var(--panel1,#f6efe0),var(--panel2,#eee4cf));
  box-shadow:inset 0 -6px 8px -6px rgba(0,0,0,.25),inset 0 6px 8px -6px rgba(255,255,255,.4)}
.wtsw[aria-pressed=true]{border-color:var(--coral-d)}
.wtsw:active{transform:translateY(1px)}
/* panel-size / spacing / hook option rows under the swatches */
.wtopt{display:flex;align-items:center;gap:10px;margin:6px 0;flex-wrap:wrap}
.wtoptlbl{font-family:var(--body);font-weight:800;font-size:.78rem;color:var(--ink);width:62px;flex-shrink:0}
.wtchips{display:flex;gap:6px;flex-wrap:wrap}
.wtchip{border:1.5px solid rgba(64,52,43,.18);background:var(--paper);color:var(--ink);border-radius:999px;
  font-family:var(--body);font-weight:700;font-size:.78rem;padding:7px 12px;min-height:34px;cursor:pointer;
  -webkit-tap-highlight-color:transparent;transition:background .15s var(--ease-out),border-color .15s var(--ease-out)}
.wtchip[aria-pressed=true]{background:var(--coral);border-color:var(--coral-d);color:#fff}
.wtchip:active{transform:translateY(1px)}
/* sliders for panel size + spacing */
.wtslider{flex:1;min-width:130px;max-width:260px;height:34px;margin:0;accent-color:var(--coral-d);cursor:pointer}
.wtval{font-family:var(--body);font-weight:800;font-size:.78rem;color:var(--ink);min-width:52px;text-align:right}
/* sign controls: text input (16px font so iOS doesn't zoom), colour chips, mascot thumbs */
.wtinput{flex:1;min-width:150px;max-width:280px;font-family:var(--body);font-weight:700;font-size:16px;color:var(--ink);
  background:var(--paper);border:1.5px solid rgba(64,52,43,.22);border-radius:12px;padding:9px 13px;min-height:40px}
.wtinput:focus-visible{outline:2px solid var(--coral-d);outline-offset:1px}
/* stacked option (emoji picker) + popular-emoji grid with search */
.wtopt-col{flex-direction:column;align-items:stretch;gap:8px}
.emojigrid{display:flex;flex-wrap:wrap;gap:3px;max-height:156px;overflow-y:auto;padding:4px 2px;
  background:rgba(64,52,43,.04);border-radius:12px;-webkit-overflow-scrolling:touch}
.emojibtn{border:0;background:transparent;font-size:1.35rem;line-height:1;width:38px;height:38px;border-radius:10px;cursor:pointer;
  display:flex;align-items:center;justify-content:center;-webkit-tap-highlight-color:transparent}
@media(hover:hover){.emojibtn:hover{background:var(--paper)}}
.emojibtn.on{background:rgba(224,122,95,.2);box-shadow:inset 0 0 0 2px var(--coral-d)}
.emojibtn:active{transform:translateY(1px)}
/* the Outline row only shows when the keychain hanger is selected */
.keychainonly{display:none}
#wtpanel.showkeychain .keychainonly{display:flex}
/* display-style tiles: five mini renders of the real display objects (charm, card, box,
   bag, acrylic case), each a tap target, the wall behind is the live preview */
.disptiles{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;width:100%}
.disptile{min-width:0;border:2px solid rgba(64,52,43,.16);border-radius:13px;background:var(--card);cursor:pointer;
  padding:4px 4px 6px;display:flex;flex-direction:column;gap:4px;position:relative;-webkit-tap-highlight-color:transparent;
  transition:transform .15s var(--ease-out),border-color .15s var(--ease-out)}
.disptile:hover{border-color:var(--coral);transform:translateY(-1px)}
.disptile:active{transform:translateY(1px)}
.disptile[aria-pressed=true]{border-color:var(--coral-d);box-shadow:0 0 0 2px rgba(224,122,95,.4)}
.disptile[aria-pressed=true]::after{content:"✓";content:"✓" / "";position:absolute;top:-7px;right:-7px;width:22px;height:22px;
  display:grid;place-items:center;font-size:.8rem;font-weight:800;color:#fff;background:var(--coral-d);
  border-radius:50%;box-shadow:0 1px 3px rgba(64,52,43,.4),0 0 0 2px var(--paper);z-index:2}
.dt-stage{height:92px;border-radius:9px;overflow:hidden;display:flex;align-items:flex-start;justify-content:center;
  background:radial-gradient(120% 100% at 50% 0%,#fff8ee,#f1e6d2)}
/* per-type fit: each preview renders at natural size, then scales to sit whole inside
   the 92px stage (pack cards are ~300×370 natural, the charm ~120×255, the case ~124×183) */
.dt-fit{transform-origin:top center;pointer-events:none;position:relative;flex:none}
.disptile.at-keychain .dt-fit{transform:scale(.34)}
.disptile.at-card .dt-fit,.disptile.at-box .dt-fit,.disptile.at-bag .dt-fit{transform:scale(.24)}
.disptile.at-case .dt-fit{transform:scale(.48)}
.dt-name{font-family:var(--body);font-weight:800;font-size:.66rem;line-height:1.2;text-align:center;color:var(--ink);
  overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow-wrap:anywhere}
/* Pack's shape row, only while a pack display is active */
.packsub{display:none}
#wtpanel.showpackage .packsub{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;width:100%;margin-top:2px}
.disptile.mini .dt-stage{height:64px}
.disptile.mini.at-card .dt-fit,.disptile.mini.at-box .dt-fit,.disptile.mini.at-bag .dt-fit{transform:scale(.165)}
/* catalog: dead hotlinks swap to this tile (global error handler); 2-line name clamp */
.catfb{width:100%;aspect-ratio:1;display:grid;place-items:center;background:#f8f1e7;border-radius:8px;font-size:2.6rem}
/* catalog card: the whole tile still opens the entry, with Save / + Add sitting on top so a
   collector can claim or wishlist a plushie without leaving the grid */
.catgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(108px,1fr));gap:10px}
.catcard{position:relative;border:1px solid var(--line,#e5ded2);border-radius:12px;padding:8px;background:#fff;display:flex;flex-direction:column}
.catcard-go{text-decoration:none;color:inherit;display:block}
.catcard.added{box-shadow:0 0 0 2px var(--coral-d,#c4643f)}
.catact{display:flex;gap:6px;align-items:center;margin-top:6px;flex-wrap:wrap}
.catadd{flex:1;min-width:0;border:0;cursor:pointer;border-radius:9px;padding:7px 8px;font:inherit;font-weight:800;font-size:.76rem;
  color:#fff;background:var(--coral-d,#c4643f);white-space:nowrap}
.catadd:hover{filter:brightness(1.06)}
.catadd[disabled]{opacity:.75;cursor:default}
/* .savebtn is the big pill used on shelves; on a catalog card it shrinks to a heart chip.
   Double class so these win over the .savebtn base rules further down the sheet. */
.savebtn.catsave{flex:none;width:34px;height:32px;padding:0;border-radius:9px;border:1px solid var(--line,#e5ded2);
  background:#fff;cursor:pointer;display:grid;place-items:center;font-size:.95rem;color:#cbc2b4;line-height:1;gap:0}
.savebtn.catsave.on{color:#fff;border-color:var(--coral-d,#c4643f);background:var(--coral-d,#c4643f)}
.savebtn.catsave:hover{transform:scale(1.06)}
/* size chips appear in place when an entry comes in more than one size */
.catsizes{display:flex;flex-wrap:wrap;gap:5px;width:100%}
.catsize{border:1px solid var(--line,#e5ded2);background:#fff;border-radius:8px;padding:5px 8px;font:inherit;font-size:.72rem;font-weight:700;cursor:pointer;color:#4a3620}
.catsize:hover{border-color:var(--coral-d,#c4643f);color:var(--coral-d,#c4643f)}
.savedh{font-size:1.05rem;margin:0 0 2px}
.catname{font-size:.8rem;font-weight:600;margin-top:4px;line-height:1.25;
  overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow-wrap:anywhere}
/* pack/case preview cell in the wall editor, same cream box as the keychain preview */
.wssw{background:linear-gradient(180deg,var(--sg1),var(--sg2));border-color:rgba(64,52,43,.3)}
.wssw[aria-pressed=true]{color:#43291b;background:linear-gradient(180deg,var(--sg1),var(--sg2));box-shadow:0 0 0 2px var(--coral-d)}
  display:inline-flex;align-items:center;justify-content:center;-webkit-tap-highlight-color:transparent}
.wtlbl{font-family:var(--body);font-size:.66rem;font-weight:800;background:rgba(255,255,255,.85);color:#43291b;border-radius:6px;padding:1px 5px;margin-bottom:6px;pointer-events:none;white-space:nowrap}
.wt-walnut .wtlbl,.wt-charcoal .wtlbl{background:transparent;color:#fff;text-shadow:0 1px 2px rgba(0,0,0,.45)}
/* ===== the furry wordmark, plush pillow letters + hearts/paws to play with ===== */
.furlogo{position:relative;display:flex;flex-wrap:wrap;justify-content:center;align-items:center;gap:2px 10px;
  margin:6px auto 24px;max-width:760px;padding:10px 16px}
.furlword{display:flex;align-items:center;gap:14px} /* halo+fringe widen each glyph ~13px — tight gaps merge letters */
.furl{display:block;height:clamp(58px,14vw,96px);width:34px} /* width self-sizes per glyph via /fur.js */
.furlogo.compact{margin:0 auto 10px;padding:4px 8px}
.furlogo.compact .furl{height:clamp(44px,11vw,60px)}
.furlogo .furdeco{display:block;position:absolute} /* .furlogo scope outranks .fur's position:relative */
/* grounding shadow options, the cheap half of "looks 3D".
   soft = sits on the page · cast = floats with a thrown studio shadow (seedream ref) */
.furlogo.sh-soft .fur-canvas{filter:drop-shadow(0 7px 9px rgba(133,63,95,.26))}
.furlogo.sh-cast .fur-canvas{filter:drop-shadow(-13px 17px 14px rgba(139,77,101,.32)) drop-shadow(-3px 5px 4px rgba(139,77,101,.18))}
/* glow = backlit rim: a white halo hugging the silhouette + a whisper of ground shadow
   (the tone-on-tone "PUSY" look, pair with the nub texture and a pale pink) */
.furlogo.sh-glow .fur-canvas{filter:drop-shadow(0 0 3px rgba(255,255,255,.95)) drop-shadow(0 0 9px rgba(255,255,255,.65)) drop-shadow(0 10px 12px rgba(170,100,125,.18))}
.furdeco.fd-h1{width:46px;height:42px;left:-16px;top:-22px;rotate:-14deg}
.furdeco.fd-h2{width:34px;height:31px;right:-6px;bottom:-16px;rotate:11deg}
.furdeco.fd-p1{width:42px;height:42px;right:-18px;top:-24px;rotate:14deg}
.furdeco.fd-p2{width:36px;height:36px;left:-4px;bottom:-20px;rotate:-10deg}
@media(max-width:460px){.furdeco.fd-h1{left:-14px}.furdeco.fd-p1{right:-14px}}
/* ===== fun share overlay: tap a wall plushie, sneaker-style product stage ===== */
.pmodal{position:fixed;inset:0;z-index:400}
.pmodal[hidden]{display:none}
/* light, opaque pastel world, no dark dim, no white modal box (sneaker.md) */
.pmodal-scrim{position:absolute;inset:0;background:#f8f4ee;opacity:0;transition:opacity .24s}
.pmodal.on .pmodal-scrim{opacity:1}
/* the world tints to the active plushie's gradient while swiping (sneaker.md) */
.pm-bg{position:absolute;inset:0;opacity:0;pointer-events:none}
/* the plushie is the hero, a soft aura spotlight, cutout floating with a shadow, sparkles */
/* ===== swipe overlay, the cutout BURSTS out of its gradient panel (sneaker-style) ===== */
.pcar{position:relative;z-index:1;height:100%;overflow:hidden;touch-action:pan-y;
  opacity:0;transform:translateY(18px) scale(.97);transition:transform .28s var(--ease-out),opacity .24s}
.pmodal.on .pcar{transform:none;opacity:1}
/* the slime-maker backdrop, exactly: #FFF3F7 with a 38px grid of #FFD8E6 dots */
.pmodal-scrim::after{content:"";position:absolute;inset:0;pointer-events:none;
  background:#FFF3F7 radial-gradient(#FFD8E6 12%,transparent 13%);background-size:38px 38px}
.pcar-track{display:flex;height:100%;will-change:transform}
.pcard{flex:0 0 100%;box-sizing:border-box;height:100%;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:22px;
  overflow:hidden; /* each slide clips its own jump-out, neighbours never peek into the corners */
  padding:max(24px,env(safe-area-inset-top)) 20px max(60px,calc(env(safe-area-inset-bottom) + 44px))}
/* the wrapper vanishes on mobile, stage + info lay out exactly as before */
.pcard-box{display:contents}
/* the gradient "box" the plushie jumps out of, background set inline per plushie */
.pcard-stage{position:relative;display:flex;align-items:center;justify-content:center;
  width:min(78vw,330px);aspect-ratio:1/1.06;border-radius:22px;
  border:3px dashed #FF9EC4; /* the slime-maker preview-zone, exactly */
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.3)}
.pcard-stage::after{content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;
  background:linear-gradient(120deg,transparent 44%,rgba(255,255,255,.28) 51%,transparent 60%)}
/* centred and CONTAINED: the plushie sits inside its washi-framed box like a proper
   product card (the old 136% burst spilled past every edge). */
.pm-cut{position:relative;z-index:2;width:88%;max-width:none;max-height:90%;object-fit:contain;
  filter:drop-shadow(0 18px 18px rgba(64,52,43,.3));transform-origin:50% 70%;will-change:transform;
  user-select:none;-webkit-user-select:none;-webkit-touch-callout:none}
.pm-cut.pm-emoji{font-size:150px;line-height:1;width:auto}
/* soft contact shadow, lags the cutout during swipes */
.pm-shadow{position:absolute;z-index:1;bottom:7%;left:50%;width:56%;height:18px;border-radius:50%;
  background:radial-gradient(ellipse at center,rgba(46,38,30,.34),transparent 68%);
  transform:translateX(-50%);will-change:transform;pointer-events:none}
.pcard-info{width:min(78vw,330px);text-align:left}
.pcard-cat{display:inline-block;font-family:var(--body);font-weight:800;font-size:.72rem;letter-spacing:.12em;text-transform:uppercase;color:#5A4A5E;background:#FFE6F0;border:2px solid #5A4A5E;border-radius:12px;padding:3px 12px;box-shadow:2px 2px 0 #5A4A5E}
.pcard-name{font-family:var(--display);font-weight:600;font-size:clamp(1.9rem,7.5vw,2.5rem);letter-spacing:0;line-height:1.05;margin:6px 0 6px;color:#5A4A5E;text-shadow:3px 3px 0 #fff,5px 5px 0 #FF9EC4}
.pcard-rar{font-family:var(--body);font-weight:700;font-size:.92rem;color:#a9762a;display:flex;align-items:center;gap:6px}
.pcard-rar.muted{color:rgba(64,52,43,.55)}
.pcard-stars{color:#f2b636;letter-spacing:.08em;font-size:1.05rem;text-shadow:0 1px 0 rgba(120,80,20,.25)}
/* gradient swatches, rounded squares, one gap+coral ring when picked */
.pm-swatches{display:flex;gap:10px;margin-top:16px}
/* invisible hit-area expansion to ~44px on small controls, expansion is mostly
   vertical so adjacent controls in a row don't steal each other's taps */
.hvbtn,.wtchip,.wtnav-b,.emojibtn,.pm-sw{position:relative}
.hvbtn::after,.wtnav-b::after{content:"";position:absolute;inset:-6px 0;border-radius:inherit}   /* single rows: grow down/up only */
.wtchip::after{content:"";position:absolute;inset:-3px -2px;border-radius:inherit}               /* wrapped rows, 6px gap: meet in the middle */
.emojibtn::after{content:"";position:absolute;inset:-1px;border-radius:inherit}                  /* 3px grid gap, anything bigger steals taps */
.pm-sw::after{content:"";position:absolute;inset:-9px -4px;border-radius:inherit}
.pm-sw{width:26px;height:26px;border-radius:9px;border:0;
  box-shadow:inset 0 0 0 1px rgba(64,52,43,.14),inset 0 1px 0 rgba(255,255,255,.4);cursor:pointer;padding:0;-webkit-tap-highlight-color:transparent;
  transition:transform .15s var(--ease-out),box-shadow .15s}
.pm-sw:hover{transform:scale(1.08)}
.pm-sw.on{box-shadow:0 0 0 2px var(--paper),0 0 0 4px var(--coral-d),inset 0 0 0 1px rgba(64,52,43,.14)}
.pme-sw{margin:2px 0 10px}
/* position dots, the only hint there's more to swipe to */
.pcar-dots{position:absolute;z-index:2;left:0;right:0;bottom:max(16px,env(safe-area-inset-bottom));display:flex;gap:6px;justify-content:center;flex-wrap:wrap;padding:0 16px;pointer-events:none}
.pcar-dot{width:6px;height:6px;border-radius:50%;background:rgba(64,52,43,.22);transition:background .2s,transform .2s}
.pcar-dot{background:#EFD9E2}
.pcar-dot.on{background:#FF9EC4;transform:scale(1.3)}
/* ===== desktop: the full-screen burst is too much, a compact floating card instead.
   Same clean cutout + changeable gradient + swatches + swipe, zero buttons.
   (Must come AFTER the mobile base rules so equal-specificity overrides win.) ===== */
@media(min-width:720px){
  /* a true modal: page dimmed behind, pastel world + backdrop tint are mobile-only */
  .pmodal-scrim{background:rgba(43,32,23,.45)}
  .pmodal-scrim::after{display:none} /* dots are part of the mobile pastel world */
  .pm-bg{display:none}
  .pcard-box{display:block;width:min(400px,92vw);max-height:calc(100vh - 96px);box-sizing:border-box;
    background:#fff;
    border-radius:26px;padding:24px 24px 20px;
    border:3px solid #5A4A5E;
    box-shadow:6px 6px 0 #5A4A5E,0 24px 60px -18px rgba(64,52,43,.3)}
  .pcard-stage{width:min(100%,44vh);margin:0 auto}
  /* contained on desktop, a tidy product shot, not a burst */
  .pm-cut{width:86%;max-height:92%}
  .pm-cut.pm-emoji{font-size:110px}
  .pcard-info{width:100%;margin-top:14px}
  .pcard-name{font-size:2rem}
}
/* close ✕, always visible (a modal you can't see how to leave is a trap on mobile) */
.pm-close{display:grid;position:fixed;top:max(14px,env(safe-area-inset-top));right:14px;z-index:460;width:46px;height:46px;border-radius:50%;
  border:2px solid #5A4A5E;background:#fff;box-shadow:2px 2px 0 #5A4A5E;
  font:800 1.05rem/1 var(--body);color:#5A4A5E;cursor:pointer;place-items:center;
  transition:transform .1s var(--ease-out),box-shadow .1s var(--ease-out)}
.pm-close:hover{background:#FFE6F0}
.pm-close:active{transform:translate(2px,2px);box-shadow:0 0 0 #5A4A5E}
/* owner ✏️ Edit chip inside the overlay card */
.pcard-actions{display:flex;gap:10px;justify-content:center;margin-top:12px}
.pcard-actions .btn{text-decoration:none}
.pm-edit{display:inline-flex;align-items:center;gap:6px;margin-top:14px;padding:9px 20px;min-height:42px;
  border-radius:14px;border:2px solid #5A4A5E;background:#FFF8FB;
  font-family:var(--body);font-weight:800;font-size:.9rem;color:#5A4A5E;cursor:pointer;
  box-shadow:2px 2px 0 #5A4A5E;
  transition:transform .1s var(--ease-out),box-shadow .1s var(--ease-out)}
.pm-edit:hover{background:#FFE6F0}
.pm-edit:active{transform:translate(2px,2px);box-shadow:0 0 0 #5A4A5E}
/* quick-edit panel, floats above the overlay, centered bottom sheet */
@keyframes pmpackin{0%{transform:translateY(16px) scale(.82) rotate(-4deg);opacity:0}100%{transform:none;opacity:1}}
.pmedit{position:fixed;z-index:470;left:50%;bottom:max(20px,env(safe-area-inset-bottom));transform:translateX(-50%);
  width:min(340px,calc(100vw - 32px))}
.pmedit form{background:#fff;
  border:3px solid #5A4A5E;border-radius:26px;
  box-shadow:6px 6px 0 #5A4A5E,0 24px 60px -16px rgba(64,52,43,.35);padding:16px 18px 14px;
  animation:pmpackin .35s cubic-bezier(.25,1.5,.4,1) both}
.pmedit input[type=text]{background:#FFF8FB;border:3px solid #5A4A5E;border-radius:14px;font-family:var(--body);font-weight:700;color:#5A4A5E}
.pmedit input[type=text]:focus{border-color:#FF9EC4;box-shadow:none}
.pmedit b{font-family:var(--display);font-weight:600;font-size:1.2rem;color:#5A4A5E}
.pmedit[hidden]{display:none}
.pmedit b{display:block;font:700 1.1rem var(--hand);margin-bottom:10px}
.pmedit label{display:block;font:800 .68rem var(--body);letter-spacing:.08em;text-transform:uppercase;color:var(--ink2);margin:8px 0 4px}
.pmedit input{width:100%;box-sizing:border-box;padding:10px 12px;border-radius:12px;border:1.5px solid var(--line);
  background:var(--paper);font:600 .95rem var(--body);color:var(--ink)}
.pmedit input:focus{outline:none;border-color:var(--coral)}
.pmedit-row{display:flex;gap:8px;align-items:center;margin-top:14px;flex-wrap:wrap}
.pmedit .sclink{margin-left:auto;font-size:.84rem}
.pmedit .status{margin:8px 0 0;font:700 .84rem var(--body);color:var(--ink2)}
/* ♥ Save / wishlist toggle */
.savebtn{display:inline-flex;align-items:center;justify-content:center;gap:7px;font-family:var(--body);font-weight:800;font-size:1rem;
  border:2px solid var(--coral);border-radius:999px;padding:10px 20px;background:var(--paper);color:var(--coral-d);cursor:pointer;
  -webkit-tap-highlight-color:transparent;transition:background .15s var(--ease-out),transform .1s var(--ease-out)}
.savebtn .savebtn-i{font-size:1.08em;line-height:1}
.savebtn.on{background:var(--coral-d);border-color:var(--coral-d);color:#fff}
.savebtn:active{transform:translateY(1px)}
@keyframes savepop{0%{transform:scale(1)}40%{transform:scale(1.32)}100%{transform:scale(1)}}
.savebtn.on .savebtn-i{animation:savepop .32s var(--ease-out)}
/* wishlist cards: you collect a die-cut STICKER of each saved friend (not the plushie) */
.savedcard{text-decoration:none;color:inherit}
.savedcard .stcard-pic{background:radial-gradient(120% 100% at 50% 0%,rgba(255,255,255,.6),rgba(64,52,43,.03))}
.savedcard .stickercut{max-width:82%;max-height:82%;width:auto;height:auto;object-fit:contain;
  filter:drop-shadow(2.5px 0 0 #fff) drop-shadow(-2.5px 0 0 #fff) drop-shadow(0 2.5px 0 #fff) drop-shadow(0 -2.5px 0 #fff) drop-shadow(1.8px 1.8px 0 #fff) drop-shadow(-1.8px -1.8px 0 #fff) drop-shadow(1.8px -1.8px 0 #fff) drop-shadow(-1.8px 1.8px 0 #fff) drop-shadow(0 6px 6px rgba(64,52,43,.28));
  transform:rotate(-2.5deg)}
.savedcard:nth-child(even) .stickercut{transform:rotate(2.5deg)}
.savedcard:nth-child(3n) .stickercut{transform:rotate(1.2deg)}
/* ===== floating plushie shelf, shadows + reflections + tactile motion ===== */
.shelfarea{position:relative;margin:16px auto 24px;max-width:720px}
@media(min-width:900px){
  /* desktop shelf: a proper centered stage, bigger friends, stronger shelf line */
  .shelfarea{margin-top:30px}
  .slot{width:156px}
  .pbook{height:250px;padding-bottom:26px}
  .pcutout{height:clamp(120px,13vw,168px);max-width:158px}
  .pemoji{font-size:96px}
  .plabel{font-size:1.5rem}
  .shelfrow{background-size:100% 250px;background-position:0 172px;padding-bottom:70px;gap:6px 22px}
}
.shelfrow{list-style:none;margin:0;padding:0 0 54px;display:flex;flex-wrap:wrap;justify-content:center;gap:4px 16px;
  /* a wooden plank under every wrapped row: lit top face, front edge, drop shadow */
  background-image:linear-gradient(to bottom,
    #e9cba4 0px,#dcb27f 5px,               /* top face catches the light */
    #c08d57 5px,#a8743f 19px,              /* front edge, a real plank, not a line */
    #96662f 19px,#8a5c28 22px,             /* underside lip */
    rgba(64,52,43,.16) 22px,rgba(64,52,43,0) 38px,  /* soft cast shadow */
    transparent 38px);
  background-size:100% 210px;background-position:0 138px;background-repeat:repeat-y}
.slot{width:120px;display:flex;min-width:0}
.pbook{position:relative;width:100%;height:210px;padding-bottom:22px;display:flex;flex-direction:column;align-items:center;justify-content:flex-end;
  text-decoration:none;color:inherit;cursor:pointer;outline:none;-webkit-tap-highlight-color:transparent}
.pbook:focus-visible{outline:2px solid var(--coral-d);outline-offset:4px;border-radius:14px}
.pfloat{display:block;animation:pfloat 3.4s ease-in-out infinite;animation-delay:calc(var(--i,0)*-0.5s)}
.plift{display:block;transition:transform .45s cubic-bezier(.25,1.5,.5,1)}
.pcutout{display:block;width:auto;height:clamp(94px,17vw,138px);max-width:128px;object-fit:contain;
  filter:url(#pb-sticker) var(--glow,drop-shadow(0 0 0 transparent)) drop-shadow(0 12px 14px rgba(64,52,43,.28));
  transition:transform .18s ease-out;-webkit-user-select:none;user-select:none;-webkit-touch-callout:none;pointer-events:none}
.pemoji{font-size:74px;line-height:1;filter:none}
.pbook:hover .plift,.pbook:focus-visible .plift{transform:translateY(-16px) scale(1.08)}
.pbook:hover .pfloat,.pbook:focus-visible .pfloat{animation-play-state:paused}
.pbook:hover .pcutout,.pbook:focus-visible .pcutout{filter:url(#pb-sticker) var(--glow,drop-shadow(0 0 0 transparent)) drop-shadow(0 20px 22px rgba(64,52,43,.26))}
.plabel{font-family:var(--hand);font-weight:700;font-size:1.3rem;line-height:1;text-align:center;color:var(--ink);margin-top:26px;overflow-wrap:anywhere;transition:transform .4s cubic-bezier(.25,1.5,.5,1)}
.pbook:hover .plabel,.pbook:focus-visible .plabel{transform:scale(1.06)}
@keyframes pfloat{0%,100%{transform:translateY(0)}50%{transform:translateY(-9px)}}
@keyframes pdrop{0%{transform:translateY(-34px);opacity:0}70%{transform:translateY(5px)}100%{transform:translateY(0);opacity:1}}
.anim .plift{animation:pdrop .6s cubic-bezier(.25,1.5,.5,1) backwards;animation-delay:calc(var(--i,0)*70ms)}
@keyframes psquish{0%{transform:translateY(-16px) scale(1.08)}35%{transform:translateY(-4px) scaleY(.82) scaleX(1.16)}70%{transform:translateY(-14px) scaleY(1.05) scaleX(.97)}100%{transform:translateY(-16px) scale(1.08)}}
.pbook.squish .plift{animation:psquish .32s ease}
/* press feedback on every secondary control (design.md: controls press) */
.vt:active,.factdel:active,.chip.pick:active,.snav-out:active{transform:translateY(1px)}
.bnav-i:active{opacity:.55}
.picon:active .pitile{transform:translateY(1px)}
@media (prefers-reduced-motion:reduce){
  .vt,.factdel{transition:none}
  .pfloat{animation:none}.plift{transition:none}.anim .plift{animation:none}.pbook.squish .plift{animation:none}.pcutout{transition:none}
  .pbook:hover .plift,.pbook:focus-visible .plift{transform:translateY(-6px)}
  .cubby .ph,.plabel,.aurapick label,.snav-i{transition:none}
}
/* ===== per-plushie aura (glow finish) ===== */
@property --gh{syntax:'<angle>';inherits:false;initial-value:0deg}
.aura-pink{--glow:drop-shadow(0 0 16px rgba(255,120,170,.62))}
.aura-coral{--glow:drop-shadow(0 0 16px rgba(224,122,95,.55))}
.aura-gold{--glow:drop-shadow(0 0 18px rgba(245,190,90,.64))}
.aura-mint{--glow:drop-shadow(0 0 16px rgba(130,205,155,.6))}
.aura-blue{--glow:drop-shadow(0 0 18px rgba(120,170,255,.6))}
.aura-lavender{--glow:drop-shadow(0 0 16px rgba(190,150,240,.6))}
.aura-halo{--glow:drop-shadow(0 0 26px rgba(255,255,255,.8))}
.aura-holo{--glow:drop-shadow(0 0 22px hsl(var(--gh) 92% 72% / .72));animation:aurahue 4.5s linear infinite}
@keyframes aurahue{to{--gh:360deg}}
/* The Sticker view IS the interactive peel. The WebGL host fills .herosticker; the library
   renders the sticker at ~58% of the host's height, so the host is sized ~1.7x the target
   sticker so the peel lands at the same size as the Card/Pack views (and matches on mobile). */
.herosticker{position:relative;display:flex;align-items:center;justify-content:center;width:min(430px,90vw);height:min(510px,92vw);margin:10px auto 6px}
.hero-cutout{display:block;height:min(300px,52vw);width:auto;object-fit:contain;
  filter:url(#pb-sticker) var(--glow,drop-shadow(0 0 0 transparent)) drop-shadow(0 16px 18px rgba(64,52,43,.26))}
/* peel canvas fills the sized host; the static cutout sits behind as the pre-load placeholder */
.peelhost{position:absolute;inset:0;touch-action:none}
.peelhost:focus,.peelhost :focus{outline:none} /* peel is a pointer gesture; drop the WebGL host's focus ring */
.peelhost canvas{display:block;width:100%;height:100%}
.aurapick{display:flex;flex-wrap:wrap;gap:11px;justify-content:center;align-items:center;margin:8px 0 0}
.aurapick input{position:absolute;width:1px;height:1px;opacity:0;pointer-events:none}
.aurapick label{width:34px;height:34px;border-radius:11px;cursor:pointer;transition:transform .15s,box-shadow .15s;display:block;position:relative;
  box-shadow:inset 0 0 0 1px rgba(64,52,43,.14)}
.aurapick label::after{content:"";position:absolute;inset:-6px;border-radius:14px} /* invisible 46px hit area */
.aurapick label:hover{transform:scale(1.1)}
/* !important: aura swatches carry their glow as an INLINE box-shadow, which would swallow the ring */
.aurapick input:checked+label{box-shadow:0 0 0 2px var(--paper),0 0 0 4px var(--coral-d) !important;transform:scale(1.04)}
.aurapick input:focus-visible+label{outline:2px solid var(--coral-d);outline-offset:3px}
@media (prefers-reduced-motion:reduce){.aura-holo{animation:none}}
/* ===== mobile bottom navigation ===== */
.bnav{position:fixed;left:0;right:0;bottom:0;z-index:60;display:none;grid-template-columns:repeat(5,1fr);align-items:end;
  background:rgba(255,253,249,.94);-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);
  border-top:1px solid var(--line);padding:7px 6px calc(7px + env(safe-area-inset-bottom))}
.bnav-i{display:flex;flex-direction:column;align-items:center;gap:3px;text-decoration:none;color:var(--ink2);
  font-size:.7rem;font-weight:700;padding:5px 0 2px;-webkit-tap-highlight-color:transparent}
.bnav-i svg{width:23px;height:23px}
.bnav-i[aria-current]{color:var(--coral-d)}
.bnav-add .fab{display:flex;align-items:center;justify-content:center;width:48px;height:48px;border-radius:50%;
  background:var(--coral-d);color:#fff;font-size:2rem;line-height:1;margin-top:-20px;box-shadow:0 7px 16px -5px rgba(200,90,68,.65)}
.bnav-add:active .fab{transform:scale(.94)}
/* the bar owns navigation all the way up to where the sidebar takes over, no dead zone */
@media(max-width:899px){.bnav{display:grid}.wrap{padding-bottom:94px}}
/* profile */
.profhead{display:flex;gap:14px;align-items:center;margin-bottom:18px}
.avatar{width:62px;height:62px;border-radius:50%;flex:none;object-fit:cover;background:var(--coral);color:#fff;
  display:flex;align-items:center;justify-content:center;font-family:var(--display);font-weight:700;font-size:1.7rem}
.avatar.sm{width:40px;height:40px;font-size:1rem}
/* profile hub: secondary destinations as one tidy list instead of scattered buttons */
.hublist{display:flex;flex-direction:column}
.hubrow{display:flex;align-items:center;gap:12px;padding:13px 2px;text-decoration:none;color:var(--ink);
  font-weight:700;border-bottom:1px solid var(--line)}
.hubrow:last-child{border-bottom:0}
.hubrow:hover{color:var(--coral-d)}
.hubrow .hubi{font-size:1.15rem;width:26px;text-align:center;flex:none}
.hubrow .hubc{flex:1;min-width:0}
.hubrow .hubs{display:block;font-weight:400;font-size:.82rem;color:var(--ink2)}
.hubrow::after{content:"›";color:var(--ink2);font-size:1.3rem;line-height:1;flex:none}
/* ===== explore: the directory of shared shelves ===== */
.exnudge{background:linear-gradient(180deg,#fffdf9,#fdf3ee)}
.exgrid{display:grid;grid-template-columns:1fr;gap:12px;margin-top:4px}
@media(min-width:640px){.exgrid{grid-template-columns:repeat(auto-fill,minmax(300px,1fr))}}
.excard{display:flex;flex-direction:column;gap:10px;padding:14px;text-decoration:none;color:inherit;
  background:var(--card);border:1px solid var(--line);border-radius:18px;box-shadow:var(--shadow-s);
  transition:transform .16s var(--ease-out),box-shadow .16s var(--ease-out),border-color .16s var(--ease-out)}
.excard:hover{transform:translateY(-2px);border-color:var(--coral);box-shadow:var(--shadow-m)}
.excard:active{transform:translateY(0)}
.exstrip{display:flex;align-items:flex-end;gap:6px;height:92px;padding:8px 10px 6px;border-radius:13px;
  background:radial-gradient(120% 100% at 50% 0%,#fffefb,#f2e6d3);box-shadow:inset 0 0 0 1px rgba(64,52,43,.06)}
.excut{flex:1 1 0;min-width:0;height:100%;display:flex;align-items:flex-end;justify-content:center}
.excut img{max-width:100%;max-height:100%;object-fit:contain;filter:drop-shadow(0 4px 4px rgba(64,52,43,.24))}
.excut.exemoji{font-size:2rem;align-items:center;opacity:.75}
.exmore{flex:none;align-self:center;font-size:.78rem;font-weight:800;color:var(--ink2)}
.exmeta{display:flex;align-items:baseline;justify-content:space-between;gap:10px;padding:0 2px}
.exname{font-family:var(--display);font-size:1.05rem;overflow-wrap:anywhere}
@media(prefers-reduced-motion:reduce){.excard{transition:none}}
/* ===== admin dashboard ===== */
.adlist{display:flex;flex-direction:column;gap:10px}
.adrow{display:grid;grid-template-columns:1.7fr 1fr 1fr auto;gap:12px;align-items:center;padding:12px 14px;background:var(--card);border:1px solid var(--line);border-radius:14px}
.adwho{display:flex;align-items:center;gap:10px;min-width:0}
.adwho b{overflow-wrap:anywhere}
.admeta,.addates{display:flex;flex-direction:column;gap:2px;font-size:.85rem}
.admeta span{white-space:nowrap}
.adact{justify-self:end}
.small{font-size:.75rem}
.adrow.banned{opacity:.65}
.banbadge{display:inline-block;background:#b3402a;color:#fff;font-size:.6rem;font-weight:800;letter-spacing:.04em;padding:2px 7px;border-radius:6px;vertical-align:middle}
@media(max-width:640px){.adrow{grid-template-columns:1fr auto}.admeta,.addates{grid-column:1/-1;flex-direction:row;flex-wrap:wrap;gap:6px 14px}}
/* admin moderation: per-user image grid */
.adbtns{margin-top:12px;display:flex;gap:8px;flex-wrap:wrap;align-items:center}
.adbtns form{margin:0}
.modgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(130px,1fr));gap:12px}
.modcard{background:var(--card);border:1px solid var(--line);border-radius:14px;padding:8px;display:flex;flex-direction:column;gap:6px}
.modimg{width:100%;aspect-ratio:1;border-radius:10px;overflow:hidden;background:#f0e8da;display:flex;align-items:center;justify-content:center}
.modimg img{width:100%;height:100%;object-fit:cover}
.modemoji{font-size:44px}
.modname{font-weight:700;font-size:.85rem;text-align:center;overflow-wrap:anywhere}
/* ===== marketing homepage ===== */
.hero{text-align:center;padding:6px 0 8px}
.hero h1{font-size:2.15rem;line-height:1.1;margin-bottom:12px;text-wrap:balance;font-weight:700}
.lede{font-size:1.05rem;color:var(--ink2);max-width:40ch;margin:0 auto 22px}
.ba{display:flex;align-items:center;justify-content:center;gap:12px;flex-wrap:wrap;margin:10px 0 22px}
.ba figure{margin:0;display:flex;flex-direction:column;align-items:center;gap:7px}
.ba figcaption{font-family:var(--hand);font-weight:700;font-size:1.2rem;color:var(--ink2)}
/* the "your photo" print: tilted, white-bordered, held down by a strip of washi */
.ba-before{position:relative;transform:rotate(-2.5deg)}
.ba-before::before{content:"";position:absolute;top:-10px;left:50%;transform:translateX(-50%) rotate(-4deg);width:72px;height:22px;border-radius:2px;z-index:2;
  background-color:rgba(214,167,92,.5);background-image:radial-gradient(rgba(255,255,255,.55) 1.5px,transparent 2px);background-size:10px 10px;box-shadow:0 2px 4px rgba(64,52,43,.14)}
.ba-after{transform:rotate(1.5deg)}
.ba-before img{width:150px;height:auto;border-radius:4px;box-shadow:0 10px 20px -8px rgba(64,52,43,.34);border:6px solid #fff;border-bottom-width:20px}
.ba-after img{height:190px;width:auto;object-fit:contain;filter:url(#pb-sticker) var(--glow,drop-shadow(0 0 0 transparent)) drop-shadow(0 12px 16px rgba(64,52,43,.24))}
.ba-arrow{font-size:1.6rem;color:var(--coral-d);font-weight:700}
.cta{font-size:1.05rem;padding:14px 22px}
.lblock{margin:38px 0}
.lblock h2{text-align:center;font-size:1.5rem;margin-bottom:18px}
/* hand-drawn coral swash under marketing section titles, the scrapbook signature */
.lblock h2::after,.finalcta h2::after{content:"";display:block;width:92px;height:10px;margin:6px auto 0;
  background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 92 10'%3E%3Cpath d='M2 7 C 18 3, 34 9, 47 5 S 76 3, 90 6' fill='none' stroke='%23E07A5F' stroke-width='3' stroke-linecap='round'/%3E%3C/svg%3E") no-repeat center/contain}
.lblock.band{background:var(--paper-2);border-radius:26px;padding:30px 22px;box-shadow:inset 0 1px 0 rgba(255,255,255,.55),inset 0 -1px 0 rgba(64,52,43,.04)}
.steps{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:14px}
.steps li{display:flex;gap:14px;align-items:flex-start;background:var(--card);border:1px solid var(--line);border-radius:16px;padding:16px;box-shadow:var(--shadow-s)}
.stepn{font-size:1.8rem;line-height:1;flex:none}
.steps b{display:block;margin-bottom:2px}
.steps p{margin:0;font-size:.92rem;color:var(--ink2)}
.why{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.whyc{background:var(--card);border:1px solid var(--line);border-radius:16px;padding:16px;box-shadow:var(--shadow-s)}
.whyc b{display:block;margin-bottom:4px;font-size:.98rem}
.whyc p{margin:0;font-size:.86rem;color:var(--ink2)}
.finalcta{position:relative;text-align:center;background:linear-gradient(150deg,#fdeee9,#fbf4ec);border:1px solid var(--line);border-radius:22px;padding:30px 20px;box-shadow:var(--shadow-m)}
.finalcta::before{content:"";position:absolute;top:-11px;left:50%;transform:translateX(-50%) rotate(-3deg);width:88px;height:24px;border-radius:2px;
  background:repeating-linear-gradient(45deg,rgba(122,158,127,.45) 0 8px,rgba(122,158,127,.22) 8px 16px);box-shadow:0 2px 4px rgba(64,52,43,.12)}
.finalcta h2{margin-bottom:16px}
.lfoot{text-align:center;color:var(--ink2);font-size:.8rem;margin:26px 0 6px}
/* pettable fur heart (canvas fur; see /fur.js) */
.petbox{margin:30px auto 4px;text-align:center}
.furheart{width:min(190px,46vw);aspect-ratio:1/1;margin:0 auto;cursor:grab}
.furheart:active{cursor:grabbing}
.petcap{font-family:var(--hand);font-weight:700;font-size:1.35rem;color:var(--ink2);margin:14px 0 0}
.fur{position:relative;display:block;overflow:visible;touch-action:pan-y;transition:transform 420ms cubic-bezier(.32,.72,0,1)}
.fur:hover{transform:scale(1.015) rotate(-.4deg)}
.fur-canvas{position:absolute;pointer-events:none}
@media(prefers-reduced-motion:reduce){.fur{transition:none}.fur:hover{transform:none}}
/* legal pages */
.legal h2{font-size:1.05rem;margin:22px 0 6px}
.legal p,.legal li{color:var(--ink2);font-size:.95rem}
.legal ul{margin:0 0 0 20px}
.legal a{color:var(--coral-d)}
.lfoot a{color:var(--coral-d);text-decoration:none}
@media(max-width:520px){.why{grid-template-columns:1fr}.hero h1{font-size:1.9rem}.ba-after img{height:160px}}
.sclink{color:var(--coral-d);font-weight:700;text-decoration:none;font-size:.95rem}
.sclink:hover{text-decoration:underline}
/* showcase display switcher, chips flip the stage between the real display renderers */
.scsw{display:flex;flex-wrap:wrap;gap:8px;justify-content:center;margin:4px 0 16px}
.scstage{max-width:980px;margin:0 auto}
.scstage [data-scpane][hidden]{display:none}
.scthemes{display:flex;gap:12px;justify-content:center;margin-top:14px}
.scth{width:30px;height:30px;border-radius:10px;border:0;box-shadow:inset 0 0 0 1px rgba(64,52,43,.14),inset 0 1px 0 rgba(255,255,255,.4);
  cursor:pointer;padding:0;position:relative;transition:transform .15s var(--ease-out),box-shadow .15s;touch-action:manipulation}
.scth::after{content:"";position:absolute;inset:-7px;border-radius:13px} /* 44px hit area */
.scth:hover{transform:scale(1.1)}
.scth.on{box-shadow:0 0 0 2px var(--paper),0 0 0 4px var(--coral-d),inset 0 0 0 1px rgba(64,52,43,.14)}
.scstories{display:flex;flex-direction:column;gap:12px;margin:0 0 8px}
.sccard{display:flex;gap:14px;align-items:flex-start;background:var(--card);border:1px solid var(--line);border-radius:16px;padding:16px;scroll-margin-top:16px;box-shadow:var(--shadow-s)}
.scdot{width:26px;height:26px;border-radius:50%;flex:none;margin-top:5px}
.sccard b.hand{font-size:1.7rem;display:block;line-height:1;margin:0}
.scmeta{font-size:.8125rem;color:var(--ink2);font-weight:600;text-transform:capitalize}
.sccard p{margin:6px 0 0;font-size:.9rem;color:var(--ink2)}
/* landing, desktop: a wide, balanced canvas (mobile keeps the centered column) */
.wrap.wrapwide{max-width:1040px}
@media(min-width:640px){
  .wrapwide .hero{padding:24px 0 12px}
  .wrapwide .hero h1{font-size:3rem;max-width:15ch;margin-inline:auto}
  .wrapwide .lede{font-size:1.15rem;max-width:48ch}
  .wrapwide .ba{gap:44px;margin:22px 0 30px}
  .wrapwide .ba-before img{width:220px}
  .wrapwide .ba-after img{height:280px}
  .wrapwide .ba-arrow{font-size:2.4rem}
  .wrapwide .cta{max-width:440px;margin-inline:auto;font-size:1.1rem}
  .wrapwide .lblock{max-width:960px;margin-left:auto;margin-right:auto}
  .wrapwide .lblock h2{font-size:1.9rem;margin-bottom:24px}
  .wrapwide .steps{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:16px}
  .wrapwide .why{grid-template-columns:repeat(4,minmax(0,1fr))}
  .wrapwide .finalcta{max-width:760px;margin-left:auto;margin-right:auto;padding:36px}
}
