/* ═══════════════════════════════════════════
   VITONIZE — CREATE APP
   Built on the marketing site's tokens (styles.css loads first) but
   with its own component set: top bar, horizontal stepper, upload
   stage with a tips sidebar, model grid, background picker, summary,
   plus the saved-uploads shelf.
   ═══════════════════════════════════════════ */

.app-body{background:var(--wash);min-height:100vh;}

/* ═══ TOP NAV ═══
   Frosted glass over whatever scrolls beneath it, a hairline instead of a
   shadow, and the destinations split into two weights: the four places you
   work (Explore, Image, Video, Edit) read as primary, the generators and
   tools sit quieter in a rail beside them. Whitespace does the grouping;
   only one hairline divider survives. The row scrolls sideways rather than
   wrapping, so its height never changes as items are added. */
.anav{
  position:sticky;top:0;z-index:60;
  background:var(--a-nav-glass);
  backdrop-filter:blur(22px) saturate(180%);
  -webkit-backdrop-filter:blur(22px) saturate(180%);
  border-bottom:1px solid var(--a-line);
}
.anav-in{
  display:flex;align-items:center;gap:14px;
  height:60px;padding:0 20px;
  max-width:1720px;margin:0 auto;
}

/* ── logo ───────────────────────────────────── */
.anav-logo{
  display:flex;flex-direction:row;align-items:center;gap:.42em;
  line-height:1;flex:0 0 auto;padding-right:4px;
  color:var(--a-ink);
}
.anav-logo .nav-logo-main{
  font-size:15px;font-weight:700;letter-spacing:-.01em;color:var(--a-ink);
}
.anav-logo .nav-logo-sub{
  font-size:7.5px;font-weight:600;letter-spacing:.36em;
  color:var(--a-mute);padding-top:3px;
}

/* ── destinations ───────────────────────────── */
.anav-links{
  display:flex;align-items:center;gap:2px;
  /* Stretched to the full bar rather than shrink-wrapped to the labels.
     overflow-x:auto forces overflow-y to auto too, so a row sized to the
     links themselves clips anything drawn above them — and the marker
     drops in from above. Stretching gives it 14px of headroom. */
  align-self:stretch;
  flex:1 1 auto;min-width:0;
  overflow-x:auto;scrollbar-width:none;
  /* the fade tells you the row continues, without drawing a control */
  -webkit-mask-image:linear-gradient(to right,transparent,#000 14px,#000 calc(100% - 30px),transparent);
  mask-image:linear-gradient(to right,transparent,#000 14px,#000 calc(100% - 30px),transparent);
  padding:0 2px;
}
.anav-links::-webkit-scrollbar{height:0;}

/* one hairline, between "where you work" and "what you make" */
.anav-div{
  flex:0 0 auto;width:1px;height:18px;margin:0 10px;
  background:var(--a-line);
}
.anav-div + .anav-link ~ .anav-div{margin:0 12px;}

.anav-link{
  position:relative;flex:0 0 auto;white-space:nowrap;
  display:flex;align-items:center;gap:6px;
  padding:7px 11px;border-radius:9px;
  font-size:13.5px;font-weight:500;letter-spacing:-.01em;
  color:var(--a-nav-ink);
  transition:color .18s var(--ease),background-color .18s var(--ease);
}
/* No pill, on hover or otherwise. The row is a line of words; the only
   thing that should change is how present a word is — muted to full ink.
   A grey slab behind the label adds a shape the rest of the bar never
   uses, and with fourteen links it turns the row into a strip of boxes. */
.anav-link:hover{color:var(--a-ink);background:transparent;}

/* The current page keeps the ink and the weight, and takes a short yellow
   rule under the word. One marker, and it is the accent doing the work. */
.anav-link.is-on{
  color:var(--a-ink);font-weight:600;
  background:transparent;box-shadow:none;
}
/* The marker is a rolling wave rather than a rule. It is painted as a
   solid bar of the accent and then MASKED to a wave, so the colour still
   comes from --vz-acc and follows the theme — a wave drawn directly into
   the SVG would freeze one hard-coded yellow into the file.

   The tile is one full period, 18px wide, and the mask simply scrolls by
   exactly one tile: at the end of the cycle the wave is back where it
   started, so the loop has no seam. Where mask-image is unsupported the
   ::after degrades to a solid 6px bar, which is still a clear marker. */
/* Two layers. The wave rolls through ONCE on arrival and fades out; the
   plain rule draws in underneath it and is what remains. A wave that
   loops forever pulls the eye away from the page for as long as you are
   on it — as a single arrival gesture it does its job and then gets out
   of the way. */
/* ── the marker: DROPLET ────────────────────
   A bead of yellow falls from above the bar, passes through the word and
   colours the letters as it goes, then hits bottom and flattens out into
   the rule that stays. It plays once, on arrival, and then the item is
   simply a word with a line under it.

   Three parts, one shared timeline: the bead (::before), the painted
   letters (.anav-t::after) and the rule (::after). */
.anav-link.is-on::before{
  content:"";position:absolute;left:50%;top:-10px;
  width:8px;height:8px;margin-left:-4px;border-radius:50%;
  background:var(--vz-acc);opacity:0;pointer-events:none;
  animation:drop-fall .92s cubic-bezier(.55,0,.35,1) both;
}
/* the yellow copy of the label, stacked exactly over the ink one and
   revealed top-down as the bead passes through it */
.anav-t{position:relative;display:inline-block;}
.anav-link.is-on .anav-t::after{
  content:attr(data-t);
  position:absolute;left:0;top:0;width:100%;
  color:var(--vz-acc);
  clip-path:inset(0 0 100% 0);
  pointer-events:none;
  animation:drop-splash .92s cubic-bezier(.55,0,.35,1) both;
}
/* what remains once the bead has landed */
.anav-link.is-on::after{
  content:"";position:absolute;left:8px;right:8px;bottom:2px;
  height:3px;border-radius:3px;
  background:var(--vz-acc);
  transform-origin:center;
  animation:drop-rule .92s cubic-bezier(.3,.9,.3,1) both;
}
[data-app="dark"] .anav-link.is-on::after{
  box-shadow:0 0 6px color-mix(in srgb,var(--vz-acc) 45%,transparent);
}

@keyframes drop-fall{
  0%  {opacity:0;transform:translateY(0) scale(.6);}
  14% {opacity:1;transform:translateY(3px) scale(1);}
  50% {opacity:1;transform:translateY(22px) scaleX(1.4) scaleY(.72);}
  72% {opacity:1;transform:translateY(33px) scaleX(6) scaleY(.26);}
  100%{opacity:0;transform:translateY(35px) scaleX(10) scaleY(.14);}
}
/* the letters take the colour only while the bead is passing over them */
@keyframes drop-splash{
  0%,44%{clip-path:inset(0 0 100% 0);}
  60%   {clip-path:inset(0 0 0 0);}
  100%  {clip-path:inset(0 0 100% 0);}
}
@keyframes drop-rule{
  0%,64%{transform:scaleX(0);opacity:0;}
  100%  {transform:scaleX(1);opacity:1;}
}
[data-app="dark"] .anav-link.is-on::after{
  box-shadow:0 0 6px color-mix(in srgb,var(--vz-acc) 45%,transparent);
}

/* Explore is the one link that carries the brand colour. It cannot wear it
   as text on a light bar — yellow on white measures 1.7:1 — so it wears it
   as a tinted pill with dark ink instead, the same trick the badges use. */
.anav-explore{
  color:var(--vz-acc-ink);font-weight:600;
  background:color-mix(in srgb,var(--vz-acc) 62%,transparent);
}
.anav-explore:hover{
  color:var(--vz-acc-ink);
  background:var(--vz-acc);
}

.anav-badge{
  font-style:normal;font-size:8px;font-weight:700;
  letter-spacing:.07em;text-transform:uppercase;
  padding:2.5px 5px;border-radius:5px;line-height:1;
  background:var(--vz-acc);
  color:var(--vz-acc-ink);
}

/* ── right cluster ──────────────────────────── */
.anav-right{display:flex;align-items:center;gap:7px;flex:0 0 auto;padding-left:4px;}
.anav-icon{
  width:34px;height:34px;border-radius:10px;cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  color:var(--a-nav-ink);
  transition:background-color .18s var(--ease),color .18s var(--ease);
}
.anav-icon svg{width:16px;height:16px;}
.anav-icon:hover{background:var(--a-chip);color:var(--a-ink);}

.anav-upgrade,.anav-assets{
  display:flex;align-items:center;gap:7px;white-space:nowrap;
  height:34px;padding:0 14px;border-radius:10px;
  font-size:13px;font-weight:600;letter-spacing:-.01em;
  transition:transform .18s var(--ease),box-shadow .18s var(--ease),
             background-color .18s var(--ease);
}
.anav-upgrade svg,.anav-assets svg{width:14px;height:14px;}

/* the one saturated thing on the bar, so it reads as the one offer */
.anav-upgrade{
  background:linear-gradient(180deg,var(--vz-acc),var(--vz-acc-2));
  color:var(--vz-acc-ink);
  text-shadow:0 1px 0 rgba(255,255,255,.3);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.45),
    inset 0 -1px 0 rgba(0,0,0,.12),
    0 1px 2px rgba(0,0,0,.12),
    0 6px 18px -8px color-mix(in srgb,var(--vz-acc) 80%,transparent);
}
.anav-upgrade:hover{
  transform:translateY(-1px);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.5),
    inset 0 -1px 0 rgba(0,0,0,.12),
    0 2px 4px rgba(0,0,0,.12),
    0 12px 26px -10px color-mix(in srgb,var(--vz-acc) 85%,transparent);
}

.anav-assets{
  background:transparent;color:var(--a-ink);
  box-shadow:inset 0 0 0 1px var(--a-line);
}
.anav-assets:hover{background:var(--a-chip);}
.anav-assets.is-on{
  background:var(--a-btn);color:var(--a-btn-ink);
  box-shadow:inset 0 0 0 1px transparent;
}

.anav-credits{
  display:flex;align-items:center;gap:5px;
  height:34px;padding:0 12px;border-radius:100px;
  background:var(--a-chip);color:var(--a-nav-ink);
  font-size:12.5px;font-variant-numeric:tabular-nums;
}
.anav-credits b{color:var(--a-ink);font-weight:600;}
.anav-credits::before{content:"◆";font-size:8.5px;color:var(--vz-acc);}

.anav .app-avatar{
  width:34px;height:34px;flex:0 0 auto;
  background:linear-gradient(135deg,var(--vz-acc),var(--vz-acc-2));
  color:var(--vz-acc-ink);
  font-size:12px;font-weight:700;
  box-shadow:0 0 0 1px var(--a-line),0 1px 3px rgba(0,0,0,.16);
  transition:box-shadow .18s var(--ease);
}
.anav .app-avatar:hover{box-shadow:0 0 0 2px var(--vz-acc),0 2px 6px rgba(0,0,0,.2);}

@media (max-width:1100px){
  .anav-credits{display:none;}
}
@media (max-width:820px){
  .anav-in{gap:10px;padding:0 12px;}
  .anav-upgrade span,.anav-assets span{display:none;}
  .anav-upgrade,.anav-assets{padding:0 11px;}
  .anav-logo .nav-logo-sub{display:none;}
}

/* ── top bar ──────────────────────────────── */
.app-bar{
  position:sticky;top:0;z-index:40;
  background:rgba(255,255,255,.86);backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);
  border-bottom:1px solid var(--line);
}
.app-bar-inner{
  max-width:1400px;margin:0 auto;padding:0 24px;height:64px;
  display:flex;align-items:center;gap:40px;
}
.app-bar-nav{display:flex;align-items:center;gap:28px;margin-right:auto;}
.app-bar-nav a{
  font-size:14px;font-weight:500;color:var(--ink-mute);
  padding:8px 2px;position:relative;
  transition:color .3s var(--ease);
}
.app-bar-nav a::after{
  content:"";position:absolute;left:0;right:0;bottom:0;height:2px;
  background:var(--ink-strong);transform:scaleX(0);transform-origin:left;
  transition:transform .35s var(--ease);
}
.app-bar-nav a:hover{color:var(--ink-strong);}
.app-bar-nav a.is-active{color:var(--ink-strong);}
.app-bar-nav a.is-active::after{transform:scaleX(1);}
.app-bar-right{display:flex;align-items:center;gap:14px;}
.app-credits{
  display:inline-flex;align-items:center;gap:7px;
  padding:8px 14px;border-radius:100px;
  background:var(--accent-soft);color:var(--accent-text);
  font-size:13px;font-weight:500;
}
.app-credits svg{width:13px;height:13px;color:var(--accent);}
.app-credits b{font-weight:700;color:var(--accent-text);}
.app-avatar{
  width:34px;height:34px;border-radius:50%;overflow:hidden;
  background:var(--ink-strong);color:var(--white);
  display:flex;align-items:center;justify-content:center;
  font-size:13px;font-weight:600;
  transition:transform .3s var(--ease);
}
.app-avatar:hover{transform:scale(1.06);}
.app-avatar img{width:100%;height:100%;object-fit:cover;}

/* ── stepper ──────────────────────────────── */
.app-stepper-w{background:var(--white);border-bottom:1px solid var(--line);}
.app-stepper{
  display:flex;align-items:center;gap:0;
  padding:20px 24px;overflow-x:auto;
}
.app-step{
  display:flex;align-items:center;gap:9px;flex:0 0 auto;
  color:var(--ink-mute);white-space:nowrap;
  transition:color .3s var(--ease);
}
.app-step-num{
  position:relative;
  width:24px;height:24px;border-radius:50%;flex:0 0 auto;
  display:flex;align-items:center;justify-content:center;
  font-size:11.5px;font-weight:600;
  background:var(--wash);color:var(--ink-mute);
  transition:background-color .3s var(--ease),color .3s var(--ease),transform .3s var(--ease);
}
.app-step-label{font-size:14px;font-weight:500;}
.app-step.is-active{color:var(--ink-strong);}
.app-step.is-active .app-step-num{background:var(--ink-strong);color:var(--white);transform:scale(1.08);}
.app-step.is-done:not(.is-active) .app-step-num{background:var(--accent);color:transparent;}
.app-step.is-done:not(.is-active) .app-step-num::before{
  content:"✓";position:absolute;inset:0;display:flex;align-items:center;justify-content:center;color:var(--white);
}
.app-step.is-done:not(.is-active) .app-step-label{color:var(--ink);}
.app-step-rail{
  width:36px;height:1px;flex:0 0 36px;margin:0 12px;
  background:var(--line);
}
@media (min-width:600px){.app-step-rail{width:56px;flex-basis:56px;}}

/* ── panels ───────────────────────────────── */
.app-main{padding:30px 0 0;}
.app-panel{display:none;}
.app-panel.is-active{display:block;animation:panelIn .5s var(--ease);}
@keyframes panelIn{from{opacity:0;transform:translateY(14px);}to{opacity:1;transform:translateY(0);}}

/* The heading was sized for a poster. On the step that matters most —
   twenty faces to choose between — it and its subtitle took a third of
   the window before a single face appeared. Smaller, tighter, and the
   first row is on screen when the step opens. */
.app-panel-head{max-width:620px;margin:0 auto 18px;text-align:center;}
.app-panel-title{
  font-size:27px;line-height:1.2;font-weight:500;letter-spacing:-.6px;color:var(--ink-strong);
}
.app-panel-sub{font-size:13.5px;line-height:1.5;color:var(--ink-mute);padding:7px 0 0;}

/* ── upload stage + tips sidebar ──────────── */
.app-stage-c{
  display:grid;grid-template-columns:1fr 300px;gap:32px;align-items:start;
  padding-bottom:16px;
}
.app-stage{
  background:var(--white);border-radius:20px;overflow:hidden;
  box-shadow:0 30px 60px -40px rgba(0,0,0,.25);
  min-height:360px;display:flex;
}
.app-upload{width:100%;display:flex;}
.app-upload-empty{margin:auto;text-align:center;max-width:400px;padding:60px 32px;}
.app-upload-ic{
  width:64px;height:64px;margin:0 auto 22px;border-radius:50%;
  background:var(--accent-soft);color:var(--accent);
  display:flex;align-items:center;justify-content:center;
}
.app-upload-ic svg{width:30px;height:30px;}
.app-upload-title{font-size:22px;font-weight:500;letter-spacing:-.4px;color:var(--ink-strong);}
.app-upload-sub{font-size:14.5px;line-height:1.55;color:var(--ink-mute);padding:10px 0 22px;}
.app-upload-btn{cursor:pointer;}
.app-upload-hint{display:block;font-size:12.5px;color:var(--ink-mute);padding-top:14px;}

.app-upload-grid{
  width:100%;padding:24px;
  display:grid;grid-template-columns:repeat(auto-fill,minmax(120px,1fr));gap:14px;
  align-content:start;
}
.app-upload-item{
  position:relative;aspect-ratio:3/4;border-radius:12px;overflow:hidden;
  background:var(--wash);box-shadow:0 14px 30px -18px rgba(0,0,0,.3);
  animation:panelIn .4s var(--ease);
}
.app-upload-item img{width:100%;height:100%;object-fit:cover;}
.app-upload-remove{
  position:absolute;top:6px;right:6px;width:24px;height:24px;border-radius:50%;
  background:rgba(12,12,12,.7);backdrop-filter:blur(6px);color:var(--white);
  display:flex;align-items:center;justify-content:center;font-size:13px;line-height:1;
  transition:background-color .25s var(--ease),transform .25s var(--ease);
}
.app-upload-remove:hover{background:var(--ink-strong);transform:scale(1.08);}
.app-upload-add{
  aspect-ratio:3/4;border-radius:12px;border:1.5px dashed var(--line);
  display:flex;align-items:center;justify-content:center;
  color:var(--ink-mute);font-size:26px;font-weight:300;cursor:pointer;
  transition:border-color .3s var(--ease),color .3s var(--ease),background-color .3s var(--ease);
}
.app-upload-add:hover{border-color:var(--accent);color:var(--accent);background:var(--accent-soft);}

.app-tips{display:flex;flex-direction:column;gap:28px;}
.app-tips-block h3{font-size:14.5px;font-weight:600;color:var(--ink-strong);}
.app-tips-block p{font-size:13px;line-height:1.5;color:var(--ink-mute);padding-top:6px;}
.app-tips-row{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;padding-top:14px;}
.app-tip-thumb{position:relative;aspect-ratio:3/4;border-radius:8px;overflow:hidden;background:var(--wash);}
.app-tip-thumb img{width:100%;height:100%;object-fit:cover;}
.app-tip-badge{
  position:absolute;top:5px;right:5px;width:18px;height:18px;border-radius:50%;
  display:flex;align-items:center;justify-content:center;font-size:10px;font-weight:700;
  color:var(--white);
}
.app-tip-badge.is-good{background:#2d7349;}
.app-tips-list{list-style:none;margin:0;padding:14px 0 0;display:flex;flex-direction:column;gap:9px;}
.app-tips-list li{font-size:13px;color:var(--ink-mute);padding-left:18px;position:relative;}
.app-tips-list li::before{
  content:"";position:absolute;left:0;top:7px;width:7px;height:7px;border-radius:50%;
  background:#c1503f;opacity:.55;
}

/* ── saved uploads shelf ──────────────────── */
.app-lib{
  background:var(--white);border-radius:20px;padding:18px 22px 20px;
  box-shadow:0 30px 60px -40px rgba(0,0,0,.25);
  margin-bottom:8px;
}
.app-lib-head{display:flex;align-items:center;justify-content:space-between;gap:16px;padding-bottom:14px;}
.app-lib-title{font-size:15px;font-weight:600;letter-spacing:-.2px;color:var(--ink-strong);}
.app-lib-sub{font-size:12px;line-height:1.5;color:var(--ink-mute);padding-top:2px;max-width:460px;}
.app-lib-count{
  flex:0 0 auto;font-size:11.5px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;
  color:var(--accent-text);background:var(--accent-soft);padding:5px 11px;border-radius:100px;
}
.app-lib-grid{
  display:flex;gap:10px;overflow-x:auto;overflow-y:hidden;
  padding-bottom:6px;scroll-snap-type:x proximity;scrollbar-width:thin;
}
.app-lib-grid::-webkit-scrollbar{height:6px;}
.app-lib-grid::-webkit-scrollbar-thumb{border-radius:100px;background:var(--a-line,rgba(0,0,0,.18));}
.app-lib-grid::-webkit-scrollbar-track{background:transparent;}
.app-lib-empty{
  grid-column:1/-1;font-size:13px;color:var(--ink-mute);
  padding:20px;text-align:center;border-radius:12px;background:var(--wash);
}
.app-lib-item{position:relative;flex:0 0 84px;scroll-snap-align:start;}
.app-lib-pick{
  display:block;width:100%;aspect-ratio:1/1;border-radius:11px;overflow:hidden;
  background:var(--wash);position:relative;
  transition:transform .3s var(--ease),box-shadow .3s var(--ease);
}
.app-lib-pick img{width:100%;height:100%;object-fit:cover;transition:filter .3s var(--ease);}
.app-lib-pick:hover{transform:translateY(-3px);box-shadow:0 16px 26px -16px rgba(0,0,0,.42);}
.app-lib-pick:hover img{filter:brightness(.62);}
.app-lib-plus{
  position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
  color:var(--white);font-size:22px;line-height:1;
  opacity:0;transition:opacity .3s var(--ease);
}
.app-lib-pick:hover .app-lib-plus{opacity:1;}
.app-lib-x{
  position:absolute;top:5px;right:5px;width:21px;height:21px;border-radius:50%;
  background:rgba(12,12,12,.68);backdrop-filter:blur(6px);color:var(--white);
  display:flex;align-items:center;justify-content:center;font-size:10px;
  opacity:0;transition:opacity .25s var(--ease),background-color .25s var(--ease);
}
.app-lib-item:hover .app-lib-x{opacity:1;}
.app-lib-x:hover{background:#b4553f;}

/* ── tabs (gender + background mode) ──────── */
.app-gender-tabs{
  display:inline-flex;gap:4px;margin:20px auto 0;padding:4px;
  background:var(--white);border-radius:100px;box-shadow:inset 0 0 0 1px var(--line);
}
.app-gender-tabs button{
  padding:9px 20px;border-radius:100px;font-size:13.5px;font-weight:500;color:var(--ink-mute);
  transition:background-color .3s var(--ease),color .3s var(--ease);
}
.app-gender-tabs button.is-active{background:var(--ink-strong);color:var(--white);}

/* ── model grid ───────────────────────────── */
.app-model-grid{
  display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:16px;
  padding-bottom:8px;
}
.app-model-card{
  position:relative;display:block;border-radius:16px;overflow:hidden;
  background:var(--white);box-shadow:0 20px 40px -28px rgba(0,0,0,.25);
  transition:transform .35s var(--ease),box-shadow .35s var(--ease);
}
.app-model-card:hover{transform:translateY(-4px);box-shadow:0 28px 50px -26px rgba(0,0,0,.35);}
.app-model-img{display:block;aspect-ratio:3/4;background:var(--wash);}
.app-model-img img{width:100%;height:100%;object-fit:cover;transition:transform .8s var(--ease),filter .4s var(--ease);}
.app-model-card:hover .app-model-img img{transform:scale(1.05);}
.app-model-name{
  display:block;padding:11px 4px;text-align:center;
  font-size:13.5px;font-weight:500;color:var(--ink);
}
.app-model-card.is-selected{box-shadow:0 0 0 2.5px var(--ink-strong),0 20px 40px -28px rgba(0,0,0,.35);}
.app-model-card.is-selected::after{
  content:"✓";position:absolute;top:9px;right:9px;width:24px;height:24px;border-radius:50%;
  background:var(--ink-strong);color:var(--white);font-size:12px;font-weight:700;
  display:flex;align-items:center;justify-content:center;z-index:2;
}
.app-model-card.is-locked{cursor:not-allowed;}
.app-model-card.is-locked .app-model-img img{filter:grayscale(.35) brightness(.72);}
.app-model-lock{
  position:absolute;left:0;right:0;bottom:38px;
  display:flex;align-items:center;justify-content:center;gap:5px;
  padding:9px 0;font-size:11px;font-weight:600;letter-spacing:.02em;color:var(--white);
  background:linear-gradient(0deg,rgba(0,0,0,.55),rgba(0,0,0,0) 85%);
}
.app-model-lock svg{width:12px;height:12px;}
.app-locknote{font-size:13px;color:var(--ink-mute);padding-top:18px;text-align:center;}

/* ── pose placeholder ─────────────────────── */
.app-pose-grid{
  display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:16px;
}
.app-pose-card{
  position:relative;aspect-ratio:3/4;border-radius:16px;overflow:hidden;background:var(--wash);
  box-shadow:0 20px 40px -28px rgba(0,0,0,.25);
}
.app-pose-card img{width:100%;height:100%;object-fit:cover;object-position:center 18%;filter:grayscale(.4) blur(1.5px) brightness(.85);}
.app-pose-soon{
  position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
  font-size:12.5px;font-weight:600;letter-spacing:.03em;color:var(--white);
  background:rgba(12,12,12,.32);
}

/* ── background picker ────────────────────── */
.app-bg-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;}
.app-bg-swatch{
  position:relative;aspect-ratio:3/4;border-radius:16px;overflow:hidden;
  display:flex;align-items:flex-end;
  box-shadow:0 20px 40px -28px rgba(0,0,0,.3);
  transition:transform .35s var(--ease),box-shadow .35s var(--ease);
}
.app-bg-swatch:hover{transform:translateY(-4px);}
.app-bg-swatch span{
  position:relative;z-index:2;padding:12px;font-size:12px;font-weight:600;letter-spacing:.02em;
  color:#fff;text-shadow:0 1px 6px rgba(0,0,0,.5);
}
.app-bg-swatch.studio{background:linear-gradient(170deg,#fdfdfd,#e4e1dd);}
.app-bg-swatch.studio span{color:#5c5854;text-shadow:none;}
.app-bg-swatch.sand{background:linear-gradient(170deg,#e8cbaa,#c08e5e);}
.app-bg-swatch.concrete{background:linear-gradient(170deg,#b9bcbd,#71767a);}
.app-bg-swatch.editorial{background:linear-gradient(170deg,#3a3734,#111);}
.app-bg-swatch.is-active{box-shadow:0 0 0 2.5px var(--ink-strong),0 20px 40px -28px rgba(0,0,0,.35);}
.app-bg-swatch.is-active::before{
  content:"✓";position:absolute;top:10px;right:10px;z-index:3;
  width:22px;height:22px;border-radius:50%;background:var(--white);color:var(--ink-strong);
  font-size:11px;font-weight:700;display:flex;align-items:center;justify-content:center;
}

.app-prompt-field{display:block;max-width:640px;margin:0 auto;}
.app-prompt-label{display:block;font-size:13px;font-weight:600;color:var(--ink-strong);padding-bottom:10px;}
.app-prompt-field textarea{
  width:100%;padding:16px 18px;border-radius:14px;resize:vertical;
  background:var(--white);box-shadow:inset 0 0 0 1px var(--line);
  font-family:inherit;font-size:15px;line-height:1.55;color:var(--ink);
  transition:box-shadow .3s var(--ease);
}
.app-prompt-field textarea:focus{outline:none;box-shadow:inset 0 0 0 1.5px var(--ink-strong);}
.app-prompt-field textarea::placeholder{color:var(--ink-mute);}

/* ── mood + crop (editorial) ──────────────── */
.app-chips{display:flex;flex-wrap:wrap;gap:9px;justify-content:center;padding-bottom:22px;}
.app-chip{
  padding:10px 16px;border-radius:100px;font-size:13.5px;color:var(--ink);
  background:var(--white);box-shadow:inset 0 0 0 1px var(--line);
  transition:background-color .3s var(--ease),color .3s var(--ease);
}
.app-chip:hover{background:var(--accent-soft);}
.app-chip.is-active{background:var(--ink-strong);color:var(--white);box-shadow:none;}
.app-ratios{display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:12px;padding-top:24px;max-width:640px;margin:0 auto;}
.app-ratio{
  display:flex;flex-direction:column;align-items:center;gap:6px;
  padding:16px 10px;border-radius:14px;background:var(--white);
  box-shadow:inset 0 0 0 1px var(--line);
  transition:box-shadow .3s var(--ease);
}
.app-ratio b{font-size:13.5px;font-weight:600;color:var(--ink-strong);}
.app-ratio em{font-size:11.5px;font-style:normal;color:var(--ink-mute);}
.app-ratio.is-active{box-shadow:inset 0 0 0 2px var(--ink-strong);}
.app-ratio-box{display:block;background:#dedbd8;border-radius:3px;}
.app-ratio-box.r45{width:26px;height:32px;}
.app-ratio-box.r11{width:30px;height:30px;}
.app-ratio-box.r916{width:20px;height:35px;}
.app-ratio-box.r169{width:38px;height:22px;}
.app-ratio.is-active .app-ratio-box{background:var(--ink-strong);}

/* ── summary ──────────────────────────────── */
.app-summary-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:20px;}
.app-summary-card{
  background:var(--white);border-radius:16px;padding:22px;
  box-shadow:0 20px 40px -28px rgba(0,0,0,.25);
}
.app-summary-card h3{font-size:13px;font-weight:600;color:var(--ink-mute);text-transform:uppercase;letter-spacing:.05em;}
.app-summary-thumbs{display:flex;flex-wrap:wrap;gap:8px;padding-top:14px;}
.app-summary-thumbs img{width:52px;height:52px;border-radius:8px;object-fit:cover;}
.app-summary-model{display:flex;align-items:center;gap:12px;padding-top:14px;}
.app-summary-model img{width:52px;height:52px;border-radius:50%;object-fit:cover;}
.app-summary-model b{font-size:15px;font-weight:500;color:var(--ink-strong);}
.app-summary-text{padding-top:14px;font-size:15px;line-height:1.5;color:var(--ink-strong);}
.app-summary-empty{font-size:14px;color:var(--ink-mute);padding-top:14px;display:block;}

/* ── actions ──────────────────────────────── */
/* ── Back and Continue, always on screen ──
   The panel is as tall as its longest step, and on a laptop that put
   Continue below the fold: you filled a step in, then had to go looking
   for the way out of it. Sticky rather than fixed, so on a step that
   does fit it sits where it belongs at the end of the content, and on
   one that does not it rides the bottom of the window instead.

   It needs its own background — it is passing over the content, and a
   transparent bar with text sliding under it is worse than the scroll
   was. The shadow above it says the same thing more quietly. */
.app-actions{
  position:sticky;bottom:0;z-index:5;
  display:flex;align-items:center;gap:18px;
  padding:16px 0 20px;border-top:1px solid var(--line);margin-top:26px;
  background:var(--a-bg,var(--bg,#fff));
}
.app-actions::before{
  content:'';position:absolute;left:0;right:0;bottom:100%;height:22px;
  pointer-events:none;
  background:linear-gradient(to top,var(--a-bg,var(--bg,#fff)),transparent);
}
.app-actions-hint{font-size:13.5px;color:var(--ink-mute);margin-right:auto;}
.app-next[disabled]{opacity:.4;pointer-events:none;}

/* ── toast ────────────────────────────────── */
/* z-index 9600, not 80. Every modal in the studio sits at 90 or above,
   so an error raised from inside one was drawn behind it: the template
   panel ran, failed, stopped its spinner and said nothing at all,
   because what it said was underneath. A notification belongs above
   whatever raised it — there is nothing it could usefully hide. */
.app-toast{
  position:fixed;left:50%;bottom:32px;z-index:9600;
  transform:translate(-50%,20px);opacity:0;pointer-events:none;
  background:var(--ink-strong);color:var(--white);
  padding:14px 26px;border-radius:100px;font-size:14px;font-weight:500;
  box-shadow:0 20px 40px -16px rgba(0,0,0,.5);
  transition:transform .4s var(--ease),opacity .4s var(--ease);
}
.app-toast.is-visible{transform:translate(-50%,0);opacity:1;}

/* ═══ HUB (generator picker) ════════════════ */
.hub-main{padding:60px 0 90px;}
.hub-head{max-width:660px;margin-bottom:44px;}
.hub-eyebrow{
  display:inline-block;padding:6px 13px;border-radius:100px;margin-bottom:18px;
  background:var(--accent-soft);color:var(--accent-text);
  font-size:12px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;
}
.hub-title{font-size:44px;line-height:1.08;font-weight:500;letter-spacing:-1.5px;color:var(--ink-strong);}
.hub-dot{color:var(--accent);}
.hub-sub{font-size:17px;line-height:1.55;color:var(--ink-mute);padding-top:14px;}

/* ═══ COMPOSER ═══
   A dark slab in an otherwise light app. That contrast is deliberate:
   it is the one place you type rather than click, so it should read as
   a different surface, not another card. */
.cmp{margin:0 0 52px;}

.cmp-suggest{
  display:flex;gap:9px;overflow-x:auto;padding:0 0 14px;
  scrollbar-width:none;
  -webkit-mask-image:linear-gradient(to right,#000 calc(100% - 48px),transparent);
  mask-image:linear-gradient(to right,#000 calc(100% - 48px),transparent);
}
.cmp-suggest::-webkit-scrollbar{height:0;}
.cmp-chip{
  flex:0 0 auto;white-space:nowrap;cursor:pointer;
  padding:9px 16px;border-radius:100px;
  background:var(--white);box-shadow:inset 0 0 0 1px var(--line);
  font-size:13px;color:var(--ink);
  transition:transform .25s var(--ease),box-shadow .25s var(--ease);
}
.cmp-chip:hover{transform:translateY(-1px);box-shadow:inset 0 0 0 1px #d6d2ce,0 6px 16px -10px rgba(0,0,0,.3);}

.cmp-box{
  position:relative;
  padding:20px 20px 14px;
  border-radius:22px;
  background:var(--a-panel);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.07),
    0 1px 2px rgba(0,0,0,.3),
    0 30px 60px -34px rgba(0,0,0,.75);
}
.cmp-srlabel{
  position:absolute;width:1px;height:1px;overflow:hidden;
  clip:rect(0 0 0 0);white-space:nowrap;
}
.cmp-input{
  display:block;width:100%;
  padding:2px 54px 0 4px;
  border:0;background:transparent;resize:none;
  font-family:inherit;font-size:16px;line-height:1.5;color:var(--a-ink);
  min-height:30px;max-height:220px;
}
.cmp-input::placeholder{color:var(--a-mute);}
.cmp-input:focus{outline:none;}

.cmp-refs{display:flex;flex-wrap:wrap;gap:8px;padding:14px 0 0;}
.cmp-ref{
  position:relative;
  width:62px;height:62px;border-radius:12px;
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;
  overflow:hidden;flex:0 0 auto;
}
.cmp-ref-add{
  cursor:pointer;
  border:1px dashed var(--a-line);color:var(--a-mute);
  font-size:9.5px;letter-spacing:.02em;
  transition:border-color .25s var(--ease),color .25s var(--ease);
}
.cmp-ref-add svg{width:15px;height:15px;}
.cmp-ref-add:hover,.cmp-ref-add:focus-visible{border-color:var(--a-btn-ink);color:var(--a-ink);outline:none;}
.cmp-ref-add[hidden]{display:none;}
.cmp-ref-item img{width:100%;height:100%;object-fit:cover;}
/* The whole thumbnail is the remove button. A 15px circle in the corner
   of a 42px tile is a target you have to aim at, and there is nothing
   else on a reference thumbnail to click — so the button fills it and the
   cross sits in the middle of the scrim. */
.cmp-ref-x{
  position:absolute;inset:0;border-radius:inherit;cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  background:rgba(6,6,7,.62);color:#fff;
  font-size:16px;line-height:1;
  opacity:0;transition:opacity .18s var(--ease),background-color .18s var(--ease);
}
.cmp-ref-item:hover .cmp-ref-x,
.cmp-ref-x:focus-visible{opacity:1;}
.cmp-ref-x:focus-visible{outline:2px solid var(--vz-acc);outline-offset:-2px;}
.cmp-ref-x:active{background:rgba(6,6,7,.76);}
/* No hover to reveal it, so the tile would look inert. It stays fully
   tappable and wears a small corner mark instead of a permanent scrim
   over every thumbnail. */
@media (hover:none){
  .cmp-ref-x{opacity:1;background:transparent;font-size:0;}
  .cmp-ref-x::after{
    content:"\2715";
    position:absolute;top:2px;right:2px;
    width:16px;height:16px;border-radius:50%;
    display:flex;align-items:center;justify-content:center;
    background:rgba(6,6,7,.74);color:#fff;font-size:9px;line-height:1;
  }
}


.cmp-go{
  position:absolute;top:16px;right:16px;
  width:38px;height:38px;border-radius:50%;
  display:flex;align-items:center;justify-content:center;
  background:var(--a-btn);color:var(--a-btn-ink);cursor:pointer;
  transition:transform .25s var(--ease),opacity .25s var(--ease);
}
.cmp-go svg{width:17px;height:17px;}
.cmp-go:hover{transform:scale(1.07);}

.cmp-bar{
  display:flex;align-items:center;gap:14px;flex-wrap:wrap;
  margin-top:14px;padding-top:13px;
  border-top:1px solid var(--a-line);
}
.cmp-seg{
  display:flex;gap:2px;padding:3px;border-radius:100px;
  background:var(--a-chip);
}
.cmp-seg button{
  padding:6px 16px;border-radius:100px;cursor:pointer;
  font-size:13px;font-weight:500;color:var(--a-mute);
  transition:background-color .25s var(--ease),color .25s var(--ease);
}
.cmp-seg button.is-on{background:var(--a-btn);color:var(--a-btn-ink);}

.cmp-opts{display:flex;align-items:center;gap:4px;margin-left:auto;flex-wrap:wrap;}
.cmp-pop-w{position:relative;}
.cmp-opt{
  display:flex;align-items:center;gap:7px;
  padding:7px 11px;border-radius:9px;cursor:pointer;
  font-size:13px;color:var(--a-ink);
  transition:background-color .25s var(--ease),color .25s var(--ease);
}
.cmp-opt svg{width:14px;height:14px;opacity:.8;}
.cmp-caret{width:9px!important;height:9px!important;opacity:.55;}
.cmp-opt:hover{background:var(--a-chip);color:var(--a-ink);}
.cmp-opt[aria-expanded="true"]{background:var(--a-chip-2);color:var(--a-ink);}

.cmp-pop{
  position:absolute;right:0;bottom:calc(100% + 9px);z-index:50;
  min-width:230px;padding:6px;
  border-radius:14px;
  background:var(--a-panel);
  box-shadow:
    inset 0 0 0 1px rgba(255,255,255,.08),
    0 26px 54px -20px rgba(0,0,0,.8);
  max-height:min(420px,60vh);overflow-y:auto;
}
.cmp-pop[hidden]{display:none;}
/* Anchored to the trigger's left edge, not its right. The others sit in
   the middle of the bar and have room either way, but Model is the
   leftmost control — and at 360px wide, opening leftwards put it about
   110px off the side of the screen, where its contents could not be
   read or clicked. */
/* Taller than the others because it now carries a filter and headings on
   top of thirty rows; still capped against the viewport so it can never
   run off a short screen. */
.cmp-pop-model{
  min-width:424px;left:0;right:auto;max-height:min(540px,70vh);
  /* Lit from the top-left and falling away toward the bottom. Both stops
     are mixed from the theme tokens, so the light theme gets the same
     shape rather than a second hand-picked pair of colours. */
  background:
    radial-gradient(120% 62% at 10% 0%,
      color-mix(in srgb,var(--a-ink) 7%,transparent), transparent 64%),
    linear-gradient(180deg,
      color-mix(in srgb,var(--a-ink) 4%,var(--a-panel)) 0%,
      var(--a-panel) 44%,
      color-mix(in srgb,var(--a-sunk) 62%,var(--a-panel)) 100%);
}
.cmp-pop-head{
  padding:8px 10px 7px;font-size:10.5px;font-weight:600;
  letter-spacing:.09em;text-transform:uppercase;color:var(--a-mute);
}
.cmp-row,.cmp-mrow{
  display:flex;align-items:center;gap:10px;width:100%;
  padding:9px 10px;border-radius:9px;cursor:pointer;text-align:left;
  color:var(--a-ink);font-size:13.5px;
  transition:background-color .2s var(--ease);
}
.cmp-row b{color:var(--a-ink);font-weight:600;min-width:34px;}
/* Resolution rows carry the number and what it costs, nothing else.
   "Fast draft / Standard / Print ready" said nothing 1K/2K/4K does not
   already say, and sitting mid-row they made the credits read as part of
   the description rather than as a price. margin-left:auto puts the price
   on the right edge; tabular figures keep the column straight down the
   three rows instead of drifting with the glyph widths. */
.cmp-row-cost{
  margin-left:auto;padding-left:18px;
  font-variant-numeric:tabular-nums;font-feature-settings:"tnum";
}
.cmp-row span{color:var(--a-mute);font-size:12.5px;white-space:nowrap;}
.cmp-row:hover,.cmp-mrow:hover{background:var(--a-chip);}
.cmp-row.is-on,.cmp-mrow.is-on{background:var(--a-chip-2);}
.cmp-row.is-on span,
.cmp-mrow.is-on .cmp-mrow-note,
.cmp-mrow.is-on .cmp-mrow-by,
[data-app="dark"] .cmp-row.is-on span,
[data-app="dark"] .cmp-mrow.is-on .cmp-mrow-note,
[data-app="dark"] .cmp-mrow.is-on .cmp-mrow-by{color:var(--a-ink);}

.cmp-mrow{align-items:flex-start;justify-content:space-between;}
.cmp-mrow-main{display:flex;flex-direction:column;gap:3px;min-width:0;}
.cmp-mrow-name{
  display:flex;align-items:center;gap:7px;
  color:var(--a-ink);font-weight:600;font-size:13.5px;
}
.cmp-mrow-name em{
  font-style:normal;font-size:9.5px;font-weight:600;
  letter-spacing:.06em;text-transform:uppercase;
  padding:2px 6px;border-radius:100px;
  background:var(--a-chip-2);color:var(--a-ink);
}
.cmp-mrow-note{color:var(--a-mute);font-size:12px;line-height:1.45;}
.cmp-mrow-by{
  flex:0 0 auto;font-size:11px;color:var(--a-mute);padding-top:2px;
}

/* ── the model picker ───────────────────────
   Close to thirty engines, so the list needs landmarks: a filter pinned
   to the top and a heading per house. The credit badge that used to sit
   on every row is gone — the Generate button already states what the run
   costs, and thirty prices in a list is arithmetic nobody asked for while
   choosing a look. */
.cmp-pop-search{
  position:sticky;top:-6px;z-index:2;
  display:flex;align-items:center;gap:8px;
  margin:-6px -6px 4px;padding:11px 12px;
  /* opaque, and a shade up from the panel: rows scroll underneath it and
     a translucent bar would let them show through */
  background:color-mix(in srgb,var(--a-ink) 6%,var(--a-panel));
  border-bottom:1px solid var(--a-line);
}
.cmp-pop-search svg{width:14px;height:14px;flex:0 0 auto;color:var(--a-mute);}
.cmp-pop-search input{
  flex:1;min-width:0;background:none;border:0;padding:0;
  font-size:13px;color:var(--a-ink);
}
.cmp-pop-search input::placeholder{color:var(--a-mute);}
/* the field is plainly a field and already has the panel's focus ring
   around it — a second ring inside is noise */
.cmp-pop-search input:focus{outline:none;}
.cmp-pop-search input::-webkit-search-cancel-button{filter:grayscale(1);opacity:.5;}

.cmp-pop-group{
  position:relative;
  margin-top:8px;padding:13px 10px 5px;
  font-size:9.5px;font-weight:700;letter-spacing:.11em;text-transform:uppercase;
  color:var(--a-mute);
}
/* a hairline above each house, so a long scroll reads as bands you can
   count rather than one unbroken run */
.cmp-pop-group::before{
  content:"";position:absolute;left:10px;right:10px;top:0;height:1px;
  background:var(--a-line);
}
.cmp-pop-search + .cmp-pop-group{margin-top:0;padding-top:4px;}
.cmp-pop-search + .cmp-pop-group::before{display:none;}
.cmp-pop-empty{padding:18px 12px;font-size:12.5px;color:var(--a-mute);text-align:center;}

/* the chosen row is marked, not priced */
.cmp-mrow-tick{
  flex:0 0 auto;display:grid;place-items:center;
  width:18px;height:18px;margin-top:1px;
  color:var(--vz-acc);opacity:0;
  transition:opacity .18s var(--e-out);
}
.cmp-mrow-tick svg{width:13px;height:13px;}
.cmp-mrow.is-on .cmp-mrow-tick{opacity:1;}

.cmp-note{
  padding:12px 4px 0;font-size:12.5px;line-height:1.5;color:var(--ink-mute);
}
.cmp-note[data-state="warn"]{color:var(--ink-strong);}

@media (max-width:760px){
  .cmp-box{padding:16px 16px 12px;border-radius:18px;}
  .cmp-opts{margin-left:0;width:100%;}
  .cmp-pop{left:0;right:auto;}
  .cmp-pop-model{min-width:min(424px,90vw);}
}

/* ═══ EDITOR ═══
   Stage on the left, dark tool panel on the right — the panel matches
   the composer's surface so the two read as one workspace. */
.ed{margin:0 0 8px;}
.ed-head{margin-bottom:20px;}
.ed-title{font-size:23px;font-weight:500;letter-spacing:-.5px;color:var(--ink-strong);}
.ed-sub{font-size:14px;color:var(--ink-mute);padding-top:5px;}

.ed-shell{
  display:grid;grid-template-columns:minmax(0,1fr) 296px;gap:18px;align-items:start;
}
.ed-stage{
  position:relative;min-height:440px;
  border-radius:20px;overflow:hidden;
  display:flex;align-items:center;justify-content:center;
  background-color:var(--white);
  background-image:
    linear-gradient(45deg,#f0edea 25%,transparent 25%,transparent 75%,#f0edea 75%),
    linear-gradient(45deg,#f0edea 25%,#fff 25%,#fff 75%,#f0edea 75%);
  background-size:18px 18px;background-position:0 0,9px 9px;
  box-shadow:inset 0 0 0 1px var(--line);
}
.ed-drop{
  display:flex;flex-direction:column;align-items:center;gap:7px;
  padding:40px;text-align:center;cursor:pointer;color:var(--ink-mute);
}
.ed-drop[hidden]{display:none;}
.ed-drop b{font-size:16px;font-weight:500;color:var(--ink-strong);}
.ed-drop span{font-size:13px;}
.ed-drop-ic{
  width:52px;height:52px;border-radius:16px;margin-bottom:6px;
  display:flex;align-items:center;justify-content:center;
  background:var(--wash);color:var(--ink-strong);
}
.ed-drop-ic svg{width:24px;height:24px;}

.ed-canvas-w{position:relative;max-width:100%;max-height:72vh;padding:18px;}
.ed-canvas-w[hidden]{display:none;}
.ed-canvas-w canvas{
  display:block;max-width:100%;max-height:66vh;width:auto;height:auto;
  border-radius:10px;box-shadow:0 20px 44px -28px rgba(0,0,0,.55);
  touch-action:none;
}
.ed-clear{
  position:absolute;top:12px;right:12px;
  width:26px;height:26px;border-radius:50%;
  background:rgba(0,0,0,.62);color:#fff;font-size:12px;cursor:pointer;
  display:flex;align-items:center;justify-content:center;
}
/* Absolute inside the stage, for the same reason as .ut-brushdot:
   the stage carries a transform from the entrance animation, which makes
   it the containing block for anything fixed inside it. */
.ed-brushdot{
  position:absolute;z-index:60;pointer-events:none;
  transform:translate(-50%,-50%);border-radius:50%;
  border:1.5px solid rgba(0,0,0,.75);
  box-shadow:0 0 0 1.5px rgba(255,255,255,.85) inset;
}
.ed-brushdot[data-mode="restore"]{border-color:#3ec98a;}
.ed-brushdot[hidden]{display:none;}

.ed-panel{
  border-radius:20px;padding:14px;
  background:var(--a-panel);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.07),0 24px 50px -34px rgba(0,0,0,.7);
}
.ed-panel-top{display:grid;grid-template-columns:1fr 1fr;gap:8px;padding-bottom:14px;}
.ed-btn{
  padding:9px 12px;border-radius:9px;font-size:13.5px;font-weight:600;cursor:pointer;
  transition:opacity .2s var(--ease),transform .2s var(--ease);
}
.ed-btn:hover{transform:translateY(-1px);}
.ed-btn-dark{background:var(--a-sunk);color:var(--a-ink);}
.ed-btn-light{background:var(--a-btn);color:var(--a-btn-ink);}

.ed-tabs{
  display:flex;gap:2px;padding:3px;margin-bottom:8px;
  border-radius:10px;background:var(--a-chip);
}
.ed-tabs button{
  flex:1;padding:6px 8px;border-radius:8px;cursor:pointer;
  font-size:12.5px;font-weight:500;color:var(--a-mute);
  transition:background-color .25s var(--ease),color .25s var(--ease);
}
.ed-tabs button.is-on{background:rgba(255,255,255,.12);color:var(--a-ink);}

.ed-pane[hidden]{display:none;}
.ed-tool{border-bottom:1px solid var(--a-line);}
.ed-tool:last-child{border-bottom:0;}
.ed-tool-row{
  display:flex;align-items:center;gap:11px;width:100%;
  padding:12px 8px;cursor:pointer;text-align:left;
  color:var(--a-ink);font-size:14px;
  transition:color .2s var(--ease);
}
.ed-tool-row svg{width:17px;height:17px;flex:0 0 auto;opacity:.85;}
.ed-tool-name{flex:1;}
.ed-tool-tag{
  font-style:normal;font-size:9px;font-weight:600;letter-spacing:.06em;
  text-transform:uppercase;padding:2px 6px;border-radius:100px;
  background:var(--a-chip-2);color:var(--a-mute);
}
.ed-tool-caret{
  width:9px!important;height:14px!important;opacity:.4;
  transition:transform .25s var(--ease);
}
.ed-tool.is-open .ed-tool-caret{transform:rotate(90deg);}
.ed-tool-row:hover{color:var(--a-ink);}
.ed-tool-body{display:none;padding:0 8px 14px;}
.ed-tool.is-open .ed-tool-body{display:block;}

.ed-hint{font-size:12px;line-height:1.5;color:var(--a-mute);padding-bottom:10px;}
/* The whole row is the drag handle (see editor.js), so it must not select
   text or pan the page while you scrub, and it should say so with the
   cursor. `touch-action:none` is what stops a sideways drag on a phone
   from scrolling the panel out from under your finger. */
.ed-slider{
  display:block;padding-bottom:10px;
  cursor:ew-resize;touch-action:none;
  -webkit-user-select:none;user-select:none;
}
.ed-slider span{display:block;font-size:12px;color:var(--a-mute);padding-bottom:5px;}
.ed-slider b{color:var(--a-ink);font-weight:600;}
.ed-slider input[type=range]{width:100%;accent-color:var(--a-ink);cursor:ew-resize;}
.ed-mini{
  padding:7px 11px;border-radius:8px;font-size:12.5px;cursor:pointer;
  background:rgba(255,255,255,.08);color:var(--a-ink);
  transition:background-color .2s var(--ease);
}
.ed-mini:hover{background:var(--a-chip-2);}
.ed-mini.is-on{background:var(--a-btn);color:var(--a-btn-ink);font-weight:600;}
.ed-mini[disabled]{opacity:.35;pointer-events:none;}
.ed-mini-go{background:var(--a-btn);color:var(--a-btn-ink);font-weight:600;}
.ed-brushmodes{display:grid;grid-template-columns:1fr 1fr;gap:7px;padding-bottom:10px;}

.ed-info-row{
  display:flex;justify-content:space-between;gap:12px;
  padding:9px 8px;border-bottom:1px solid var(--a-line);
  font-size:12.5px;
}
.ed-info-row span{color:var(--a-mute);}
.ed-info-row b{color:var(--a-ink);font-weight:500;text-align:right;word-break:break-word;}

/* ── the Adjust tab ─────────────────────────
   Grouped under small headings rather than run as one long column of
   sliders, so Light, Colour and Finish can be found at a glance. */
.ed-adj-h{
  margin:14px 0 7px;
  font-size:10px;font-weight:700;letter-spacing:.09em;text-transform:uppercase;
  color:var(--a-mute);
}
.ed-adj-h:first-child{margin-top:2px;}

.ed-looks{display:grid;grid-template-columns:repeat(4,1fr);gap:5px;}
.ed-look{
  padding:7px 4px;border-radius:8px;cursor:pointer;
  font-size:10.5px;font-weight:600;letter-spacing:-.01em;
  color:var(--a-ink);background:var(--a-sunk);
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:box-shadow .18s var(--e-out),background-color .18s var(--e-out);
}
.ed-look:hover{box-shadow:inset 0 0 0 1px var(--a-mute);}
.ed-look.is-on{
  background:var(--vz-acc);color:var(--vz-acc-ink);
  box-shadow:inset 0 0 0 1px var(--vz-acc);
}

.ed-tints{display:flex;flex-wrap:wrap;gap:7px;}
.ed-tint{
  width:28px;height:28px;border-radius:50%;cursor:pointer;
  background:var(--sw,var(--a-sunk));
  box-shadow:inset 0 0 0 1px rgba(0,0,0,.16);
  transition:transform .18s var(--e-out),box-shadow .18s var(--e-out);
}
.ed-tint:hover{transform:scale(1.09);}
/* the ring sits outside the swatch so it never tints the colour itself */
.ed-tint.is-on{box-shadow:inset 0 0 0 1px rgba(0,0,0,.16),0 0 0 2.5px var(--a-panel),0 0 0 4.5px var(--vz-acc);}
/* "no wash" reads as a struck-through circle rather than an empty hole */
.ed-tint.is-none{
  background:var(--a-sunk);
  position:relative;overflow:hidden;
  box-shadow:inset 0 0 0 1px var(--a-line);
}
.ed-tint.is-none::after{
  content:"";position:absolute;left:50%;top:-4px;bottom:-4px;width:1.5px;
  background:var(--a-mute);transform:rotate(45deg);
}

/* ── the open set ───────────────────────────
   The strip belongs under the stage, so it is placed explicitly: with
   auto-placement it would have landed in the panel's cell and pushed the
   whole right-hand column down a row. The panel therefore spans both. */
.ed-strip{
  grid-column:1;grid-row:2;
  display:flex;flex-wrap:wrap;align-items:center;gap:8px;
  padding:10px;border-radius:16px;
  background:var(--a-panel);
  box-shadow:inset 0 0 0 1px var(--a-line);
}
.ed-panel{grid-column:2;grid-row:1 / span 2;}

.ed-chip{position:relative;}
.ed-chip-pick{
  display:block;cursor:pointer;
  width:78px;height:88px;padding:0;border-radius:12px;overflow:hidden;
  background:var(--a-sunk);
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:box-shadow .2s var(--e-out),transform .2s var(--e-out);
}
/* `cover` rather than `contain`: at this size letterboxing left more
   empty chip than picture, and the strip read as a row of blank tiles. */
.ed-chip-pick canvas{
  display:block;width:100%;height:100%;object-fit:cover;
  /* a cut-out is transparent, so it needs a ground to read against */
  background:
    linear-gradient(45deg,var(--a-chip-2) 25%,transparent 25%,transparent 75%,var(--a-chip-2) 75%),
    linear-gradient(45deg,var(--a-chip-2) 25%,var(--a-sunk) 25%,var(--a-sunk) 75%,var(--a-chip-2) 75%);
  background-size:12px 12px;background-position:0 0,6px 6px;
}
.ed-chip-pick:hover{transform:translateY(-1px);}
.ed-chip.is-on .ed-chip-pick{box-shadow:inset 0 0 0 2px var(--vz-acc);}

.ed-chip-x{
  position:absolute;top:-5px;right:-5px;
  width:19px;height:19px;border-radius:50%;cursor:pointer;
  display:grid;place-items:center;
  font-size:10px;line-height:1;
  background:var(--a-ink);color:var(--a-bg);
  opacity:0;transition:opacity .18s var(--e-out);
}
.ed-chip:hover .ed-chip-x,.ed-chip-x:focus-visible{opacity:1;}

.ed-chip-add{
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;
  width:78px;height:88px;border-radius:12px;cursor:pointer;
  color:var(--a-mute);
  background:var(--a-sunk);
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:color .2s var(--e-out),box-shadow .2s var(--e-out);
}
.ed-chip-add svg{width:15px;height:15px;}
.ed-chip-add em{font-style:normal;font-size:9.5px;letter-spacing:.02em;}
.ed-chip-add:hover{color:var(--a-ink);box-shadow:inset 0 0 0 1.5px var(--a-mute);}
.ed-chip-full{font-size:10.5px;color:var(--a-mute);padding-left:4px;}

@media (max-width:900px){
  .ed-shell{grid-template-columns:1fr;}
  .ed-stage{min-height:320px;}
  /* one column: the explicit placement above no longer applies */
  .ed-strip{grid-column:1;grid-row:auto;}
  .ed-panel{grid-column:1;grid-row:auto;}
}


.hub-card[data-tone="nine"] .hub-card-visual{background:linear-gradient(150deg,#f1ecec,#e5d8d8);}

/* utility cards have no artwork — the icon carries them, and they sit
   visually quieter than the generators on purpose */
.hub-card-util .hub-card-body{padding:26px 24px 24px;}
.hub-util-ic{
  display:flex;align-items:center;justify-content:center;
  width:42px;height:42px;border-radius:12px;margin-bottom:16px;
  background:var(--accent-soft);color:var(--accent-text);
}
.hub-util-ic svg{width:20px;height:20px;}
.hub-card[data-tone="ten"],.hub-card[data-tone="eleven"]{background:var(--wash);}
.hub-card-back,.hub-card-front{
  position:absolute;display:block;border-radius:10px;overflow:hidden;
  box-shadow:0 16px 32px -18px rgba(0,0,0,.45);
  transition:transform .6s var(--ease);
}
.hub-card-badge{
  position:absolute;top:12px;right:12px;z-index:3;
  width:28px;height:28px;border-radius:50%;
  display:flex;align-items:center;justify-content:center;
  background:rgba(255,255,255,.9);backdrop-filter:blur(8px);color:var(--ink-strong);
}
.hub-card-badge svg{width:14px;height:14px;}
.hub-card-body{display:flex;flex-direction:column;padding:22px 24px 24px;flex:1;}
.hub-card-step{
  font-size:11.5px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;
  color:var(--accent);padding-bottom:9px;
}
.hub-card-title{font-size:20px;font-weight:500;letter-spacing:-.5px;color:var(--ink-strong);}
.hub-card-text{font-size:14px;line-height:1.55;color:var(--ink-mute);padding:8px 0 18px;flex:1;}
.hub-card-go{
  display:inline-flex;align-items:center;gap:7px;align-self:flex-start;
  font-size:14px;font-weight:500;color:var(--ink-strong);
}
.hub-card-go svg{width:14px;height:14px;transition:transform .35s var(--ease);}
.hub-card:hover .hub-card-go svg{transform:translateX(4px);}
.hub-card-go.is-muted{color:var(--ink-mute);}
.hub-card.is-soon{cursor:default;}
.hub-card.is-soon .hub-card-visual img{filter:grayscale(.5) brightness(.9);}
.hub-card.is-soon .hub-card-step{color:var(--ink-mute);}

/* ── responsive ───────────────────────────── */
@media (max-width:1080px){
}
@media (max-width:991px){
  .app-stage-c{grid-template-columns:1fr;}
  .app-tips{flex-direction:row;flex-wrap:wrap;}
  .app-tips-block{flex:1 1 240px;}
  .app-bar-nav{display:none;}
}
@media (max-width:760px){
  .hub-title{font-size:34px;letter-spacing:-1.1px;}
}
@media (max-width:600px){
  .app-panel-title{font-size:28px;letter-spacing:-.6px;}
  .app-bg-grid{grid-template-columns:repeat(2,1fr);}
  .app-actions{flex-wrap:wrap;}
  .app-actions-hint{order:3;width:100%;margin-right:0;}
}

/* ═══════════════════════════════════════════
   TOOL RAIL — every generator, one click away
   Fixed to the left edge under the top bar so switching tools never
   means going back to the hub first.
   ═══════════════════════════════════════════ */
.tool-rail{
  position:fixed;left:0;top:64px;bottom:0;z-index:30;
  width:88px;padding:14px 0 24px;
  display:flex;flex-direction:column;align-items:center;gap:2px;
  background:var(--white);border-right:1px solid var(--line);
  overflow-y:auto;overscroll-behavior:contain;
}
.tool-rail::-webkit-scrollbar{width:0;}
.tool-rail-label{
  font-size:9.5px;font-weight:600;letter-spacing:.1em;text-transform:uppercase;
  color:var(--ink-mute);padding:4px 0 10px;
}
.tool-item{
  position:relative;width:72px;padding:11px 4px 9px;border-radius:12px;
  display:flex;flex-direction:column;align-items:center;gap:6px;
  color:var(--ink-mute);text-align:center;
  transition:background-color .3s var(--ease),color .3s var(--ease);
}
.tool-item svg{width:21px;height:21px;}
.tool-item span{font-size:10px;line-height:1.25;font-weight:500;}
.tool-item:hover{background:var(--wash);color:var(--ink-strong);}
.tool-item.is-on{background:var(--accent-soft);color:var(--accent-text);}
/* the active marker rides the left edge rather than boxing the tile */
.tool-item.is-on::before{
  content:"";position:absolute;left:-8px;top:50%;transform:translateY(-50%);
  width:3px;height:22px;border-radius:0 3px 3px 0;background:var(--accent);
}
.tool-item.is-soon{opacity:.45;cursor:not-allowed;}
.tool-item.is-soon:hover{background:none;color:var(--ink-mute);}
.tool-rail-sep{width:44px;height:1px;background:var(--line);margin:10px 0;}

/* the rail is fixed, so every app page shifts across to clear it */

@media (max-width:900px){
  /* horizontal strip under the bar instead of a column */
  .tool-rail{
    position:sticky;top:64px;left:auto;bottom:auto;
    width:auto;height:auto;padding:8px 12px;
    flex-direction:row;align-items:stretch;gap:6px;
    border-right:0;border-bottom:1px solid var(--line);
    overflow-x:auto;overflow-y:hidden;
  }
  .tool-rail-label,.tool-rail-sep{display:none;}
  .tool-item{
    flex:0 0 auto;width:auto;flex-direction:row;gap:7px;
    padding:9px 13px;border-radius:100px;white-space:nowrap;
  }
  .tool-item span{font-size:12px;}
  .tool-item.is-on::before{display:none;}
}

/* ═══════════════════════════════════════════
   TEMPLATES
   Gallery of finished frames + the panel that pairs one with the
   visitor's own product.
   ═══════════════════════════════════════════ */
.tpl-main{padding:52px 0 90px;}
.tpl-head{max-width:720px;margin-bottom:36px;}
.tpl-head .hub-sub{max-width:640px;}

/* ── filter bar ───────────────────────────── */
/* search sits on its own row above the shelves rather than competing
   with them for width */
.tpl-bar{
  position:sticky;top:64px;z-index:20;
  display:flex;flex-direction:column;gap:16px;
  padding:14px 0 18px;margin-bottom:8px;
  background:linear-gradient(var(--wash) 78%,rgba(238,238,238,0));
}
/* The row scrolls horizontally. Fades are applied per-edge only when
   there is actually more to reach in that direction, so a row that fits
   has no phantom gradient over it. */
.tpl-cats-w{position:relative;min-width:0;}
.tpl-cats{
  display:flex;gap:12px;overflow-x:auto;
  padding:4px 2px 6px;scroll-behavior:smooth;
  scrollbar-width:none;
}
.tpl-cats::-webkit-scrollbar{height:0;}
.tpl-cats-w.has-start .tpl-cats{
  -webkit-mask-image:linear-gradient(to right,transparent,#000 56px);
  mask-image:linear-gradient(to right,transparent,#000 56px);
}
.tpl-cats-w.has-end .tpl-cats{
  -webkit-mask-image:linear-gradient(to left,transparent,#000 56px);
  mask-image:linear-gradient(to left,transparent,#000 56px);
}
.tpl-cats-w.has-start.has-end .tpl-cats{
  -webkit-mask-image:linear-gradient(to right,transparent,#000 56px,#000 calc(100% - 56px),transparent);
  mask-image:linear-gradient(to right,transparent,#000 56px,#000 calc(100% - 56px),transparent);
}

.tpl-cat{
  display:inline-flex;align-items:center;gap:13px;flex:0 0 auto;
  padding:9px 20px 9px 9px;border-radius:18px;white-space:nowrap;
  background:var(--white);
  box-shadow:0 1px 2px rgba(0,0,0,.04),inset 0 0 0 1px var(--line);
  color:var(--ink);text-align:left;
  transition:background-color .35s var(--ease),color .35s var(--ease),
             box-shadow .35s var(--ease),transform .35s var(--ease);
}
.tpl-cat:hover{
  transform:translateY(-2px);
  box-shadow:0 10px 22px -12px rgba(0,0,0,.28),inset 0 0 0 1px #ddd8d2;
}
.tpl-cat-thumb{
  display:block;width:52px;height:52px;flex:0 0 auto;
  border-radius:13px;overflow:hidden;background:var(--wash);
}
.tpl-cat-thumb img{
  width:100%;height:100%;object-fit:cover;display:block;
  transition:transform .5s var(--ease);
}
.tpl-cat:hover .tpl-cat-thumb img{transform:scale(1.07);}
.tpl-cat-txt{display:flex;flex-direction:column;gap:3px;}
.tpl-cat-label{font-size:14.5px;font-weight:600;letter-spacing:-.01em;line-height:1;}
.tpl-cat-n{
  font-size:11.5px;font-weight:400;color:var(--ink-mute);
  line-height:1;font-variant-numeric:tabular-nums;
}
.tpl-cat.is-on{
  background:var(--ink-strong);color:var(--white);
  box-shadow:0 12px 26px -14px rgba(0,0,0,.55);
}
.tpl-cat.is-on .tpl-cat-n{color:rgba(255,255,255,.62);}

/* Arrows sit over each edge and only exist when they can actually move
   the row; the previous version shipped a next arrow with no partner. */
.tpl-cats-nav{
  position:absolute;top:50%;transform:translateY(-50%);
  width:36px;height:36px;border-radius:100px;z-index:2;
  display:flex;align-items:center;justify-content:center;
  background:var(--white);
  box-shadow:0 6px 18px -6px rgba(0,0,0,.3),inset 0 0 0 1px var(--line);
  color:var(--ink-strong);cursor:pointer;
  transition:transform .25s var(--ease),box-shadow .25s var(--ease);
}
.tpl-cats-nav.is-prev{left:-6px;}
.tpl-cats-nav.is-next{right:-6px;}
.tpl-cats-nav svg{width:16px;height:16px;}
.tpl-cats-nav:hover{
  transform:translateY(-50%) scale(1.1);
  box-shadow:0 10px 24px -6px rgba(0,0,0,.36),inset 0 0 0 1px #ddd8d2;
}
.tpl-cats-nav[hidden]{display:none;}

/* full width on its own row above the shelves */
.tpl-search{
  position:relative;display:flex;align-items:center;width:100%;
}
.tpl-search svg{
  position:absolute;left:14px;width:15px;height:15px;color:var(--ink-mute);pointer-events:none;
}
.tpl-search input{
  width:100%;padding:11px 14px 11px 38px;border-radius:100px;border:0;
  background:var(--white);box-shadow:inset 0 0 0 1px var(--line);
  font-family:inherit;font-size:13.5px;color:var(--ink);
  transition:box-shadow .3s var(--ease);
}
.tpl-search input:focus{outline:none;box-shadow:inset 0 0 0 1.5px var(--ink-strong);}

.tpl-count{font-size:13px;color:var(--ink-mute);padding-bottom:16px;}
.tpl-empty{
  padding:60px 20px;text-align:center;font-size:15px;color:var(--ink-mute);
  background:var(--white);border-radius:18px;
}

/* ── card grid ────────────────────────────── */
.tpl-grid{
  display:grid;grid-template-columns:repeat(auto-fill,minmax(190px,1fr));gap:16px;
}
.tpl-card{
  display:block;text-align:left;border-radius:16px;overflow:hidden;
  background:var(--white);
  box-shadow:0 1px 2px rgba(0,0,0,.04),0 20px 40px -34px rgba(0,0,0,.35);
  transition:transform .4s var(--ease),box-shadow .4s var(--ease);
}
.tpl-card:hover{transform:translateY(-4px);box-shadow:0 1px 2px rgba(0,0,0,.04),0 32px 54px -30px rgba(0,0,0,.45);}
.tpl-card-img{position:relative;display:block;aspect-ratio:3/4;background:var(--wash);overflow:hidden;}
.tpl-card-img img{width:100%;height:100%;object-fit:cover;transition:transform .8s var(--ease),filter .4s var(--ease);}
.tpl-card:hover .tpl-card-img img{transform:scale(1.05);filter:brightness(.72);}
.tpl-card-use{
  position:absolute;left:50%;top:50%;transform:translate(-50%,-46%);
  padding:9px 16px;border-radius:100px;white-space:nowrap;
  background:rgba(255,255,255,.94);color:var(--ink-strong);
  font-size:12.5px;font-weight:600;
  opacity:0;transition:opacity .35s var(--ease),transform .35s var(--ease);
}
.tpl-card:hover .tpl-card-use{opacity:1;transform:translate(-50%,-50%);}
.tpl-card-foot{
  display:flex;align-items:center;justify-content:space-between;gap:10px;
  padding:11px 13px 13px;
}
.tpl-chip{
  font-size:10.5px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;
  color:var(--accent-text);background:var(--accent-soft);padding:4px 9px;border-radius:100px;
}
.tpl-card-n{font-size:11.5px;color:var(--ink-mute);font-variant-numeric:tabular-nums;}

/* ── modal ────────────────────────────────── */
.tpl-modal{position:fixed;inset:0;z-index:90;display:flex;align-items:center;justify-content:center;padding:24px;}
.tpl-modal[hidden]{display:none;}
.tpl-modal-veil{
  position:absolute;inset:0;background:rgba(12,12,12,.58);
  backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);
  animation:tplFade .35s var(--ease);
}
@keyframes tplFade{from{opacity:0;}to{opacity:1;}}
.tpl-modal-box{
  position:relative;z-index:2;width:100%;max-width:1000px;max-height:90vh;
  overflow:auto;border-radius:22px;background:var(--white);
  box-shadow:0 60px 120px -50px rgba(0,0,0,.8);
  animation:tplPop .4s var(--ease);
}
@keyframes tplPop{from{opacity:0;transform:translateY(18px) scale(.98);}to{opacity:1;transform:none;}}
.tpl-modal-x{
  position:absolute;top:14px;right:14px;z-index:4;
  width:34px;height:34px;border-radius:50%;
  display:flex;align-items:center;justify-content:center;
  background:rgba(255,255,255,.9);color:var(--ink-strong);
  box-shadow:0 8px 20px -10px rgba(0,0,0,.5);
  transition:transform .3s var(--ease),background-color .3s var(--ease);
}
.tpl-modal-x svg{width:15px;height:15px;}
.tpl-modal-x:hover{transform:scale(1.08);background:#fff;}

.tpl-modal-grid{display:grid;grid-template-columns:minmax(0,.85fr) minmax(0,1fr);}
.tpl-modal-ref{margin:0;position:relative;background:var(--wash);}
.tpl-modal-ref img{width:100%;height:100%;object-fit:cover;min-height:340px;}
.tpl-modal-ref figcaption{
  position:absolute;left:16px;right:16px;bottom:16px;
  display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  padding:11px 13px;border-radius:12px;
  background:rgba(255,255,255,.88);
  backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);
}
.tpl-modal-ref-note{font-size:12px;color:var(--ink-mute);}

.tpl-modal-side{padding:32px 30px 30px;display:flex;flex-direction:column;}
.tpl-modal-title{font-size:24px;font-weight:500;letter-spacing:-.6px;color:var(--ink-strong);}
.tpl-modal-sub{font-size:14px;line-height:1.55;color:var(--ink-mute);padding:8px 0 22px;}

.tpl-step{display:flex;gap:14px;padding-bottom:22px;}
.tpl-step-n{
  flex:0 0 auto;width:24px;height:24px;border-radius:50%;margin-top:1px;
  display:flex;align-items:center;justify-content:center;
  background:var(--ink-strong);color:var(--white);
  font-size:11.5px;font-weight:600;
}
.tpl-step-body{flex:1;min-width:0;}
.tpl-step-body h3{font-size:14px;font-weight:600;color:var(--ink-strong);padding-bottom:10px;}

.tpl-drop{
  border-radius:14px;background:var(--wash);
  box-shadow:inset 0 0 0 1.5px var(--line);
  transition:box-shadow .3s var(--ease);
}
.tpl-drop:hover{box-shadow:inset 0 0 0 1.5px #d6d2ce;}
.tpl-drop-empty{
  display:flex;flex-direction:column;align-items:center;gap:10px;
  padding:26px 18px;text-align:center;
}
.tpl-drop-empty svg{width:26px;height:26px;color:var(--accent);}
.tpl-drop-empty span{font-size:13px;color:var(--ink-mute);}
.tpl-drop-btn{cursor:pointer;padding:11px 22px;font-size:14px;}
.tpl-drop-full{position:relative;padding:12px;}
.tpl-drop-full img{
  width:100%;max-height:190px;object-fit:contain;border-radius:10px;background:var(--wash);
}
.tpl-drop-x{
  position:absolute;top:18px;right:18px;width:26px;height:26px;border-radius:50%;
  background:rgba(12,12,12,.66);color:#fff;
  display:flex;align-items:center;justify-content:center;font-size:12px;
  transition:background-color .25s var(--ease);
}
.tpl-drop-x:hover{background:var(--ink-strong);}

.tpl-lib{padding-top:14px;}
.tpl-lib-label{display:block;font-size:11.5px;color:var(--ink-mute);padding-bottom:8px;}
.tpl-lib-row{display:flex;gap:7px;overflow-x:auto;padding-bottom:4px;}
.tpl-lib-row::-webkit-scrollbar{height:0;}
.tpl-lib-pick{
  flex:0 0 auto;width:46px;height:46px;border-radius:9px;overflow:hidden;
  background:var(--wash);box-shadow:inset 0 0 0 1px var(--line);
  transition:transform .25s var(--ease),box-shadow .25s var(--ease);
}
.tpl-lib-pick img{width:100%;height:100%;object-fit:cover;}
.tpl-lib-pick:hover{transform:translateY(-2px);box-shadow:0 0 0 2px var(--ink-strong);}

.tpl-prompt{
  position:relative;padding:14px 16px;border-radius:12px;
  background:#141312;
}
.tpl-prompt p{
  font-size:12.5px;line-height:1.6;color:rgba(255,255,255,.82);
  max-height:112px;overflow:auto;padding-right:64px;
  font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
}
.tpl-prompt-copy{
  position:absolute;top:11px;right:11px;
  display:inline-flex;align-items:center;gap:5px;
  padding:5px 10px;border-radius:100px;
  background:rgba(255,255,255,.13);color:#fff;
  font-size:11px;font-weight:600;
  transition:background-color .25s var(--ease);
}
.tpl-prompt-copy svg{width:11px;height:11px;}
.tpl-prompt-copy:hover{background:rgba(255,255,255,.24);}

.tpl-extra{display:block;padding-top:14px;}
.tpl-extra span{display:block;font-size:11.5px;color:var(--ink-mute);padding-bottom:7px;}
.tpl-extra textarea{
  width:100%;padding:11px 13px;border-radius:11px;resize:vertical;
  background:var(--white);box-shadow:inset 0 0 0 1px var(--line);
  font-family:inherit;font-size:13.5px;line-height:1.5;color:var(--ink);
}
.tpl-extra textarea:focus{outline:none;box-shadow:inset 0 0 0 1.5px var(--ink-strong);}

.tpl-modal-actions{
  display:flex;align-items:center;justify-content:space-between;gap:14px;
  margin-top:auto;padding-top:14px;border-top:1px solid var(--line);
}
.tpl-cost{font-size:13px;color:var(--ink-mute);}
.tpl-cost b{color:var(--ink-strong);font-weight:600;}
.tpl-generate[disabled]{opacity:.4;pointer-events:none;}
.tpl-hint{font-size:12px;color:var(--ink-mute);padding-top:10px;text-align:right;}

@media (max-width:860px){
  .tpl-modal{padding:0;}
  .tpl-modal-box{max-width:none;max-height:100vh;border-radius:0;}
  .tpl-modal-grid{grid-template-columns:1fr;}
  .tpl-modal-ref img{min-height:0;aspect-ratio:4/3;}
  .tpl-bar{top:0;}
}
@media (max-width:600px){
  .tpl-grid{grid-template-columns:repeat(2,1fr);gap:12px;}
  .tpl-modal-side{padding:24px 20px;}
}

/* ═══════════════════════════════════════════
   UTILITY TOOLS  (resize, remove background)
   Single screen rather than a wizard: stage on the left, controls on
   the right, run at the bottom.
   ═══════════════════════════════════════════ */
.ut-main{padding:52px 0 90px;}
.ut-head{max-width:660px;margin-bottom:34px;}

.ut-grid{display:grid;grid-template-columns:minmax(0,1fr) 340px;gap:20px;align-items:start;}

.ut-stage{
  position:relative;min-height:440px;display:flex;
  border-radius:20px;overflow:hidden;background:var(--white);
  box-shadow:0 1px 2px rgba(0,0,0,.04),0 26px 50px -40px rgba(0,0,0,.3);
}
.ut-empty{margin:auto;text-align:center;max-width:380px;padding:50px 30px;}
.ut-empty-ic{
  width:58px;height:58px;margin:0 auto 20px;border-radius:50%;
  display:flex;align-items:center;justify-content:center;
  background:var(--accent-soft);color:var(--accent);
}
.ut-empty-ic svg{width:26px;height:26px;}
.ut-empty h2{font-size:20px;font-weight:500;letter-spacing:-.4px;color:var(--ink-strong);}
.ut-empty p{font-size:14px;line-height:1.55;color:var(--ink-mute);padding:9px 0 20px;}
.ut-pick{cursor:pointer;}

.ut-full{position:relative;width:100%;display:flex;padding:20px;}
/* display:flex would otherwise beat the UA rule for [hidden] and leave
   the empty checker panel showing before anything is uploaded */
.ut-full[hidden],.ut-empty[hidden]{display:none;}
/* the checker shows through anything transparent, which is the point
   of the cut-out tool */
/* Plain before the cut, checkered after. A checkerboard behind an
   untouched photo claims transparency that is not there yet, and over a
   large panel it reads as emptiness rather than as a backdrop. The
   result view keeps its checker, where it means something. */
.ut-full::before{
  content:"";position:absolute;inset:20px;border-radius:12px;
  background:var(--a-sunk);
}
/* Capped by the stage, not by a number. This said 420px, which was
   right when the stage was 440 tall and left roughly a third of the
   panel empty once the stage grew — the photo stayed small in the middle
   of a large checkerboard. */
.ut-full img{
  position:relative;margin:auto;max-width:100%;max-height:100%;
  object-fit:contain;border-radius:12px;
}
.ut-full{min-height:0;}
.ut-clear{
  position:absolute;top:30px;right:30px;z-index:2;
  width:28px;height:28px;border-radius:50%;
  background:rgba(12,12,12,.66);color:#fff;
  display:flex;align-items:center;justify-content:center;font-size:12px;
  transition:background-color .25s var(--ease);
}
.ut-clear:hover{background:var(--ink-strong);}
/* This caption sits ON the photograph, not on the page, so it does not
   follow the theme — it has to stay readable over whatever was dropped,
   light or dark. It used to take its colour from --ink-strong, a token
   from the marketing stylesheet that resolves to near-white in the app
   dark theme: white text on a white pill, about 1.05:1. */
.ut-meta{
  position:absolute;left:30px;bottom:30px;z-index:2;
  max-width:calc(100% - 60px);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  padding:6px 12px;border-radius:100px;
  background:rgba(12,11,10,.72);backdrop-filter:blur(8px);
  font-size:11.5px;color:#fff;font-variant-numeric:tabular-nums;
}

/* ── side panel ───────────────────────────── */
.ut-side{
  padding:24px 22px;border-radius:20px;background:var(--white);
  box-shadow:0 1px 2px rgba(0,0,0,.04),0 26px 50px -40px rgba(0,0,0,.3);
  display:flex;flex-direction:column;
}
.ut-side-h{
  font-size:11px;font-weight:600;letter-spacing:.09em;text-transform:uppercase;
  color:var(--ink-mute);padding-bottom:12px;
}
.ut-side-h + *{margin-bottom:22px;}

.ut-presets{display:grid;grid-template-columns:1fr 1fr;gap:8px;}
.ut-preset{
  display:flex;flex-direction:column;gap:3px;align-items:flex-start;
  padding:11px 12px;border-radius:11px;text-align:left;
  background:var(--white);box-shadow:inset 0 0 0 1px var(--line);
  transition:box-shadow .3s var(--ease),background-color .3s var(--ease);
}
.ut-preset b{font-size:13px;font-weight:600;color:var(--ink-strong);}
.ut-preset em{font-size:10.5px;font-style:normal;color:var(--ink-mute);}
.ut-preset:hover{background:var(--wash);}
.ut-preset.is-on{box-shadow:inset 0 0 0 1.6px var(--ink-strong);background:var(--wash);}

.ut-dims{display:flex;align-items:flex-end;gap:9px;}
.ut-dims label{flex:1;display:block;}
.ut-dims span{display:block;font-size:11px;color:var(--ink-mute);padding-bottom:6px;}
.ut-dims input{
  width:100%;padding:11px 12px;border-radius:10px;border:0;
  background:var(--white);box-shadow:inset 0 0 0 1px var(--line);
  font-family:inherit;font-size:14px;color:var(--ink);
  font-variant-numeric:tabular-nums;
}
.ut-dims input:focus{outline:none;box-shadow:inset 0 0 0 1.5px var(--ink-strong);}
.ut-lock{
  flex:0 0 auto;width:38px;height:38px;border-radius:10px;margin-bottom:1px;
  display:flex;align-items:center;justify-content:center;
  color:var(--ink-mute);box-shadow:inset 0 0 0 1px var(--line);
  transition:color .3s var(--ease),background-color .3s var(--ease);
}
.ut-lock svg{width:15px;height:15px;}
.ut-lock.is-on{background:var(--accent-soft);color:var(--accent-text);box-shadow:none;}

.ut-field{display:block;}
.ut-field span{display:block;font-size:11px;color:var(--ink-mute);padding-bottom:6px;}
.ut-field select{
  width:100%;padding:11px 12px;border-radius:10px;border:0;appearance:none;
  background:var(--white);box-shadow:inset 0 0 0 1px var(--line);
  font-family:inherit;font-size:13.5px;color:var(--ink);cursor:pointer;
}
.ut-field select:focus{outline:none;box-shadow:inset 0 0 0 1.5px var(--ink-strong);}

.ut-bgopts{display:flex;flex-direction:column;gap:8px;}
.ut-bgopt{
  display:flex;align-items:center;gap:10px;
  padding:11px 12px;border-radius:11px;text-align:left;
  font-size:13.5px;color:var(--ink);
  box-shadow:inset 0 0 0 1px var(--line);
  transition:box-shadow .3s var(--ease),background-color .3s var(--ease);
}
.ut-bgopt:hover{background:var(--wash);}
.ut-bgopt.is-on{box-shadow:inset 0 0 0 1.6px var(--ink-strong);background:var(--wash);}
.ut-sw{width:22px;height:22px;border-radius:6px;flex:0 0 auto;}
.ut-sw-alpha{
  background-color:#fff;
  background-image:
    linear-gradient(45deg,#dcd8d4 25%,transparent 25%,transparent 75%,#dcd8d4 75%),
    linear-gradient(45deg,#dcd8d4 25%,transparent 25%,transparent 75%,#dcd8d4 75%);
  background-size:10px 10px;background-position:0 0,5px 5px;
  box-shadow:inset 0 0 0 1px var(--line);
}

.ut-actions{
  margin-top:auto;padding-top:18px;border-top:1px solid var(--line);
  display:flex;flex-direction:column;gap:10px;
}
.ut-hint{font-size:12.5px;color:var(--ink-mute);}
.ut-run{width:100%;justify-content:center;}
.ut-run[disabled]{opacity:.4;pointer-events:none;}
.ut-note{font-size:11.5px;color:var(--ink-mute);padding-top:12px;line-height:1.5;}

/* ── result preview + retouch ─────────────── */
.ut-result{
  position:absolute;inset:0;
  display:flex;align-items:center;justify-content:center;
  padding:18px;
}
.ut-result[hidden]{display:none;}
.ut-canvas-w{
  max-width:100%;max-height:100%;
  border-radius:12px;overflow:hidden;
  /* checkerboard so transparency is unmistakable */
  background-color:#fff;
  background-image:
    linear-gradient(45deg,#e4e0dc 25%,transparent 25%,transparent 75%,#e4e0dc 75%),
    linear-gradient(45deg,#e4e0dc 25%,#fff 25%,#fff 75%,#e4e0dc 75%);
  background-size:16px 16px;background-position:0 0,8px 8px;
  box-shadow:0 18px 40px -26px rgba(0,0,0,.5);
}
/* The canvas fills a wrapper that carries the picture's aspect ratio,
   which JS sets from the working size. It used to size itself with a
   max-height of 70vh — a cap taken from the VIEWPORT rather than from the
   box it sits in. On a tall screen that let it render 889px high inside a
   404px frame, and since the wrapper hides its overflow, 485px of the
   picture was simply cut off the bottom. Constraining the wrapper instead
   means the whole frame is always visible, at any window size. */
.ut-canvas-w canvas{
  display:block;width:100%;height:100%;
  cursor:crosshair;touch-action:none;
}
/* brush cursor: follows the pointer at the true painted size, so the
   stroke lands where it looks like it will */
/* Absolute inside the result box, not fixed to the viewport. The
   stage carries the entrance animation's transform, and a transformed
   element becomes the containing block for its fixed descendants — so
   viewport coordinates were being read as stage coordinates and the ring
   was drawn hundreds of pixels away from the pointer. An identity matrix
   is enough to do it; the transform does not have to move anything. */
.ut-brushdot{
  position:absolute;z-index:60;pointer-events:none;
  transform:translate(-50%,-50%);
  border-radius:50%;
  border:1.5px solid rgba(0,0,0,.75);
  box-shadow:0 0 0 1.5px rgba(255,255,255,.85) inset;
}
.ut-brushdot[data-mode="restore"]{border-color:#3ec98a;}
.ut-brushdot[hidden]{display:none;}

.ut-retouch{padding-top:18px;border-top:1px solid var(--line);margin-top:4px;}
.ut-retouch[hidden]{display:none;}
.ut-brushmodes{display:grid;grid-template-columns:1fr 1fr;gap:8px;padding-bottom:12px;}
.ut-brushmode{
  display:flex;align-items:center;justify-content:center;gap:7px;
  padding:9px 10px;border-radius:10px;font-size:13px;font-weight:500;
  background:var(--white);box-shadow:inset 0 0 0 1px var(--line);
  color:var(--ink);cursor:pointer;
  transition:background-color .25s var(--ease),color .25s var(--ease);
}
.ut-brushmode svg{width:16px;height:16px;}
.ut-brushmode.is-on{background:var(--ink-strong);color:var(--white);box-shadow:none;}
.ut-brushsize input[type=range]{width:100%;margin-top:6px;accent-color:var(--ink-strong);}
.ut-brushsize span{display:block;font-size:12.5px;color:var(--ink-mute);}
.ut-brushsize b{color:var(--ink-strong);font-weight:600;}
.ut-undo{display:flex;gap:8px;padding:12px 0 4px;}
.ut-ghostbtn{
  flex:1;display:flex;align-items:center;justify-content:center;gap:6px;
  padding:8px 10px;border-radius:9px;font-size:12.5px;font-weight:500;
  background:var(--white);box-shadow:inset 0 0 0 1px var(--line);
  color:var(--ink);cursor:pointer;
  transition:opacity .2s var(--ease);
}
.ut-ghostbtn svg{width:14px;height:14px;}
.ut-ghostbtn[disabled]{opacity:.4;pointer-events:none;}
.ut-ghostbtn:hover{box-shadow:inset 0 0 0 1px #d6d2ce;}
[data-ut-save][hidden]{display:none;}

/* ── demo strip on the cut-out page ───────── */
.ut-demo{padding-top:56px;}
.ut-demo-h{font-size:22px;font-weight:500;letter-spacing:-.5px;color:var(--ink-strong);}
.ut-demo-sub{font-size:14px;color:var(--ink-mute);padding:8px 0 26px;}
/* the resize page centres its heading over the bare clip; the cut-out
   page keeps the left-aligned heading above its four-card grid */
.ut-demo:has(.ut-demo-v){text-align:center;}
.ut-demo-grid{grid-template-columns:repeat(4,1fr)!important;}
.ut-demo-grid .ba-card{opacity:1!important;transform:none!important;}
.ut-ba-frame{aspect-ratio:1/1;}

/* Self-running demo clip — autoplay, no controls, nothing to pause.
   No card, no rounded plate, no dark backdrop: the clip's own ground is
   near white, so any frame around it reads as a box floating on the page.
   Bare and centred, it sits in the layout instead of on top of it. */
.ut-demo-v{
  max-width:820px;
  margin:0 auto;
  /* demo-2 is 1280x720 — a portrait box here would crop it */
  aspect-ratio:1280/720;
}
/* multiply drops the clip's near-white plate into the page wash, so the
   footage reads as part of the page instead of a pale rectangle on it */
.ut-demo-v video{
  width:100%;height:100%;object-fit:contain;display:block;
  mix-blend-mode:multiply;
}

@media (max-width:1080px){
  .ut-grid{grid-template-columns:1fr;}
  .ut-demo-grid{grid-template-columns:repeat(2,1fr)!important;}
}
@media (max-width:900px){
}
@media (max-width:620px){
  .ut-presets{grid-template-columns:1fr;}
  .ut-demo-grid{grid-template-columns:1fr!important;}
}

/* ═══ EXPLORE ═══ */
.xp-hero{max-width:720px;margin:0 auto 38px;text-align:center;}
.xp-h1{
  font-size:clamp(34px,5vw,58px);font-weight:400;
  letter-spacing:-.035em;line-height:1.03;color:var(--ink-strong);
  padding-top:12px;
}
.xp-sub{font-size:16px;line-height:1.6;color:var(--ink-mute);padding-top:16px;}

.xp-sec{padding-bottom:38px;}
.xp-sec:last-of-type{padding-bottom:72px;}

/* The heading holds the name, the count and a rule that runs to the far
   edge, so each group reads as a band rather than as floating text. */
.xp-sec-h{
  display:grid;grid-template-columns:auto 1fr auto;align-items:baseline;
  gap:0 14px;padding:0 2px 15px;
}
.xp-sec-h h2{
  font-size:20px;font-weight:500;letter-spacing:-.02em;color:var(--ink-strong);
}
.xp-sec-h p{
  grid-column:1;grid-row:2;margin-top:5px;
  font-size:13.5px;line-height:1.5;color:var(--ink-mute);
}
.xp-sec-h::after{
  content:"";grid-column:2;grid-row:1;height:1px;background:var(--line);
  align-self:center;
}
.xp-sec-n{
  grid-column:3;grid-row:1;
  font-size:11px;font-weight:600;color:var(--ink-mute);
  padding:2px 9px;border-radius:100px;background:var(--wash);
}

/* One rule for both rooms. The studio hub and All tools show the same
   cards from the same markup; two sets of numbers for that is two sets
   to keep in step, and they had already drifted apart.
   The hub used to run six columns with the first two double-wide; it
   now sits on the same even grid, which is what "identical" means. */
.xp-grid,
.hub-grid{
  display:grid;grid-template-columns:repeat(3,1fr);gap:18px;
}
.xp-card,
.hub-card{
  position:relative;display:flex;flex-direction:column;
  border-radius:20px;overflow:hidden;background:var(--white);
  box-shadow:inset 0 0 0 1px var(--line);
  transition:transform .5s var(--ease),box-shadow .5s var(--ease);
}
/* Revealed by explore.js. The hiding class is only ever added when the
   observer is known to exist, so a card can never be stranded invisible. */
.xp-card.is-hidden{opacity:0;transform:translateY(20px);}
.xp-card.is-in{
  opacity:1;transform:none;
  transition:opacity .7s var(--ease) calc(var(--i) * 40ms),
             transform .7s var(--ease) calc(var(--i) * 40ms);
}
.xp-card:hover,
.hub-card:not(.is-soon):hover{
  transform:translateY(-5px);
  box-shadow:inset 0 0 0 1px #ddd8d2,0 30px 56px -34px rgba(0,0,0,.4);
}
/* ── two frames, not one ──
   The same treatment the studio hub uses on its wizard cards: a back
   frame and a front one, overlapping. One picture of a finished shot
   could be the input or the output and says nothing about what the tool
   does; a pair reads as before and after without a caption.

   The box is deliberately not transparent — several of these frames are
   cut-outs on alpha (the background remover's, above all), and on a dark
   panel a transparent PNG would simply vanish. */
.xp-card-img,
.hub-card-visual{
  position:relative;display:block;aspect-ratio:3/2;overflow:hidden;
  background:linear-gradient(150deg,#f2efec,#e4e0dc);
}
.xp-card-back,.xp-card-front,
.hub-card-back,.hub-card-front{
  position:absolute;display:block;border-radius:9px;overflow:hidden;
  box-shadow:0 14px 30px -16px rgba(0,0,0,.5);
  transition:transform .6s var(--ease);
}
/* Bigger than the hub's, and tilted where the hub's sit square. Two
   upright rectangles read as a diagram; a couple of degrees apart reads
   as photographs someone laid down. The angle is small on purpose —
   past about three degrees it stops looking placed and starts looking
   broken.

   The tops are pulled up as the frames grow so the taller pair still
   clears the bottom of the box once rotated: a 2.2deg turn lifts a
   corner by roughly half the width times sin(angle), which at this size
   is a few pixels, and the margin below absorbs it. */
.xp-card-back,
.hub-card-back{
  left:8%;top:12%;width:38%;aspect-ratio:3/4;
  transform:rotate(-2.2deg);
}
.xp-card-front,
.hub-card-front{
  right:9%;top:6%;width:44%;aspect-ratio:3/4;
  transform:rotate(2.2deg);
}
.xp-card-img img,
.hub-card-visual img{width:100%;height:100%;object-fit:cover;display:block;}

/* on hover the two ease apart, so the card shows it is two things */
.xp-card:hover .xp-card-back,
.hub-card:not(.is-soon):hover .hub-card-back{transform:translate3d(-6px,3px,0) rotate(-3.4deg);}
.xp-card:hover .xp-card-front,
.hub-card:not(.is-soon):hover .hub-card-front{transform:translate3d(6px,-3px,0) rotate(3.4deg);}

@media (prefers-reduced-motion:reduce){
  /* the resting tilt stays: it is composition, not motion. Only the
     hover movement is dropped. */
  .xp-card:hover .xp-card-back{transform:rotate(-2.2deg);}
  .xp-card:hover .xp-card-front{transform:rotate(2.2deg);}
}
.xp-card-body{display:flex;flex-direction:column;gap:7px;padding:20px 20px 22px;flex:1;}
.xp-kind{
  position:absolute;width:1px;height:1px;
  margin:-1px;padding:0;overflow:hidden;
  clip-path:inset(50%);white-space:nowrap;
}
.xp-name{font-size:19px;font-weight:500;letter-spacing:-.02em;color:var(--ink-strong);}
.xp-desc{
  font-size:13.5px;line-height:1.55;color:var(--ink-mute);flex:1;
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;
  overflow:hidden;min-height:calc(2 * 1.55em);
}
.xp-go{
  display:flex;align-items:center;gap:6px;padding-top:6px;
  font-size:13px;font-weight:600;color:var(--ink-strong);
}
.xp-go svg{width:14px;height:14px;transition:transform .3s var(--ease);}
.xp-card:hover .xp-go svg{transform:translateX(3px);}

.xp-grid:has(> .xp-card:only-child){grid-template-columns:1fr;}
.xp-card:only-child{flex-direction:row;min-height:212px;}
.xp-card:only-child .xp-card-img{
  aspect-ratio:5/4;flex:none;width:min(34%,300px);
}
.xp-card:only-child .xp-card-body{
  justify-content:center;padding:26px 30px;max-width:560px;
}
.xp-card:only-child .xp-desc{
  -webkit-line-clamp:3;min-height:0;flex:none;padding-bottom:4px;
}
@media (max-width:620px){
  .xp-card:only-child{flex-direction:column;min-height:0;}
  .xp-card:only-child .xp-card-img{width:100%;aspect-ratio:3/2;}
  .xp-card:only-child .xp-card-body{padding:20px 20px 22px;}
}

/* Four across once there is room: the cards are short now, and three
   wide left a lot of empty page on a wide screen. */
@media (min-width:1180px){.xp-grid,.hub-grid{grid-template-columns:repeat(4,1fr);}}
@media (max-width:980px){.xp-grid,.hub-grid{grid-template-columns:repeat(2,1fr);}}
@media (max-width:620px){
  .xp-grid,.hub-grid{grid-template-columns:1fr;}
  .xp-sec-h{grid-template-columns:auto auto 1fr;}
  .xp-sec-h::after{display:none;}
  .xp-sec-n{grid-column:2;}
}


/* ═══ ASSETS ═══
   Sidebar of scopes, main column grouped by the day each asset was
   made. Replaces the old flat filter row. */
.as-main{padding:0;}
.as-shell{display:grid;grid-template-columns:224px minmax(0,1fr);align-items:start;}

.as-side{
  position:sticky;top:56px;align-self:start;
  height:calc(100vh - 56px);overflow-y:auto;
  padding:18px 12px;
  border-right:1px solid var(--vz-line,var(--line));
}
.as-side-row{
  display:flex;align-items:center;gap:10px;width:100%;
  padding:8px 10px;border-radius:10px;cursor:pointer;text-align:left;
  font-size:13.5px;color:var(--vz-text,var(--ink));
  transition:background-color .2s var(--ease);
}
.as-side-row:hover{background:var(--vz-chip,rgba(21,19,15,.05));}
.as-side-row.is-on{background:var(--vz-chip,rgba(21,19,15,.08));font-weight:600;}
.as-side-ic{display:flex;flex:0 0 auto;color:var(--vz-muted,var(--ink-mute));}
.as-side-ic svg{width:15px;height:15px;}
.as-side-row.is-on .as-side-ic{color:var(--vz-acc,var(--ink-strong));}
.as-side-l{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.as-side-n{
  font-size:11px;font-variant-numeric:tabular-nums;
  color:var(--vz-muted,var(--ink-mute));flex:0 0 auto;
}
.as-side-h{
  display:flex;align-items:center;justify-content:space-between;
  padding:18px 10px 7px;
  font-size:10px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;
  color:var(--vz-muted,var(--ink-mute));
}
.as-newfolder{
  width:20px;height:20px;border-radius:6px;cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  font-size:15px;line-height:1;color:var(--vz-muted,var(--ink-mute));
  transition:background-color .2s var(--ease);
}
.as-newfolder:hover{background:var(--vz-chip,rgba(21,19,15,.08));}
.as-folder-w{position:relative;}
.as-folder-x{
  position:absolute;right:6px;top:50%;transform:translateY(-50%);
  width:18px;height:18px;border-radius:5px;cursor:pointer;opacity:0;
  display:flex;align-items:center;justify-content:center;
  font-size:10px;color:var(--vz-muted,var(--ink-mute));
  transition:opacity .2s var(--ease);
}
.as-folder-w:hover .as-folder-x{opacity:1;}
.as-folder-x:hover{background:rgba(255,255,255,.15);color:var(--a-danger);}
.as-side-empty{padding:2px 10px;font-size:12px;color:var(--vz-muted,var(--ink-mute));}

.as-body{padding:26px 26px 80px;min-width:0;}
.as-head{padding-bottom:22px;}
.as-title{font-size:24px;font-weight:600;letter-spacing:-.02em;color:var(--vz-text,var(--ink-strong));}
.as-note{font-size:12.5px;color:var(--vz-muted,var(--ink-mute));padding-top:5px;}

.as-day{padding-bottom:34px;}
.as-day-h{
  display:flex;align-items:center;gap:9px;padding-bottom:12px;
  font-size:15px;font-weight:600;color:var(--vz-text,var(--ink-strong));
}
.as-day-h span{
  font-size:10.5px;font-weight:600;padding:2px 7px;border-radius:100px;
  background:var(--vz-chip,rgba(21,19,15,.07));color:var(--vz-muted,var(--ink-mute));
}
/* Rows, not columns — the same hanging the wall uses. Cards keep the
   shape of the work in them, and six fixed columns then leave a hole
   under every card shorter than the tallest in its row. js/assets.js
   closes each row at the height that fills the width exactly. */
.as-grid{display:flex;flex-wrap:wrap;align-content:flex-start;gap:12px;}

.as-card{
  position:relative;margin:0;border-radius:13px;overflow:hidden;
  flex:0 0 auto;width:15.5%;
  /* What it holds until that pass runs, and without scripting: 3/4 until
     the file says otherwise — see learnSizes in js/assets.js. A 16:9
     frame in a portrait card is a crop nobody asked for, and then the
     thumbnail disagrees with the picture it opens. */
  aspect-ratio:var(--as-ar,3/4);background:var(--vz-panel,var(--white));
  box-shadow:inset 0 0 0 1px var(--vz-line,var(--line));
  transition:transform .35s var(--ease),box-shadow .35s var(--ease);
}
.as-card:hover{transform:translateY(-3px);box-shadow:0 18px 34px -22px rgba(0,0,0,.45);}
.as-media{width:100%;height:100%;}
.as-card img,.as-card video{width:100%;height:100%;object-fit:cover;display:block;}
.as-card.is-alpha{
  background-image:
    linear-gradient(45deg,#e8e5e1 25%,transparent 25%,transparent 75%,#e8e5e1 75%),
    linear-gradient(45deg,#e8e5e1 25%,#fff 25%,#fff 75%,#e8e5e1 75%);
  background-size:14px 14px;background-position:0 0,7px 7px;
}
.as-card.is-alpha img{object-fit:contain;}

.as-fav{
  position:absolute;left:8px;bottom:8px;
  width:28px;height:28px;border-radius:100px;cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  background:rgba(10,9,8,.5);color:rgba(255,255,255,.85);
  backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);
  opacity:0;transform:scale(.9);
  transition:opacity .2s var(--ease),transform .2s var(--ease),color .2s var(--ease);
}
.as-fav svg{width:14px;height:14px;}
.as-card:hover .as-fav{opacity:1;transform:none;}
.as-fav.is-on{opacity:1;transform:none;color:#ff4d5e;}

.as-acts{
  position:absolute;top:8px;right:8px;display:flex;gap:5px;
  opacity:0;transform:translateY(-3px);
  transition:opacity .2s var(--ease),transform .2s var(--ease);
}
.as-card:hover .as-acts{opacity:1;transform:none;}
.as-act{
  width:28px;height:28px;border-radius:100px;cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  background:rgba(10,9,8,.55);color:#fff;font-size:14px;line-height:1;
  backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);
  transition:background-color .2s var(--ease);
}
.as-act svg{width:14px;height:14px;}
.as-act:hover{background:rgba(10,9,8,.8);}
.as-tag{
  position:absolute;left:8px;top:8px;
  padding:3px 8px;border-radius:100px;
  background:rgba(10,9,8,.55);color:#fff;
  font-size:9.5px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;
  backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);
}
.as-vbadge{
  position:absolute;right:8px;bottom:8px;
  width:24px;height:24px;border-radius:100px;
  display:flex;align-items:center;justify-content:center;
  background:rgba(10,9,8,.55);color:#fff;
}
.as-vbadge svg{width:11px;height:11px;}
/* Assets ships with nothing in it now, so this is the first thing a new
   account sees rather than a rare edge case. It says what belongs here
   and offers the one move that fills it. */
.as-empty{
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:8px;padding:76px 40px;text-align:center;
  border:1px dashed var(--vz-line,var(--line));border-radius:16px;
}
.as-empty-h{
  font-size:16px;font-weight:600;letter-spacing:-.015em;
  color:var(--vz-text,var(--ink-strong));
}
.as-empty-s{
  max-width:38ch;font-size:13px;line-height:1.65;
  color:var(--vz-muted,var(--ink-mute));
}
.as-empty-go{
  margin-top:8px;display:inline-flex;align-items:center;
  height:40px;padding:0 20px;border-radius:12px;text-decoration:none;
  font-size:13px;font-weight:600;letter-spacing:-.01em;
  background:var(--vz-text,var(--ink-strong));color:var(--vz-panel,#fff);
  transition:opacity .2s var(--ease),transform .2s var(--ease);
}
.as-empty-go:hover{opacity:.86;transform:translateY(-1px);}

/* ── context menu ── */
.as-menu{
  position:fixed;z-index:80;min-width:206px;padding:5px;
  border-radius:13px;
  background:var(--a-panel);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.09),0 26px 54px -18px rgba(0,0,0,.8);
}
.as-menu-row{
  display:flex;align-items:center;gap:10px;width:100%;
  padding:8px 10px;border-radius:9px;cursor:pointer;text-align:left;
  font-size:13px;color:var(--a-ink);
  transition:background-color .18s var(--ease);
}
.as-menu-row svg{width:14px;height:14px;flex:0 0 auto;opacity:.8;}
.as-menu-row em{
  margin-left:auto;font-style:normal;font-size:8.5px;font-weight:700;
  letter-spacing:.06em;text-transform:uppercase;
  padding:2px 5px;border-radius:100px;
  background:var(--a-chip-2);color:var(--a-mute);
}
.as-menu-row:hover{background:rgba(255,255,255,.08);}
.as-menu-row.is-danger{color:#ff6b6b;}
.as-menu-row.is-danger:hover{background:rgba(255,255,255,.14);}

/* ── folder modal ── */
.as-modal{position:fixed;inset:0;z-index:90;display:flex;align-items:center;justify-content:center;}
.as-modal-veil{position:absolute;inset:0;background:rgba(8,7,6,.55);backdrop-filter:blur(4px);}
.as-modal-box{
  position:relative;width:min(360px,calc(100vw - 32px));padding:22px;
  border-radius:18px;background:var(--vz-panel,var(--white));
  box-shadow:0 30px 70px -24px rgba(0,0,0,.6);
}
.as-modal-box h3{font-size:16px;font-weight:600;color:var(--vz-text,var(--ink-strong));padding-bottom:14px;}
.as-modal-list{display:flex;flex-direction:column;gap:4px;max-height:230px;overflow-y:auto;}
.as-modal-row{
  padding:9px 12px;border-radius:9px;cursor:pointer;text-align:left;
  font-size:13.5px;color:var(--vz-text,var(--ink));
  background:var(--vz-chip,rgba(21,19,15,.05));
  transition:background-color .2s var(--ease);
}
.as-modal-row:hover{background:var(--vz-chip,rgba(21,19,15,.1));}
.as-modal-row.is-on{background:var(--vz-acc,var(--ink-strong));color:var(--vz-acc-ink,#fff);font-weight:600;}
.as-modal-row.is-danger{color:var(--a-danger);}
.as-modal-new{display:flex;gap:7px;padding-top:14px;}
.as-modal-new input{
  flex:1;min-width:0;padding:9px 12px;border:0;border-radius:9px;
  background:var(--vz-chip,rgba(21,19,15,.06));
  color:var(--vz-text,var(--ink));font-family:inherit;font-size:13.5px;
}
.as-modal-new input:focus{outline:2px solid var(--vz-acc,var(--ink-strong));outline-offset:-2px;}
.as-modal-new button{
  padding:9px 15px;border-radius:9px;cursor:pointer;
  background:var(--vz-text,var(--ink-strong));color:var(--vz-bg,var(--white));
  font-size:13px;font-weight:600;
}
.as-modal-x{
  position:absolute;top:14px;right:14px;
  width:26px;height:26px;border-radius:50%;cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  font-size:12px;color:var(--vz-muted,var(--ink-mute));
}
.as-hint{font-size:12.5px;color:var(--vz-muted,var(--ink-mute));}

/* The column counts are a target row height in js/assets.js now; these
   are only the widths the grid falls back to before that pass runs. */
@media (max-width:1200px){.as-card{width:24%;}}
@media (max-width:900px){
  .as-shell{grid-template-columns:1fr;}
  .as-side{position:static;height:auto;border-right:0;border-bottom:1px solid var(--vz-line,var(--line));}
  .as-body{padding:20px 16px 70px;}
}
@media (max-width:600px){.as-card{width:48.5%;}}

/* ═══ VIDEO GENERATOR ═══
   Full dark, unlike the light image studio — the two should not be
   mistaken for each other at a glance. */
.vid-body{background:var(--a-nav);}
.vid-main{color:var(--a-ink);padding-bottom:90px;}
.vid-hero{
  padding:58px 0 40px;
  background:radial-gradient(120% 90% at 50% 0%,rgba(255,255,255,.16),transparent 60%);
}
.vid-eyebrow{
  display:inline-block;font-size:10.5px;font-weight:700;
  letter-spacing:.13em;text-transform:uppercase;color:var(--accent,#c9a227);
}
.vid-h1{
  font-size:clamp(34px,5vw,58px);font-weight:400;
  letter-spacing:-.035em;line-height:1.03;color:var(--a-ink);padding-top:12px;
}
.vid-sub{font-size:16px;line-height:1.6;color:var(--a-mute);padding-top:14px;max-width:56ch;}

.vid-shell{display:grid;grid-template-columns:minmax(0,1fr) 320px;gap:18px;align-items:start;}
.vid-left{display:flex;flex-direction:column;gap:14px;}
.vid-drop{
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:7px;
  min-height:340px;padding:40px;text-align:center;cursor:pointer;
  border-radius:20px;border:1px dashed var(--a-line);color:var(--a-mute);
  background:var(--a-panel);
  transition:border-color .3s var(--ease);
}
.vid-drop:hover{border-color:var(--a-btn-ink);}
.vid-drop[hidden]{display:none;}
.vid-drop b{font-size:16px;font-weight:500;color:var(--a-ink);}
.vid-drop span{font-size:13px;}
.vid-drop-ic{
  width:56px;height:56px;border-radius:16px;margin-bottom:6px;
  display:flex;align-items:center;justify-content:center;
  background:var(--a-chip);color:var(--a-ink);
}
.vid-drop-ic svg{width:26px;height:26px;}
.vid-preview{position:relative;border-radius:20px;overflow:hidden;background:var(--a-panel);}
.vid-preview[hidden]{display:none;}
.vid-preview img{width:100%;max-height:60vh;object-fit:contain;display:block;}
.vid-prompt{
  width:100%;padding:15px 16px;border:0;border-radius:16px;resize:vertical;
  background:var(--a-panel);color:var(--a-ink);font-family:inherit;font-size:14.5px;line-height:1.55;
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.08);
}
.vid-prompt::placeholder{color:var(--a-mute);}
.vid-prompt:focus{outline:none;box-shadow:inset 0 0 0 1.5px rgba(255,255,255,.2);}

.vid-side{
  padding:18px;border-radius:20px;background:var(--a-panel);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.07);
}
.vid-side-h{
  font-size:10.5px;font-weight:700;letter-spacing:.11em;text-transform:uppercase;
  color:var(--a-mute);padding:14px 0 9px;
}
.vid-side-h:first-child{padding-top:0;}
.vid-opts{display:grid;gap:6px;}
.vid-opt{
  display:flex;flex-direction:column;gap:2px;padding:9px 12px;
  border-radius:10px;cursor:pointer;text-align:left;
  background:rgba(255,255,255,.05);
  transition:background-color .25s var(--ease);
}
.vid-opt b{font-size:13.5px;font-weight:600;color:var(--a-ink);}
.vid-opt em{font-style:normal;font-size:11.5px;color:var(--a-mute);}
.vid-opt:hover{background:var(--a-chip-2);}
.vid-opt.is-on{background:var(--a-btn);color:var(--a-btn-ink);}
.vid-opt.is-on b,.vid-opt.is-on em{color:var(--a-btn-ink);}
.vid-opt.is-on b{color:var(--a-btn-ink);}
.vid-opt.is-on em{color:var(--a-btn-ink);}
.vid-pills{display:flex;gap:6px;flex-wrap:wrap;}
.vid-pill{
  padding:7px 14px;border-radius:100px;cursor:pointer;
  font-size:13px;color:var(--a-nav-ink);background:rgba(255,255,255,.05);
  transition:background-color .25s var(--ease),color .25s var(--ease);
}
.vid-pill:hover{background:var(--a-chip-2);color:var(--a-ink);}
.vid-pill.is-on{background:var(--a-btn);color:var(--a-btn-ink);font-weight:600;}
.vid-select{
  width:100%;padding:10px 12px;border:0;border-radius:10px;
  background:rgba(255,255,255,.05);color:var(--a-ink);
  font-family:inherit;font-size:13.5px;cursor:pointer;
}
.vid-go{width:100%;justify-content:center;margin-top:18px;
  background:var(--a-btn)!important;color:var(--a-btn-ink)!important;}
.vid-note{font-size:11.5px;line-height:1.5;color:var(--a-mute);padding-top:11px;}
.vid-note[data-state="warn"]{color:var(--a-ink);}

.vid-gallery{padding-top:64px;}
.vid-gh{font-size:20px;font-weight:500;color:var(--a-ink);padding-bottom:18px;}
.vid-gallery .reel-title{color:var(--a-ink);}
.vid-gallery .reel-card figcaption{padding-top:9px;}

@media (max-width:900px){
  .vid-shell{grid-template-columns:1fr;}
  .vid-drop{min-height:240px;}
}

/* ═══ IMAGE STUDIO — result wall + floating composer ═══
   No page chrome and no copy: the work fills the viewport and the bar
   floats over it. Everything the studio needs is in the bar. */
.gw-body{background:var(--a-bg);}
.gw{padding-bottom:150px;}

/* Rows, not columns. js/wall.js measures each frame and closes a row at
   the height that makes it fill the width exactly, so every tile in a row
   is the same height and no frame is cropped or left with a hole under
   it. The column counts that used to be here — six, then five, four,
   three, two down the breakpoints — are now a target row height instead,
   which is the same idea expressed in the one dimension that matters. */
.gw-wall{
  display:flex;flex-wrap:wrap;align-content:flex-start;
  gap:2px;
}
.gw-cell{
  position:relative;margin:0;overflow:hidden;cursor:zoom-in;
  flex:0 0 auto;
  /* The shape it holds until the layout pass runs, and the shape it keeps
     if scripting never gets there: 3/4 is the sample wall's, and anything
     generated carries the ratio it was asked for. */
  aspect-ratio:var(--gw-ar,3/4);
  width:16.6%;
  background:var(--a-panel);
}
@keyframes gw-in{from{opacity:0;transform:scale(1.03);}to{opacity:1;transform:none;}}
.gw-cell img{
  width:100%;height:100%;object-fit:cover;display:block;
  transition:transform .7s var(--ease),filter .4s var(--ease);
}
/* The frame settles back rather than brightening. Reaching for a control
   should not mean hunting for it against a lit photograph, and the old
   brightness(1.06) pushed the picture the wrong way for that. */
/* ── :focus-visible, not :focus-within ──────────────────────────────
   A mouse click leaves focus on the button it pressed, so :focus-within
   went on matching after the pointer had gone: the rail stayed out, the
   scrim stayed up and the frame stayed zoomed and dimmed, for as long as
   nothing else was clicked. Pressing the heart made a frame look stuck.

   :focus-visible is the same state for somebody arriving by keyboard and
   nothing at all for a click, which is exactly the difference that was
   wanted. Each pair is written as two rules rather than one selector
   list because a browser without :has() drops a whole list on the one
   selector it cannot parse — and that would take the hover with it. */
.gw-cell:hover img{transform:scale(1.045);filter:brightness(.8);}
.gw-cell:has(:focus-visible) img{transform:scale(1.045);filter:brightness(.8);}

/* The scrim is heaviest exactly where the chrome sits — under the rail in
   the top-right corner and along the bottom edge — instead of an even
   wash, which would flatten the work you came here to look at. */
.gw-cell::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:
    radial-gradient(84% 66% at 100% 0%,rgba(6,6,7,.58),rgba(6,6,7,0) 76%),
    linear-gradient(0deg,rgba(6,6,7,.5) 0%,rgba(6,6,7,0) 36%);
  opacity:0;transition:opacity .3s var(--ease);
}
.gw-cell:hover::after{opacity:1;}
.gw-cell:has(:focus-visible)::after{opacity:1;}

.gw-rail{
  position:absolute;top:9px;right:9px;z-index:2;
  display:flex;flex-direction:column;gap:6px;
}
.gw-act{
  display:flex;align-items:center;justify-content:center;
  width:30px;height:30px;border-radius:100px;cursor:pointer;
  /* .62 rather than .5: the rail reaches past the corner scrim, so the
     bottom two buttons have to hold their own icons against whatever the
     photograph does behind them — a pale studio wall is the hard case. */
  background:rgba(10,9,8,.62);color:rgba(255,255,255,.94);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.15);
  backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);
  opacity:0;transform:translateY(-6px) scale(.9);
  transition:opacity .2s var(--ease),transform .2s var(--ease),
             background-color .18s var(--ease),color .18s var(--ease);
}
.gw-act svg{width:14px;height:14px;}
/* a favourited frame says so whether or not the pointer is on it */
.gw-act.is-on{opacity:1;transform:none;background:var(--accent,#c9a227);color:var(--vz-acc-ink);}
/* nothing was recorded for this frame, so Recreate has nothing to run */
.gw-act.is-off{color:rgba(255,255,255,.7);}
/* They arrive one after another and leave together: a stagger on the way
   out reads as the interface lagging behind the pointer. */
.gw-cell:hover .gw-act{
  opacity:1;transform:none;
  transition-delay:calc(var(--n) * 34ms);
}
.gw-cell:has(:focus-visible) .gw-act{
  opacity:1;transform:none;
  transition-delay:calc(var(--n) * 34ms);
}
.gw-act:hover{background:rgba(255,255,255,.2);color:#fff;}
.gw-cell:hover .gw-act:hover{transform:scale(1.09);}
.gw-cell:has(:focus-visible) .gw-act:hover{transform:scale(1.09);}
@media (prefers-reduced-motion: reduce){
  .gw-cell:hover .gw-act{transition-delay:0s;}
  .gw-cell:has(:focus-visible) .gw-act{transition-delay:0s;}
}
/* No pointer to hover with, so a hidden rail is an unreachable one. But
   four buttons on every one of forty-three frames is a wall of chrome, so
   only the heart stays out — a tap opens the window, and the window
   carries the rest of the set. No scrim either: it would dim the whole
   wall permanently. */
@media (hover:none){
  .gw-act{display:none;}
  .gw-act[data-gw-like]{display:flex;opacity:1;transform:none;}
}

/* The old column counts lived here. They are a target row height in
   js/wall.js now — see targetRow() — because with rows the number of
   tiles on a line follows from their shapes, not from a breakpoint. The
   widths below are only what the wall falls back to before that pass
   runs, or without scripting at all. */
@media (max-width:1400px){.gw-cell{width:20%;}}
@media (max-width:1100px){.gw-cell{width:25%;}}
@media (max-width:820px){.gw-cell{width:33.3%;}}
@media (max-width:560px){.gw-cell{width:50%;}}

/* ── floating composer ── */
.gc{
  /* Centred with auto margins rather than translateX(-50%). A transform
     used for layout is fragile: anything that writes transform later — an
     entrance animation, a hover lift — silently knocks the bar off centre,
     which is exactly what happened here, by 465px. Margins cannot be
     clobbered that way. */
  position:fixed;left:0;right:0;margin-inline:auto;bottom:22px;
  z-index:50;width:min(1120px,calc(100vw - 40px));
  padding:14px 14px 12px;border-radius:20px;
  background:color-mix(in srgb,var(--a-panel) 92%,transparent);
  backdrop-filter:blur(26px) saturate(1.4);
  -webkit-backdrop-filter:blur(26px) saturate(1.4);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.08),
    0 0 0 1px rgba(255,255,255,.06),
    0 30px 70px -24px rgba(0,0,0,.9);
}
.gc-top{display:flex;align-items:flex-start;gap:11px;}
.gc-refs{display:flex;gap:7px;flex:0 0 auto;flex-wrap:wrap;max-width:210px;}
/* Past five references the strip stops sharing a line with the prompt and
   takes its own, with the prompt underneath. In the 210px column above,
   ten thumbnails wrap three rows deep and drive the bar tall while the
   prompt keeps whatever width is left; across the full bar the same ten
   sit on one line. js/composer.js sets .is-stacked from the count. */
.gc.is-stacked .gc-top{flex-direction:column;align-items:stretch;gap:8px;}
.gc.is-stacked .gc-refs{max-width:none;}
.gc.is-stacked .gc-input{padding-top:0;padding-left:2px;min-height:34px;}
.gc-ref{
  position:relative;width:42px;height:42px;border-radius:11px;
  overflow:hidden;flex:0 0 auto;
  display:flex;align-items:center;justify-content:center;
}
.gc-ref-add{
  cursor:pointer;color:var(--a-mute);
  background:var(--a-chip);
  transition:background-color .25s var(--ease),color .25s var(--ease);
}
.gc-ref-add svg{width:18px;height:18px;}
.gc-ref-add:hover,.gc-ref-add:focus-visible{background:var(--a-chip-2);color:var(--a-ink);outline:none;}
.gc-ref-add[hidden]{display:none;}
.gc-ref-item img{width:100%;height:100%;object-fit:cover;}
/* The whole thumbnail is the remove button. A 15px circle in the corner
   of a 42px tile is a target you have to aim at, and there is nothing
   else on a reference thumbnail to click — so the button fills it and the
   cross sits in the middle of the scrim. */
.gc-ref-x{
  position:absolute;inset:0;border-radius:inherit;cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  background:rgba(6,6,7,.62);color:#fff;
  font-size:15px;line-height:1;
  opacity:0;transition:opacity .18s var(--ease),background-color .18s var(--ease);
}
.gc-ref-item:hover .gc-ref-x,
.gc-ref-x:focus-visible{opacity:1;}
.gc-ref-x:focus-visible{outline:2px solid var(--vz-acc);outline-offset:-2px;}
.gc-ref-x:active{background:rgba(6,6,7,.76);}
/* No hover to reveal it, so the tile would look inert. It stays fully
   tappable and wears a small corner mark instead of a permanent scrim
   over every thumbnail. */
@media (hover:none){
  .gc-ref-x{opacity:1;background:transparent;font-size:0;}
  .gc-ref-x::after{
    content:"\2715";
    position:absolute;top:2px;right:2px;
    width:16px;height:16px;border-radius:50%;
    display:flex;align-items:center;justify-content:center;
    background:rgba(6,6,7,.74);color:#fff;font-size:9px;line-height:1;
  }
}


.gc-input{
  flex:1;min-width:0;display:block;
  padding:11px 4px 0;border:0;background:transparent;resize:none;
  font-family:inherit;font-size:15px;line-height:1.45;color:var(--a-ink);
  min-height:42px;max-height:180px;
}
.gc-input::placeholder{color:var(--a-mute);}
.gc-input:focus{outline:none;}

.gc-bar{display:flex;align-items:center;gap:10px;padding-top:11px;}
.gc-opts{display:flex;align-items:center;gap:5px;flex:1;min-width:0;flex-wrap:wrap;}
.gc-opt{
  display:flex;align-items:center;gap:7px;white-space:nowrap;
  padding:7px 11px;border-radius:100px;cursor:pointer;
  background:var(--a-chip);color:var(--a-ink);font-size:12.5px;
  transition:background-color .2s var(--ease),color .2s var(--ease);
}
.gc-opt svg{width:13px;height:13px;opacity:.85;}
.gc-opt:hover,.gc-opt[aria-expanded="true"]{background:var(--a-chip-2);color:var(--a-ink);}
.gc-dot{
  width:14px;height:14px;border-radius:50%;flex:0 0 auto;
  background:linear-gradient(135deg,#e8c14a,#8d6f14);
}
.gc-count{
  display:flex;align-items:center;gap:3px;
  padding:3px 5px;border-radius:100px;
  background:var(--a-chip);color:var(--a-ink);font-size:12.5px;
}
.gc-count span{padding:0 5px;}
.gc-count b{color:var(--a-ink);font-weight:600;}
.gc-step{
  width:22px;height:22px;border-radius:50%;cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  color:var(--a-ink);font-size:14px;line-height:1;
  transition:background-color .2s var(--ease);
}
.gc-step:hover{background:var(--a-chip-2);color:var(--a-ink);}
.gc-seg{display:flex;gap:2px;padding:3px;border-radius:100px;background:var(--a-chip);}
.gc-seg button{
  padding:5px 13px;border-radius:100px;cursor:pointer;
  font-size:12.5px;font-weight:500;color:var(--a-mute);
  transition:background-color .2s var(--ease),color .2s var(--ease);
}
.gc-seg button.is-on{background:var(--a-btn);color:var(--a-btn-ink);}

.gc-go{
  display:flex;align-items:center;gap:8px;flex:0 0 auto;
  padding:12px 26px;border-radius:13px;cursor:pointer;
  background:linear-gradient(135deg,#e8c14a,#c9a227);
  color:var(--vz-acc-ink);font-size:14px;font-weight:700;
  box-shadow:0 10px 26px -12px rgba(255,255,255,.8);
  transition:transform .2s var(--ease),box-shadow .2s var(--ease);
}
.gc-go svg{width:15px;height:15px;}
.gc-go:hover{transform:translateY(-1px);box-shadow:0 14px 32px -12px rgba(255,255,255,.95);}

.gc-note{
  padding:10px 4px 0;font-size:12px;line-height:1.5;color:var(--a-nav-ink);
  border-top:1px solid var(--a-line);margin-top:11px;
}
.gc-note[hidden]{display:none;}

/* the popovers open upward out of the floating bar */
.gc .cmp-pop{bottom:calc(100% + 10px);}

@media (max-width:820px){
  .gc{bottom:10px;padding:11px;border-radius:16px;}
  .gc-bar{flex-wrap:wrap;}
  .gc-go{width:100%;justify-content:center;}
  .gw{padding-bottom:210px;}
}

/* ═══ STUDIO SURFACE ═══
   Paper: a light gallery where the work carries the page and the UI
   recedes. Tokens live on <body data-theme="paper">; the wall, nav and
   composer all read from them, so the surface changes in one place. */

[data-theme="paper"]{
  --vz-bg:#eceae6;      --vz-cell:#dedad4;    --vz-gap:10px;
  --vz-nav:#ffffff;     --vz-nav-text:#6d6862; --vz-nav-on:#15130f;
  --vz-surface:rgba(255,255,255,.92);
  --vz-text:#15130f;    --vz-muted:#6d6862;    --vz-chip:rgba(21,19,15,.06);
  --vz-acc:#15130f;     --vz-acc-2:#2c2825;    --vz-acc-ink:#ffffff;
  --vz-radius:18px;
}

/* 3 — Noir & Ice: cool, technical, high contrast. */

/* ── the surfaces that read from the tokens ── */
[data-theme] .gw-body,
body[data-theme]{background:var(--vz-bg);}
[data-theme] .gw-wall{gap:var(--vz-gap);}
[data-theme] .gw-cell{background:var(--vz-cell);border-radius:calc(var(--vz-radius) - 12px);}
/* the heart keeps the glass and colours the glyph, in every theme */
[data-theme] .gw-act.is-on{background:rgba(10,9,8,.62);color:#fff;}


[data-theme] .gc{background:var(--vz-surface);border-radius:var(--vz-radius);}
[data-theme] .gc-input{color:var(--vz-text);}
[data-theme] .gc-input::placeholder{color:var(--vz-muted);}
[data-theme] .gc-opt,[data-theme] .gc-count,[data-theme] .gc-seg,
[data-theme] .gc-ref-add{background:var(--vz-chip);color:var(--vz-text);}
[data-theme] .gc-opt,[data-theme] .gc-count{color:var(--vz-muted);}
[data-theme] .gc-count b{color:var(--vz-text);}
[data-theme] .gc-seg button{color:var(--vz-muted);}
[data-theme] .gc-seg button.is-on{background:var(--vz-text);color:var(--vz-bg);}
[data-theme] .gc-dot{background:linear-gradient(135deg,var(--vz-acc),var(--vz-acc-2));}
[data-theme] .gc-go{
  background:linear-gradient(135deg,var(--vz-acc),var(--vz-acc-2));
  color:var(--vz-acc-ink);
  border-radius:calc(var(--vz-radius) - 7px);
  box-shadow:0 10px 26px -12px color-mix(in srgb,var(--vz-acc) 80%,transparent);
}
[data-theme] .gc-note{color:var(--vz-muted);}
[data-theme] .cmp-pop{background:var(--vz-surface);}
[data-theme] .cmp-mrow-name,[data-theme] .cmp-row b{color:var(--vz-text);}
[data-theme] .cmp-mrow-note,[data-theme] .cmp-row span,
[data-theme] .cmp-pop-head,[data-theme] .cmp-mrow-by{color:var(--vz-muted);}

/* Paper needs the light-surface treatment the dark themes do not */
[data-theme="paper"] .gc{box-shadow:0 0 0 1px rgba(21,19,15,.08),0 30px 70px -30px rgba(0,0,0,.35);}
[data-theme="paper"] .gc-opt:hover,[data-theme="paper"] .gc-step:hover{background:rgba(21,19,15,.11);}
[data-theme="paper"] .cmp-pop{box-shadow:0 0 0 1px rgba(21,19,15,.1),0 26px 54px -20px rgba(0,0,0,.3);}
[data-theme="paper"] .cmp-row:hover,[data-theme="paper"] .cmp-mrow:hover{background:rgba(21,19,15,.06);}
[data-theme="paper"] .cmp-row.is-on,[data-theme="paper"] .cmp-mrow.is-on{background:rgba(21,19,15,.1);}
[data-theme="paper"] .gw-act{background:rgba(255,255,255,.8);color:#15130f;}


/* ═══ ASSET DETAIL ═══
   Restraint is the whole design here. One typographic accent, hairline
   rules instead of filled boxes, a single solid button and everything
   else quiet. The media gets the room; the panel stays out of its way. */
.lb{position:fixed;inset:0;z-index:100;display:flex;align-items:center;justify-content:center;}
.lb-veil{
  position:absolute;inset:0;background:rgba(9,8,7,.62);
  backdrop-filter:blur(28px) saturate(1.15);-webkit-backdrop-filter:blur(28px) saturate(1.15);
  opacity:0;transition:opacity .4s cubic-bezier(.22,1,.36,1);
}
.lb.is-in .lb-veil{opacity:1;}

/* Width and height are set by JS from the asset's real pixel size, so the
   window takes the shape of the work instead of boxing everything into
   one rectangle. These are only the fallback until that lands. */
.lb-box{
  position:relative;display:grid;
  grid-template-columns:minmax(0,1fr) 348px;
  width:min(1840px,calc(100vw - 20px));height:calc(100vh - 20px);
  border-radius:20px;overflow:hidden;
  background:var(--vz-panel,#fff);
  box-shadow:0 2px 6px rgba(0,0,0,.14),0 60px 140px -50px rgba(0,0,0,.75);
  opacity:0;transform:translateY(10px) scale(.995);
  transition:opacity .45s cubic-bezier(.22,1,.36,1),transform .45s cubic-bezier(.22,1,.36,1),
             width .35s cubic-bezier(.22,1,.36,1);
}
.lb.is-in .lb-box{opacity:1;transform:none;}

/* ── stage ── */
.lb-stage{
  position:relative;
  display:flex;align-items:center;justify-content:center;
  /* 44px of stage on every side was 88px of the width the picture could
     have had, and 24 was still 48. Enough is kept for the frame to read as
     mounted and no more — the picture is what was opened. */
  padding:14px;min-width:0;min-height:0;
  background:var(--a-sunk);
}
/* `height:100%` is doing real work here, not tidiness. The image inside is
   capped with `max-height:100%`, and a percentage cap needs a definite
   height to resolve against. With this frame left at auto height that cap
   was silently dropped — only the width applied, so a tall portrait ran
   past the window and had its head clipped by the box's overflow. */
.lb-frame{
  display:flex;align-items:center;justify-content:center;
  max-width:100%;max-height:100%;
  width:100%;height:100%;min-height:0;min-width:0;
}
/* The picture takes the whole stage. `width:auto` under a max cap meant a
   768px generation was drawn at 768px in a frame with room for 912 — small
   and marooned in dark veil, which is exactly what it looked like. The
   stage is already cut to this picture's own aspect by shape(), so filling
   it changes the size and nothing else; `contain` keeps it honest, and
   never crops, if the two ever disagree by a pixel. */
.lb-frame img,.lb-frame video{
  max-width:100%;max-height:100%;
  width:100%;height:100%;object-fit:contain;display:block;
  border-radius:4px;
  /* drop-shadow rather than box-shadow: it follows what is actually
     painted. Stacked on a phone the stage keeps whatever shape is left
     over, so a portrait is centred inside a wider box — a box-shadow
     there is cast by the box, hanging in the veil to either side of the
     picture it is supposed to be lifting. */
  filter:drop-shadow(0 34px 70px rgba(0,0,0,.85));
}
/* arrows sit quiet until the stage is hovered */
.lb-nav{
  position:absolute;top:50%;transform:translateY(-50%);
  width:40px;height:40px;border-radius:100px;cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  background:rgba(255,255,255,.09);color:rgba(255,255,255,.9);
  backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);
  opacity:0;transition:opacity .3s var(--ease),background-color .2s var(--ease);
}
.lb-nav svg{width:15px;height:15px;}
.lb-prev{left:18px;}
.lb-next{right:18px;}
.lb-stage:hover .lb-nav{opacity:1;}
.lb-nav:hover{background:rgba(255,255,255,.18);}
.lb-count{
  position:absolute;left:50%;bottom:18px;transform:translateX(-50%);
  padding:5px 12px;border-radius:100px;
  background:rgba(255,255,255,.08);color:rgba(255,255,255,.62);
  font-size:11px;font-variant-numeric:tabular-nums;letter-spacing:.04em;
  backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);
  opacity:0;transition:opacity .3s var(--ease);
}
.lb-stage:hover .lb-count{opacity:1;}

/* ── panel ── */
.lb-panel{
  display:flex;flex-direction:column;min-width:0;min-height:0;
  background:var(--vz-panel,#fff);
}
.lb-head{
  position:relative;
  padding:30px 30px 22px;
  border-bottom:1px solid var(--vz-line,var(--line));
}
.lb-kicker{
  display:block;
  font-size:10px;font-weight:600;letter-spacing:.16em;text-transform:uppercase;
  color:var(--vz-muted,var(--ink-mute));
}
.lb-h{
  padding-top:9px;
  font-size:25px;font-weight:500;letter-spacing:-.025em;line-height:1.1;
  color:var(--vz-text,var(--ink-strong));
}
.lb-x{
  position:absolute;top:26px;right:26px;
  width:30px;height:30px;border-radius:100px;cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  color:var(--vz-muted,var(--ink-mute));
  transition:background-color .2s var(--ease),color .2s var(--ease);
}
.lb-x svg{width:14px;height:14px;}
.lb-x:hover{background:var(--vz-chip,rgba(21,19,15,.06));color:var(--vz-text,var(--ink-strong));}

.lb-scroll{flex:1;min-height:0;overflow-y:auto;padding:26px 30px 8px;}
.lb-sec{padding-bottom:28px;}
.lb-sec:last-child{padding-bottom:8px;}
.lb-sec-h{
  display:flex;align-items:center;justify-content:space-between;gap:10px;
  padding-bottom:11px;
  font-size:10px;font-weight:600;letter-spacing:.16em;text-transform:uppercase;
  color:var(--vz-muted,var(--ink-mute));
}
.lb-copy{
  padding:0;cursor:pointer;background:none;
  font-size:10.5px;font-weight:600;letter-spacing:.02em;text-transform:none;
  color:var(--vz-text,var(--ink-strong));
  border-bottom:1px solid var(--vz-line,var(--line));
  transition:border-color .2s var(--ease),opacity .2s var(--ease);
}
.lb-copy:hover{border-color:currentColor;}

/* the prompt is the one place with real reading weight */
.lb-prompt{
  font-size:14.5px;line-height:1.65;
  color:var(--vz-text,var(--ink-strong));
  letter-spacing:-.005em;
}
.lb-prompt.lb-none{color:var(--vz-muted,var(--ink-mute));font-size:13.5px;}

.lb-rows{display:flex;flex-direction:column;}
.lb-rows > div{
  display:flex;align-items:baseline;justify-content:space-between;gap:18px;
  padding:11px 0;border-top:1px solid var(--vz-line,var(--line));
}
.lb-rows > div:first-child{border-top:0;padding-top:0;}
.lb-rows dt{font-size:13px;color:var(--vz-muted,var(--ink-mute));white-space:nowrap;}
.lb-rows dd{
  font-size:13px;font-weight:500;text-align:right;
  color:var(--vz-text,var(--ink-strong));
  font-variant-numeric:tabular-nums;word-break:break-word;
}

.lb-flag{
  font-size:12px;line-height:1.55;
  padding:12px 0 0;margin-top:4px;
  border-top:1px solid var(--vz-line,var(--line));
  color:var(--vz-muted,var(--ink-mute));
}

/* ── actions ── */
.lb-actions{
  display:flex;flex-direction:column;gap:9px;
  padding:20px 30px 26px;
  border-top:1px solid var(--vz-line,var(--line));
}
.lb-primary{
  display:flex;align-items:center;justify-content:center;gap:9px;
  padding:14px;border-radius:11px;cursor:pointer;
  background:var(--vz-text,var(--ink-strong));
  color:var(--vz-panel,#fff);
  font-size:14px;font-weight:600;letter-spacing:-.01em;
  transition:opacity .2s var(--ease),transform .2s var(--ease);
}
.lb-primary svg{width:16px;height:16px;}
.lb-primary:hover{opacity:.86;transform:translateY(-1px);}
/* Recreate and Reference: the two that put the picture back into the
   composer, and the only two here that work without a server. */
.lb-duo{display:grid;grid-template-columns:1fr 1fr;gap:9px;}
.lb-ic{display:flex;align-items:center;justify-content:center;gap:8px;}
.lb-ic svg{width:15px;height:15px;flex:none;}
.lb-pair{display:grid;grid-template-columns:1fr 1fr;gap:9px;}
.lb-btn{
  padding:12px;border-radius:11px;cursor:pointer;
  font-size:13.5px;font-weight:500;
  color:var(--vz-text,var(--ink-strong));
  box-shadow:inset 0 0 0 1px var(--vz-line,var(--line));
  transition:box-shadow .2s var(--ease),background-color .2s var(--ease);
}
.lb-btn:hover{box-shadow:inset 0 0 0 1px var(--vz-muted,#b8b2ab);}
.lb-btn[disabled]{opacity:.35;pointer-events:none;}
/* Muted rather than `disabled`: with nothing recorded for a frame the
   button still has to answer a press and say why it cannot run, and a
   disabled control swallows the click and explains nothing. */
.lb-btn.is-off{color:var(--a-mute);}
.lb-btn.is-off:hover{color:var(--a-ink);}

/* the quiet tier, for going somewhere rather than doing something */
.lb-ghosts{display:flex;align-items:center;gap:12px;padding:3px 0 1px;}
/* These follow the app theme, not the marketing palette. --vz-muted is a
   site token and does not change with data-app, so in dark mode this text
   stayed light-grey against a dark panel and measured 2.89:1. */
.lb-ghost{
  padding:5px 0;cursor:pointer;
  font-size:12.5px;color:var(--a-mute);
  transition:color .2s var(--ease);
}
.lb-ghost:hover{color:var(--a-ink);}
.lb-sep{width:1px;height:11px;background:var(--vz-line,var(--line));}

.lb-mini{display:flex;gap:4px;padding-top:3px;}
.lb-icon{
  flex:1;height:38px;border-radius:10px;cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  color:var(--a-mute);
  transition:background-color .2s var(--ease),color .2s var(--ease);
}
.lb-icon svg{width:16px;height:16px;}
.lb-icon:hover{background:var(--vz-chip,rgba(21,19,15,.05));color:var(--vz-text,var(--ink-strong));}
.lb-icon.is-on{color:var(--a-ink,var(--ink-strong));}
.lb-icon.is-danger:hover{background:rgba(255,255,255,.1);color:var(--a-danger);}

@media (max-width:1000px){
  .lb-box{
    grid-template-columns:1fr;grid-template-rows:minmax(0,1fr) auto;
    width:calc(100vw - 20px);height:calc(100vh - 20px);
  }
  /* stacked: the panel scrolls anyway, so it takes less than half the
     window and leaves the rest to the picture */
  .lb-panel{max-height:47vh;border-top:1px solid var(--vz-line,var(--line));}
  .lb-stage{padding:20px;}
  .lb-head{padding:20px 20px 16px;}
  .lb-scroll{padding:18px 20px 6px;}
  .lb-actions{padding:16px 20px 20px;}
  .lb-nav{opacity:1;}
}

/* ═══ ACCENT VARIANTS ═══
   Accent only — the surfaces (paper / dark) are untouched, so these
   compose with whatever theme a page is already using. Set on <html>
   as data-accent. Once one is chosen, keep that block, delete the rest
   and drop the picker. */

/* current: muted gold */
[data-accent="gold"]{
  --accent:#c9a227;
  --vz-acc:#e8c14a; --vz-acc-2:#c9a227; --vz-acc-ink:#171512;
  --vz-nav-on:#e8c14a;
}
/* full yellow — the reference tone: bright, warm, and FLAT.
   The previous pair faded to #ffc800, and a gradient with amber at the
   bottom reads as gold, not yellow — which is why it looked "darker"
   than the colour it was named after. The two stops now sit a hair
   apart, so the fill keeps a little dimension without changing hue. */
[data-accent="yellow"]{
  --accent:#ffd42b;
  --vz-acc:#ffd42b; --vz-acc-2:#ffc90a; --vz-acc-ink:#171200;
  --vz-nav-on:#ffd42b;
}
/* full orange — warmer, heavier, more retail than editorial */
[data-accent="orange"]{
  --accent:#ff6b1f;
  --vz-acc:#ff8a4c; --vz-acc-2:#f2560a; --vz-acc-ink:#1f0d02;
  --vz-nav-on:#ff7a35;
}
/* mono — no hue at all, contrast does the work */
/* The greys here sit on the exact neutral axis. The first pass at mono
   kept the warm values the yellow theme used (#f4f2f0, #d8d4d0, #15130f)
   and the result read as bone rather than as white — over a whole
   interface that reads as a colour scheme nobody chose. */
[data-accent="mono"]{
  --accent:#f4f4f4;
  --vz-acc:#ffffff; --vz-acc-2:#d6d6d6; --vz-acc-ink:#0d0d0d;
  --vz-nav-on:#ffffff;
}
/* on a light surface mono has to invert or it disappears.

   `data-theme="paper"` alone was not enough: the app carries its light
   and dark state on `data-app`, not `data-theme`, so in the studio's
   light mode the accent stayed #ffffff and every accented control — the
   Generate button among them — was white on a near-white page. Both
   attributes are matched now. */
[data-accent="mono"][data-theme="paper"],
[data-theme="paper"] [data-accent="mono"],
[data-accent="mono"][data-app="light"],
[data-app="light"] [data-accent="mono"]{
  --accent:#121212;
  --vz-acc:#121212; --vz-acc-2:#2b2b2b; --vz-acc-ink:#ffffff;
  --vz-nav-on:#121212;
  --acc-text:#121212;
}
/* and the dark side needs its own readable text tone */
[data-accent="mono"][data-app="dark"],
[data-app="dark"] [data-accent="mono"]{
  --acc-text:#ffffff;
}

/* the few places that still name the old gold directly */
[data-accent] .anav-badge{
  background:var(--vz-acc);
  color:var(--vz-acc-ink);
}
[data-accent] .anav-upgrade{
  background:linear-gradient(135deg,var(--vz-acc),var(--vz-acc-2));
  color:var(--vz-acc-ink);
}
[data-accent] .anav .app-avatar{
  background:linear-gradient(135deg,var(--vz-acc),var(--vz-acc-2));
  color:var(--vz-acc-ink);
}
[data-accent] .anav-credits::before{color:var(--vz-acc);}
[data-accent] .vid-eyebrow{color:var(--vz-acc);}
[data-accent] .gc-dot,
[data-accent] .lb-dot{background:linear-gradient(135deg,var(--vz-acc),var(--vz-acc-2));}
[data-accent] .gc-go{
  background:linear-gradient(135deg,var(--vz-acc),var(--vz-acc-2));
  color:var(--vz-acc-ink);
  box-shadow:0 10px 26px -12px color-mix(in srgb,var(--vz-acc) 75%,transparent);
}
[data-accent] .set-avatar{
  background:radial-gradient(circle at 40% 35%,
    color-mix(in srgb,var(--vz-acc) 55%,#fff),var(--vz-acc-2) 72%);
}
[data-accent] .as-side-row.is-on .as-side-ic{color:var(--vz-acc);}
[data-accent] .tpl-cats-nav:hover{box-shadow:0 10px 24px -6px rgba(0,0,0,.36),inset 0 0 0 1px var(--vz-acc);}

/* mono keeps the gold out of the dark nav too */
[data-accent="mono"] .anav-upgrade{background:#f4f2f0;color:#0c0c0c;}
[data-accent="mono"] .anav .app-avatar{background:#3a3734;color:#f4f2f0;}

/* ── picker (temporary) ── */
.acw{
  position:fixed;right:16px;bottom:16px;z-index:95;
  display:flex;align-items:center;gap:8px;
  padding:8px 10px;border-radius:100px;
  background:rgba(20,19,18,.94);
  backdrop-filter:blur(18px);-webkit-backdrop-filter:blur(18px);
  box-shadow:0 0 0 1px rgba(255,255,255,.1),0 20px 44px -18px rgba(0,0,0,.8);
}
.acw-l{
  font-size:9.5px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;
  color:var(--a-mute);padding-right:2px;
}
.acw-sw{
  width:26px;height:26px;border-radius:50%;cursor:pointer;flex:0 0 auto;
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.22);
  transition:transform .2s ease,box-shadow .2s ease;
}
.acw-sw:hover{transform:scale(1.12);}
.acw-sw.is-on{box-shadow:0 0 0 2px #141312,0 0 0 4px currentColor;}
@media (max-width:700px){.acw{display:none;}}

/* ═══ APP SURFACE: LIGHT / DARK ═══
   One switch for the whole app. Light is a white page with black
   controls; dark inverts both. Every surface reads from these tokens so
   nothing has to be restyled per page. Set on <html> as data-app. */
/* Every value on the neutral axis. These carried a warm cast — #f2f0ed,
   #15130f, #9c968e — which is invisible on one chip and unmistakable
   across a whole interface: the studio read as bone and sand rather than
   as black and white. The alpha-based lines and chips were already
   neutral and are left alone. */
[data-app="light"]{
  --a-bg:#f3f3f3;      --a-panel:#ffffff;   --a-sunk:#e8e8e8;
  --a-line:rgba(18,18,18,.10);
  --a-ink:#121212;     --a-mute:#6b6b6b;
  --a-btn:#121212;     --a-btn-ink:#ffffff;  /* black buttons */
  --a-chip:rgba(18,18,18,.055);
  --a-danger:#1a1a1a;
  --a-chip-2:rgba(18,18,18,.11);
  --a-nav:#ffffff;     --a-nav-ink:#6b6b6b;
  --a-nav-glass:rgba(255,255,255,.72);
  --a-shadow:0 20px 44px -28px rgba(0,0,0,.35);
}
[data-app="dark"]{
  --a-bg:#0a0a0a;      --a-panel:#151515;   --a-sunk:#0e0e0e;
  --a-line:rgba(255,255,255,.09);
  --a-ink:#f4f4f4;     --a-mute:#9a9a9a;
  --a-btn:#f4f4f4;     --a-btn-ink:#131313;  /* white buttons */
  --a-chip:rgba(255,255,255,.07);
  --a-danger:#ffffff;
  --a-chip-2:rgba(255,255,255,.14);
  --a-nav:#0d0d0d;     --a-nav-ink:#a0a0a0;
  --a-nav-glass:rgba(13,13,12,.7);
  --a-shadow:0 24px 50px -30px rgba(0,0,0,.8);
}

[data-app] .app-body,
[data-app] .gw-body,
[data-app] .vid-body{background:var(--a-bg);}

/* nav */

/* headings and body copy */
[data-app] .hub-title,[data-app] .xp-h1,[data-app] .vid-h1,
[data-app] .as-title,[data-app] .as-day-h,[data-app] .as-sec-title,
[data-app] .ed-title,[data-app] .vid-gh,[data-app] .tpl-count,
[data-app] .set-name{color:var(--a-ink);}
[data-app] .hub-sub,[data-app] .xp-sub,[data-app] .vid-sub,
[data-app] .as-note,[data-app] .ed-sub{color:var(--a-mute);}

/* panels, cards and sunken wells */
[data-app] .hub-card,[data-app] .xp-card,[data-app] .as-card,
[data-app] .tpl-card,[data-app] .ut-side,[data-app] .vid-side,
[data-app] .ed-panel,[data-app] .set-card,[data-app] .set-row,
[data-app] .vid-prompt,[data-app] .tpl-cat,[data-app] .as-filter,
[data-app] .tpl-search input{
  background:var(--a-panel);
  box-shadow:inset 0 0 0 1px var(--a-line);
  color:var(--a-ink);
}
[data-app] .hub-card-title,[data-app] .xp-name,[data-app] .tpl-cat-label,
[data-app] .xp-sec-h h2,
[data-app] .ut-side-h,[data-app] .vid-side-h{color:var(--a-ink);}
[data-app] .hub-card-text,[data-app] .xp-desc,[data-app] .tpl-cat-n,
[data-app] .xp-sec-h p,[data-app] .xp-sec-n,
[data-app] .xp-kind,[data-app] .as-sec-note{color:var(--a-mute);}
[data-app] .xp-sec-h::after{background:var(--a-line);}
[data-app] .xp-sec-n{background:var(--a-chip);}
[data-app] .ut-stage,[data-app] .ed-stage,[data-app] .vid-drop{
  background:var(--a-sunk);
}
[data-app] .as-side{border-right-color:var(--a-line);}
[data-app] .as-side-row{color:var(--a-ink);}
[data-app] .as-side-row:hover,[data-app] .as-side-row.is-on{background:var(--a-chip);}
[data-app] .as-side-h,[data-app] .as-side-n,[data-app] .as-side-ic{color:var(--a-mute);}

/* ═══ BUTTON SHEEN ═══
   Flat fills read as painted-on. A top-down gradient plus a hairline of
   light along the upper edge makes the same colour look lit, which is
   the whole difference between a cheap button and an expensive one. */
[data-app] .btn-dark,
[data-app] .vid-go,
[data-app] .gc-go,
[data-app] .lb-primary,
[data-app] .set-topup,
[data-app] .as-modal-new button,
[data-app] .ut-run,
[data-app] .acc-get{
  position:relative;overflow:hidden;
  background-image:linear-gradient(180deg,
    rgba(255,255,255,.16) 0%,
    rgba(255,255,255,0) 42%,
    rgba(0,0,0,.06) 100%);
  background-color:var(--a-btn);
  color:var(--a-btn-ink);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.22),
    inset 0 -1px 0 rgba(0,0,0,.14),
    0 1px 2px rgba(0,0,0,.18),
    0 8px 20px -10px rgba(0,0,0,.4);
  transition:transform .2s var(--ease),box-shadow .25s var(--ease),filter .25s var(--ease);
}
/* light theme: the button is black, so the sheen has to come from above
   rather than a white wash that would grey it out */
[data-app="light"] .btn-dark,
[data-app="light"] .vid-go,
[data-app="light"] .gc-go,
[data-app="light"] .lb-primary,
[data-app="light"] .set-topup,
[data-app="light"] .ut-run,
[data-app="light"] .as-modal-new button{
  background-image:linear-gradient(180deg,
    rgba(255,255,255,.22) 0%,
    rgba(255,255,255,.04) 46%,
    rgba(0,0,0,.10) 100%);
}
[data-app] .btn-dark:hover,
[data-app] .vid-go:hover,
[data-app] .gc-go:hover,
[data-app] .lb-primary:hover,
[data-app] .set-topup:hover,
[data-app] .ut-run:hover{
  transform:translateY(-1px);
  filter:brightness(1.06);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.28),
    inset 0 -1px 0 rgba(0,0,0,.16),
    0 2px 4px rgba(0,0,0,.2),
    0 14px 28px -10px rgba(0,0,0,.45);
}
/* a slow highlight that crosses the face on hover */
[data-app] .btn-dark::before,
[data-app] .vid-go::before,
[data-app] .gc-go::before,
[data-app] .lb-primary::before{
  content:"";position:absolute;inset:0;
  background:linear-gradient(105deg,
    transparent 35%,
    rgba(255,255,255,.20) 50%,
    transparent 65%);
  transform:translateX(-120%);
  transition:transform .75s cubic-bezier(.22,1,.36,1);
  pointer-events:none;
}
[data-app] .btn-dark:hover::before,
[data-app] .vid-go:hover::before,
[data-app] .gc-go:hover::before,
[data-app] .lb-primary:hover::before{transform:translateX(120%);}
@media (prefers-reduced-motion:reduce){
  [data-app] .btn-dark::before,[data-app] .vid-go::before,
  [data-app] .gc-go::before,[data-app] .lb-primary::before{display:none;}
}

/* quieter buttons get a lighter version of the same idea */
[data-app] .ed-btn,[data-app] .lb-btn,[data-app] .ut-preset,
[data-app] .vid-pill,[data-app] .gc-opt,[data-app] .as-filter,
[data-app] .ed-mini,[data-app] .lb-icon,[data-app] .acw-sw{
  background-image:linear-gradient(180deg,rgba(255,255,255,.07),rgba(0,0,0,.03));
}
[data-app="light"] .ed-btn,[data-app="light"] .lb-btn,
[data-app="light"] .ut-preset,[data-app="light"] .as-filter{
  background-image:linear-gradient(180deg,rgba(255,255,255,.9),rgba(20,18,16,.03));
}

/* ═══ ACCOUNT MENU ═══ */
.acc{
  position:fixed;z-index:90;width:296px;
  padding:8px;border-radius:18px;
  background:var(--a-panel,#151312);
  box-shadow:
    inset 0 0 0 1px var(--a-line,rgba(255,255,255,.09)),
    0 30px 64px -22px rgba(0,0,0,.7);
  opacity:0;transform:translateY(-6px) scale(.985);
  transition:opacity .22s var(--ease),transform .22s var(--ease);
}
.acc.is-in{opacity:1;transform:none;}
.acc-id{display:flex;align-items:center;gap:11px;padding:10px 10px 14px;}
.acc-face{
  width:38px;height:38px;border-radius:50%;flex:0 0 auto;
  display:flex;align-items:center;justify-content:center;
  font-size:13px;font-weight:600;
  background:linear-gradient(135deg,var(--vz-acc,#e8c14a),var(--vz-acc-2,#c9a227));
  color:var(--vz-acc-ink,#171512);
}
.acc-who{display:flex;flex-direction:column;gap:2px;min-width:0;}
.acc-who b{font-size:14px;font-weight:600;color:var(--a-ink,#f4f2f0);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.acc-who em{font-style:normal;font-size:11.5px;color:var(--a-mute,#9c968e);}

.acc-credits{
  display:block;padding:12px 12px 13px;border-radius:13px;
  background:var(--a-chip,rgba(255,255,255,.05));
}
.acc-credits-top{display:flex;align-items:center;justify-content:space-between;gap:10px;}
.acc-credits-top > span:first-child{font-size:13px;font-weight:600;color:var(--a-ink,#f4f2f0);}
.acc-credits-n{
  display:flex;align-items:center;gap:5px;
  font-size:12.5px;color:var(--a-mute,#9c968e);
}
.acc-credits-n svg{width:12px;height:12px;}


.acc-offers{padding:8px 0 6px;}
.acc-offer{
  display:flex;align-items:center;gap:11px;
  padding:8px 10px;border-radius:11px;
  font-size:13.5px;color:var(--a-ink,#e6e2de);
}
.acc-offer svg{width:16px;height:16px;flex:0 0 auto;color:var(--vz-acc,#e8c14a);}
.acc-offer span{flex:1;min-width:0;}
.acc-get{
  padding:5px 14px;border-radius:100px;flex:0 0 auto;
  font-size:12px;font-weight:700;
  background:var(--vz-acc,#e8c14a);color:var(--vz-acc-ink,#171512);
  transition:filter .2s var(--ease);
}
.acc-get:hover{filter:brightness(1.08);}

.acc-links{padding-top:6px;border-top:1px solid var(--a-line,rgba(255,255,255,.08));}
.acc-link{
  display:flex;align-items:center;gap:11px;width:100%;
  padding:9px 10px;border-radius:11px;cursor:pointer;text-align:left;
  font-size:13.5px;color:var(--a-ink,#e6e2de);
  transition:background-color .18s var(--ease);
}
.acc-link svg{width:16px;height:16px;flex:0 0 auto;opacity:.75;}
.acc-link:hover{background:var(--a-chip,rgba(255,255,255,.06));}
.acc-val{
  margin-left:auto;display:flex;align-items:center;gap:5px;
  font-size:12.5px;color:var(--a-mute,#9c968e);
}
.acc-val svg{width:9px;height:9px;opacity:1;}
.acc-langs{padding:2px 0 4px 37px;}
.acc-langrow{
  display:flex;align-items:center;gap:8px;width:100%;
  padding:7px 10px;border-radius:9px;cursor:pointer;text-align:left;
  font-size:13px;color:var(--a-mute,#9c968e);
  transition:background-color .18s var(--ease),color .18s var(--ease);
}
.acc-langrow em{
  font-style:normal;font-size:10px;margin-left:auto;
  color:var(--a-mute,#6f6a65);opacity:.75;
}
.acc-langrow:hover{background:var(--a-chip,rgba(255,255,255,.06));color:var(--a-ink,#f4f2f0);}
.acc-langrow.is-on{color:var(--a-ink,#f4f2f0);font-weight:600;}
.acc-out{
  margin-top:6px;padding-top:11px;
  border-top:1px solid var(--a-line,rgba(255,255,255,.08));
  border-radius:0 0 11px 11px;
}

/* ═══ UPLOAD TRAY ═══
   Several images at once, shown as a grid of thumbs with an add tile.
   The first one is marked so it is obvious which drives the result. */
.tray{display:grid;grid-template-columns:repeat(4,1fr);gap:8px;}
.tray-cell{
  position:relative;aspect-ratio:1;border-radius:13px;overflow:hidden;
  background:var(--a-sunk,#0f0e0d);
  box-shadow:inset 0 0 0 1px var(--a-line,rgba(255,255,255,.08));
}
.tray-cell img{width:100%;height:100%;object-fit:cover;display:block;}
.tray-x{
  position:absolute;top:5px;right:5px;
  width:20px;height:20px;border-radius:50%;cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  background:rgba(8,7,6,.66);color:#fff;font-size:10px;line-height:1;
  opacity:0;transition:opacity .2s var(--ease);
  backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);
}
.tray-cell:hover .tray-x{opacity:1;}
.tray-add{
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:5px;
  cursor:pointer;color:var(--a-mute,#9c968e);
  border:1px dashed var(--a-line,rgba(255,255,255,.16));
  box-shadow:none;
  transition:border-color .25s var(--ease),color .25s var(--ease);
}
.tray-add svg{width:20px;height:20px;}
.tray-add span{font-size:10.5px;}
.tray-add:hover,.tray-add:focus-within{
  border-color:var(--a-mute,#5d5852);color:var(--a-ink,#f4f2f0);
}
@media (max-width:620px){.tray{grid-template-columns:repeat(3,1fr);}}

/* ═══ SETTINGS ═══ */
.set-main{padding:44px 0 90px;}
.set-shell{display:grid;grid-template-columns:236px minmax(0,1fr);gap:34px;align-items:start;}

.set-ws{
  font-size:12px;color:var(--vz-muted,var(--ink-mute));
  padding:0 10px 12px;
}
.set-nav{display:flex;flex-direction:column;gap:3px;}
.set-navlink{
  display:flex;align-items:center;gap:11px;
  padding:9px 11px;border-radius:11px;cursor:pointer;text-align:left;
  font-size:14px;font-weight:500;color:var(--vz-text,var(--ink-strong));
  transition:background-color .2s var(--ease);
}
.set-navlink:hover{background:var(--vz-chip,rgba(21,19,15,.05));}
.set-navlink.is-on{background:var(--vz-chip,rgba(21,19,15,.07));}
.set-ic{
  width:26px;height:26px;border-radius:8px;flex:0 0 auto;
  display:flex;align-items:center;justify-content:center;color:#fff;
}
.set-ic svg{width:14px;height:14px;}
/* five settings tiles that were pink, teal, indigo and gold. Each one
   already carries its own glyph, so the hue was decoration; a ladder of
   greys keeps them distinguishable without breaking the palette. */
.set-ic[data-c="profile"]{background:#1b1b1b;}
.set-ic[data-c="plan"]{background:#333333;}
.set-ic[data-c="usage"]{background:#4b4b4b;}
.set-ic[data-c="promo"]{background:#5f5f5f;}
.set-ic[data-c="look"]{background:#737373;}

.set-pane[hidden]{display:none;}

.set-id{display:flex;align-items:center;gap:18px;padding-bottom:26px;}
.set-avatar{
  width:84px;height:84px;border-radius:50%;flex:0 0 auto;
  background:radial-gradient(circle at 40% 35%,#f2e9a8,#c9a227 70%);
  display:flex;align-items:center;justify-content:center;
  font-size:26px;font-weight:600;color:#fff;
}
.set-name{
  display:flex;align-items:center;gap:10px;
  font-size:28px;font-weight:600;letter-spacing:-.02em;color:var(--ink-strong);
}
.set-edit{
  display:inline-flex;align-items:center;gap:5px;
  padding:4px 10px;border-radius:100px;cursor:pointer;
  font-size:11.5px;font-weight:500;
  background:var(--vz-chip,rgba(21,19,15,.06));
  color:var(--vz-text,var(--ink));
}
.set-edit svg{width:11px;height:11px;}
.set-email{font-size:13.5px;color:var(--vz-muted,var(--ink-mute));padding-top:5px;}

.set-promo{
  display:flex;align-items:center;gap:12px;flex-wrap:wrap;
  padding:14px 18px;border-radius:14px;margin-bottom:20px;
  background:linear-gradient(100deg,var(--vz-acc,#c9a227),var(--vz-acc-2,#a8861c));
  color:var(--vz-acc-ink,#171512);font-size:14px;font-weight:600;
}
.set-promo-tag{
  display:inline-flex;align-items:center;gap:6px;
  padding:4px 10px;border-radius:100px;
  background:rgba(0,0,0,.22);
  font-size:10px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;
}

.set-cards{display:grid;grid-template-columns:repeat(2,1fr);gap:14px;}
.set-card{
  padding:20px;border-radius:16px;
  background:var(--vz-panel,var(--white));
  box-shadow:inset 0 0 0 1px var(--vz-line,var(--line));
}
.set-card-h{
  display:flex;align-items:center;gap:8px;
  font-size:12.5px;color:var(--vz-muted,var(--ink-mute));padding-bottom:22px;
}
.set-card-h svg{width:15px;height:15px;}
.set-big{font-size:27px;font-weight:600;letter-spacing:-.02em;color:var(--vz-text,var(--ink-strong));}
.set-small{font-size:12.5px;color:var(--vz-muted,var(--ink-mute));padding-top:5px;}
.set-card-foot{display:flex;align-items:flex-end;justify-content:space-between;gap:14px;}
.set-topup{
  padding:9px 18px;border-radius:100px;cursor:pointer;flex:0 0 auto;
  background:var(--vz-text,var(--ink-strong));color:var(--vz-bg,var(--white));
  font-size:13px;font-weight:600;
}
.set-meter{height:5px;border-radius:100px;margin-top:14px;overflow:hidden;
  background:var(--vz-chip,rgba(21,19,15,.08));}
.set-meter i{display:block;height:100%;border-radius:100px;
  background:linear-gradient(90deg,var(--vz-acc,#c9a227),var(--vz-acc-2,#a8861c));}

.set-rows{margin-top:14px;}
.set-row{
  display:flex;align-items:center;justify-content:space-between;gap:18px;
  padding:15px 20px;
  background:var(--vz-panel,var(--white));
  box-shadow:inset 0 0 0 1px var(--vz-line,var(--line));
}
.set-row:first-child{border-radius:16px 16px 0 0;}
.set-row:last-child{border-radius:0 0 16px 16px;}
.set-row + .set-row{margin-top:-1px;}
.set-row-t{font-size:14px;font-weight:500;color:var(--vz-text,var(--ink-strong));}
.set-row-s{font-size:12.5px;color:var(--vz-muted,var(--ink-mute));padding-top:3px;}

/* switch */
.set-sw{
  position:relative;width:42px;height:24px;border-radius:100px;flex:0 0 auto;
  cursor:pointer;background:var(--vz-chip,rgba(21,19,15,.14));
  transition:background-color .25s var(--ease);
}
.set-sw::after{
  content:"";position:absolute;top:3px;left:3px;
  width:18px;height:18px;border-radius:50%;background:#fff;
  box-shadow:0 1px 3px rgba(0,0,0,.3);
  transition:transform .25s var(--ease);
}
.set-sw.is-on{background:var(--vz-acc,#c9a227);}
.set-sw.is-on::after{transform:translateX(18px);}

/* theme picker */
.set-themes{display:grid;grid-template-columns:repeat(2,1fr);gap:12px;margin-top:14px;}
.set-theme{
  padding:12px;border-radius:16px;cursor:pointer;text-align:left;
  background:var(--vz-panel,var(--white));
  box-shadow:inset 0 0 0 1px var(--vz-line,var(--line));
  transition:box-shadow .25s var(--ease),transform .25s var(--ease);
}
.set-theme:hover{transform:translateY(-2px);}
.set-theme.is-on{box-shadow:inset 0 0 0 2px var(--vz-acc,#c9a227);}
.set-theme-prev{
  height:74px;border-radius:11px;overflow:hidden;margin-bottom:10px;
  display:flex;flex-direction:column;
}
.set-theme-bar{height:16px;}
.set-theme-body{flex:1;display:flex;align-items:flex-end;padding:7px;}
.set-theme-pill{height:14px;width:52px;border-radius:100px;}
.set-theme-n{font-size:13.5px;font-weight:600;color:var(--vz-text,var(--ink-strong));}
.set-theme-d{font-size:11.5px;color:var(--vz-muted,var(--ink-mute));padding-top:2px;}

.set-danger{
  margin-top:22px;padding:16px 20px;border-radius:16px;
  display:flex;align-items:center;justify-content:space-between;gap:18px;
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.28);
}
.set-out{
  padding:8px 16px;border-radius:100px;cursor:pointer;
  background:rgba(255,255,255,.12);color:var(--a-danger);font-size:13px;font-weight:600;
}

@media (max-width:820px){
  .set-shell{grid-template-columns:1fr;gap:20px;}
  .set-cards,.set-themes{grid-template-columns:1fr;}
  .set-nav{flex-direction:row;overflow-x:auto;}
}

/* ═══ ACCENT: FILL vs TEXT ═══
   A bright accent is fine as a FILL with dark ink on it, and unreadable
   as TEXT on a light page — yellow on white measured 1.73:1 where 4.5
   is the minimum. So the accent carries two values: --vz-acc paints
   surfaces, --acc-text is the darkened version used for words. In dark
   mode the two converge, because bright on near-black already passes. */
/* Yellow is the one accent with no readable text form on a light page:
   to clear 4.5:1 it has to go so dark it stops looking yellow at all.
   The reference site solves this by never setting a letter in yellow —
   yellow is a fill, letters on it are black. Same rule here. */
[data-accent="yellow"]{ --acc-text:#15130f; }
[data-accent="orange"]{ --acc-text:#9c3a00; }
[data-accent="gold"]  { --acc-text:#7a6115; }
[data-accent="mono"]  { --acc-text:#15130f; }

/* on near-black the same yellow clears 4.5:1 easily, so words may wear it */
[data-app="dark"][data-accent="yellow"],[data-app="dark"] [data-accent="yellow"]{ --acc-text:#ffd84d; }
[data-app="dark"][data-accent="orange"],[data-app="dark"] [data-accent="orange"]{ --acc-text:#ff8a4c; }
[data-app="dark"][data-accent="gold"],  [data-app="dark"] [data-accent="gold"]  { --acc-text:#e8c14a; }
[data-app="dark"][data-accent="mono"],  [data-app="dark"] [data-accent="mono"]  { --acc-text:#ffffff; }

/* every place the accent was being used for words */
[data-app] .hub-dot,
[data-app] .hub-card-step,
[data-app] .hub-eyebrow,
[data-app] .vid-eyebrow,
[data-app] .page-eyebrow,
[data-app] .xp-kind,
[data-app] .as-side-row.is-on .as-side-ic,
[data-app] .tpl-chip,
[data-app] .acc-offer svg{
  color:var(--acc-text,var(--vz-acc));
}
/* Filled pills are the exception to the rule above. Accent-as-text is
   right for an icon or a label sitting on the page, but Explore and the
   badges sit on an accent fill — giving them accent text too put yellow
   on yellow and measured 2.49:1 in dark mode. They take the dark ink the
   fill was designed for. */
[data-app] .anav-explore,
[data-app] .anav-badge{
  background:var(--vz-acc);
  color:var(--vz-acc-ink);
}
/* the underline is a shape, not text — it can stay bright */
[data-app] .anav-link.is-on::after{background:var(--vz-acc);}
[data-app] .anav-link.is-on{color:var(--a-ink);}

/* Explore stays a filled accent pill even when it is the active link, so
   the generic active colour above would put near-white on yellow (1.28:1).
   It keeps the dark ink the fill was designed for. The droplet overlay
   reveals accent-coloured letters, which cannot show on an accent fill —
   Explore already signals "active" by being filled, so it skips it. */
[data-app] .anav-link.anav-explore.is-on{color:var(--vz-acc-ink);}
.anav-link.anav-explore.is-on .anav-t::after{display:none;}

/* ═══ LEGIBILITY ON ACCENT FILLS ═══
   Dark ink on a bright fill is readable, but flat. A hair of light
   above the letters and a hair of shadow below gives them an edge so
   they hold their shape against the colour. */
[data-app] .anav-upgrade,
[data-app] .acc-get,
[data-app] .set-promo,
[data-app] .lb-primary{
  text-shadow:0 1px 0 rgba(255,255,255,.28);
}
[data-app] .anav-upgrade{
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.4),
    inset 0 -1px 0 rgba(0,0,0,.16),
    0 1px 2px rgba(0,0,0,.22),
    0 6px 16px -8px color-mix(in srgb,var(--vz-acc) 70%,transparent);
}
[data-app] .acc-get{
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.36),
    inset 0 -1px 0 rgba(0,0,0,.14);
}
/* mono has no colour to carry a warm shadow */
[data-accent="mono"] .anav-upgrade,
[data-accent="mono"] .acc-get,
[data-accent="mono"] .set-promo{text-shadow:none;}

/* ═══ REMAINING LOW-CONTRAST TEXT ═══
   Found by measuring, not by eye. */
[data-app="light"] .nav-logo-sub{color:#5f5a54;}   /* was 4.43:1 */
[data-app] .anav-logo .nav-logo-sub{color:var(--a-mute);}
[data-app="dark"] .nav-logo-sub{color:#9a938b;}

/* Muted text in dark mode measured 3.4–3.7:1 against the panels, under
   the 4.5 minimum. Lifted until it passes; the tone is unchanged, only
   the value. */
[data-app="dark"]{ --a-mute:#9b948c; }
[data-app="dark"] .vid-note,
[data-app="dark"] .vid-opt em,
[data-app="dark"] .vid-side-h,
[data-app="dark"] .gc-note,
[data-app="dark"] .lb-rows dt,
[data-app="dark"] .as-side-h,
[data-app="dark"] .cmp-mrow-note,
[data-app="dark"] .cmp-mrow-by{color:#9b948c;}
[data-app="dark"] .vid-opt.is-on em{color:#5d5852;}

/* ═══ TOKEN BRIDGE ═══
   The surface variables (--vz-text, --vz-muted, --vz-panel, --vz-line…)
   were only ever defined inside [data-theme="paper"], which no longer
   exists on any page. Every one of the ~100 references was therefore
   silently falling back to a light-mode grey — which is why text went
   invisible in dark mode. Mapping them onto the live --a-* tokens fixes
   all of them at once instead of rewriting each reference.

   The accent variables (--vz-acc*) are deliberately NOT bridged: those
   are set by data-accent and are already correct in both modes. */
[data-app]{
  --vz-bg:var(--a-bg);
  --vz-panel:var(--a-panel);
  --vz-surface:var(--a-panel);
  --vz-cell:var(--a-sunk);
  --vz-line:var(--a-line);
  --vz-text:var(--a-ink);
  --vz-muted:var(--a-mute);
  --vz-chip:var(--a-chip);
  --vz-nav:var(--a-nav);
  --vz-nav-text:var(--a-nav-ink);
}

/* ═══ THE SECOND BRIDGE: the marketing site's palette ═══
   Most of app.css predates the theme switch and was written against the
   site tokens — --ink-strong, --ink-mute, --line, --wash, --white — which
   :root pins to light-mode values. They never followed data-app either,
   so in dark mode .hub-card-go painted #0c0c0c on a #151312 panel: a
   contrast ratio of 1.06, i.e. invisible. That is ~330 declarations, so
   they get remapped rather than rewritten.

   --white and --ink-strong move as a PAIR. The many "dark fill, white
   ink" controls (.app-chip.is-active, .tpl-cat.is-on, .app-avatar…) are
   written as background:var(--ink-strong);color:var(--white), so when
   both invert the control inverts with them and stays legible.

   Only app pages carry data-app — appearance.js is not loaded on the
   marketing site — so index/models/pricing are untouched by this. */
[data-app]{
  --accent-text:var(--acc-text,var(--a-ink));
  --ink-strong:var(--a-ink);
  --ink:var(--a-ink);
  --ink-mute:var(--a-mute);
  --line:var(--a-line);
  --wash:var(--a-sunk);
  --ghost:var(--a-sunk);
  --white:var(--a-panel);
}
/* `--accent-soft` is the pill behind small labels, and its partner is
   always `--accent-text`. It comes from styles.css, which these pages
   load alongside this one, and it has to be a TINT of the accent on both
   surfaces or the label on it disappears.

   It used to be pale yellow, which happened to work on a light page, so
   only the dark side was overridden here. Once the accent went
   monochrome that pale yellow became solid black — and on the light
   theme the pill inherited it: black label on a black pill, measured at
   1.02:1 on Templates. Both sides are now derived rather than inherited,
   which is what should have been true from the start. */
[data-app="dark"]{
  --accent-soft:color-mix(in srgb,var(--vz-acc) 34%,var(--a-panel));
}
[data-app="light"]{
  --accent-soft:color-mix(in srgb,var(--vz-acc) 12%,var(--a-panel));
}
/* These few are white because of what sits BEHIND them — a photo dimmed
   by a scrim, or a coloured status badge — not because the theme is
   light. They opt out of the pair above. */
[data-app] .app-upload-remove,
[data-app] .app-lib-x,
[data-app] .app-lib-plus,
[data-app] .app-pose-soon,
[data-app] .app-tip-badge{color:#fff;}
[data-app] .ba-pill,
[data-app] .tpl-card-use{color:#15130f;}

/* Final margin: muted grey measured 4.34:1 on white, just under the
   4.5 minimum. Darkened a step — same tone, passes now. */
[data-app="light"]{ --a-mute:#635e58; }
/* The card overlays sit on photographs, so their real contrast depends
   on the image underneath. Deepened so they hold on a pale one too. */
[data-app] .as-tag,
[data-app] .as-act,
[data-app] .as-vbadge,
[data-app] .as-fav{background:rgba(8,7,6,.66);}

/* ═══ TWO LAST CONTRAST FIXES ═══
   Both found by measuring, not by looking.

   The selected category chip was a dark fill with white text. When the
   theme bridge gave every .tpl-cat a light panel background at equal
   specificity, the later rule won and the chip turned white — but its
   label kept the white ink meant for the dark fill. White on white, 1:1.
   It now uses the button pair, so it inverts with the theme. */
[data-app] .tpl-cat.is-on{
  background:var(--a-btn);color:var(--a-btn-ink);
  box-shadow:0 12px 26px -14px rgba(0,0,0,.45);
}
[data-app] .tpl-cat.is-on .tpl-cat-label{color:var(--a-btn-ink);}
[data-app] .tpl-cat.is-on .tpl-cat-n{color:var(--a-btn-ink);opacity:.72;}

/* A 9px uppercase tag needs the full 4.5:1; the muted tone gave it 4.13
   against the chip it sits on. At that size, quiet is not worth unreadable. */
[data-app] .ed-tool-tag{color:var(--a-ink);}

/* ═══════════════════════════════════════════════════════════════════
   CRAFT LAYER
   Everything below is about how the app feels rather than what it does.
   Three ideas, applied consistently:

   1. Depth comes from stacked shadows, not one big blur. A real object
      casts a tight contact shadow AND a wide ambient one; a single
      40px blur reads as a sticker.
   2. Motion is short, eased out, and only ever on transform/opacity, so
      it stays on the compositor and never causes layout.
   3. Nothing moves for a visitor who asked for reduced motion.
   ═══════════════════════════════════════════════════════════════════ */

:root{
  /* out-quint: leaves fast, lands soft — the curve that reads "settled"
     rather than "stopped" */
  --e-out:cubic-bezier(.22,1,.36,1);
  --e-soft:cubic-bezier(.4,0,.2,1);

  --lift-1:0 1px 2px rgba(12,10,9,.06), 0 4px 10px -4px rgba(12,10,9,.08);
  --lift-2:0 1px 2px rgba(12,10,9,.07), 0 8px 20px -8px rgba(12,10,9,.13);
  --lift-3:0 2px 4px rgba(12,10,9,.08), 0 18px 40px -16px rgba(12,10,9,.22);
}
[data-app="dark"]{
  --lift-1:0 1px 2px rgba(0,0,0,.5), 0 4px 12px -4px rgba(0,0,0,.55);
  --lift-2:0 1px 3px rgba(0,0,0,.55), 0 10px 26px -10px rgba(0,0,0,.7);
  --lift-3:0 2px 6px rgba(0,0,0,.6), 0 22px 48px -18px rgba(0,0,0,.85);
}

/* ── entrance ───────────────────────────────
   Held 14px low and slightly flattened, then released. The blur is
   deliberately absent: blurring text during a transition costs a repaint
   per frame and looks cheap on a low-end machine. */
.mo .mo-item{
  opacity:0;
  /* held to the left of its resting place and slightly small, then
     released — the stagger sorts by position, so each row fills from its
     left edge across */
  transform:translate3d(-22px,0,0) scale(.978);
  transition:opacity .52s var(--e-out), transform .58s var(--e-out);
  will-change:opacity,transform;
}
.mo .mo-item.is-in{
  opacity:1;
  transform:translate3d(0,0,0) scale(1);
  will-change:auto;
}

/* ── the same entrance, the other way round ──
   Generate wears this one: identical timing, the sweep running from the
   right edge of each row instead of the left. */
.mo.mo-rtl .mo-item{transform:translate3d(22px,0,0) scale(.978);}
/* The line above sits after .mo .mo-item.is-in and carries the same
   specificity, so it was winning on source order and re-applying the
   START of the animation to items that had already arrived. Everything
   on a mo-rtl page settled 22px to the right and 2.2% small and stayed
   there — which on the Generate wall pushed the second column 20px off
   the screen. The resting state needs to be stated for this direction
   too, and stated after it. */
.mo.mo-rtl .mo-item.is-in{transform:translate3d(0,0,0) scale(1);}

/* ── the top bar's own menu, applied to a page ──
   Editorial wears this one. The values are lifted from .anav-menu rather
   than approximated — a 6px fall, a 0.18s fade, both on the same curve,
   and every block moving together the way the panel does. */
.mo.mo-drop .mo-item{
  transform:translate3d(0,-14px,0);
  transition:opacity .5s var(--e-out), transform .56s var(--e-out);
}
.mo.mo-drop .mo-item.is-in{transform:none;}

/* images settle over their placeholder tone */
.mo-img{opacity:0;transition:opacity .5s var(--e-soft);}
.mo-img.is-loaded,img.is-loaded{opacity:1;}

@media (prefers-reduced-motion: reduce){
  .mo .mo-item,.mo .mo-item.is-in{opacity:1;transform:none;transition:none;}
  .mo-img{opacity:1;transition:none;}
  *,*::before,*::after{animation-duration:.001ms!important;transition-duration:.001ms!important;}
  /* Collapsing the duration is the right move for a one-shot animation and
     the wrong one for a looping animation: an infinite loop at .001ms keeps
     restarting forever. Anything that repeats is stopped outright, and the
     wave simply holds its shape. */
  *,*::before,*::after{animation-iteration-count:1!important;}
  /* the falling bead and the paint are pure decoration, so they go; the
     rule they leave behind is the actual state marker and stays */
  .anav-link.is-on::before,
  .anav-link.is-on .anav-t::after{display:none;}
  .anav-link.is-on::after{animation:none!important;transform:none;opacity:1;}
}

/* ── the generator cards ────────────────────
   The card lifts, its shadow deepens, the photograph inside pushes in
   very slightly, and the arrow steps forward. Four small moves timed
   together read as one gesture. */
[data-app] .hub-card,
[data-app] .xp-card,
[data-app] .tpl-card,
[data-app] .as-card{
  box-shadow:inset 0 0 0 1px var(--a-line), var(--lift-1);
  transition:transform .42s var(--e-out), box-shadow .42s var(--e-out);
}
[data-app] .hub-card:hover,
[data-app] .xp-card:hover,
[data-app] .tpl-card:hover,
[data-app] .as-card:hover{
  transform:translate3d(0,-3px,0);
  box-shadow:inset 0 0 0 1px var(--a-line), var(--lift-3);
}
[data-app] .hub-card:active{transform:translate3d(0,-1px,0);transition-duration:.09s;}

.hub-card-visual img,
.xp-card img,
.tpl-card-img img{transition:transform .7s var(--e-out);}
.hub-card:hover .hub-card-visual img,
.xp-card:hover img,
.tpl-card:hover .tpl-card-img img{transform:scale(1.035);}

.hub-card-go svg{transition:transform .42s var(--e-out);}
.hub-card:hover .hub-card-go svg{transform:translateX(5px);}

/* the card a visitor cannot use yet should not pretend to respond */
[data-app] .hub-card.is-soon:hover{transform:none;box-shadow:inset 0 0 0 1px var(--a-line), var(--lift-1);}
.hub-card.is-soon:hover .hub-card-visual img{transform:none;}

/* ── buttons ────────────────────────────────
   Press is the part most interfaces skip, and it is the part that makes
   a control feel physical: down on pointerdown, back on release. */
.anav-upgrade:active,.anav-assets:active,
.hub-card-go:active,.gc-go:active,.cmp-go:active,
.ed-mini-go:active,.vid-go:active,.lb-primary:active{
  transform:translate3d(0,1px,0);
  transition-duration:.08s;
}

/* ── focus ──────────────────────────────────
   One visible ring everywhere, on the accent, only for keyboard users. */
[data-app] :focus-visible{
  outline:2px solid var(--vz-acc);
  outline-offset:2px;
  border-radius:6px;
}
[data-app] .anav-link:focus-visible,
[data-app] .hub-card:focus-visible{outline-offset:3px;}

/* ── surfaces ───────────────────────────────
   Panels get the same two-layer depth so nothing looks pasted on. */
[data-app] .ed-panel,
[data-app] .vid-side,
[data-app] .ut-side,
[data-app] .set-card,
[data-app] .acc,
[data-app] .as-menu,
[data-app] .cmp-pop{
  box-shadow:inset 0 0 0 1px var(--a-line), var(--lift-2);
}
[data-app] .cmp-box,
[data-app] .gc{
  box-shadow:inset 0 0 0 1px var(--a-line), var(--lift-3);
}

/* ── details ────────────────────────────────
   The small things that are only noticed when they are missing. */
[data-app] ::selection{background:var(--vz-acc);color:var(--vz-acc-ink);}

[data-app] .anav-credits b,
[data-app] .hub-card-step,
[data-app] .as-day-h span{font-variant-numeric:tabular-nums;}

/* a scrollbar that belongs to the theme instead of the operating system */
[data-app]{scrollbar-color:var(--a-line) transparent;scrollbar-width:thin;}
[data-app] ::-webkit-scrollbar{width:11px;height:11px;}
[data-app] ::-webkit-scrollbar-track{background:transparent;}
[data-app] ::-webkit-scrollbar-thumb{
  background:var(--a-line);
  border-radius:100px;
  border:3px solid transparent;
  background-clip:content-box;
}
[data-app] ::-webkit-scrollbar-thumb:hover{background:var(--a-mute);background-clip:content-box;}

/* ── the page head ──────────────────────────
   Larger, tighter, and optically corrected: at display sizes the default
   tracking is too loose, and the eyebrow needs air beneath it. */
.hub-title{
  font-size:clamp(34px,4.4vw,52px);
  line-height:1.04;
  letter-spacing:-.035em;
  font-weight:600;
}
.hub-sub{font-size:17px;line-height:1.55;max-width:52ch;}
.hub-head{margin-bottom:48px;}
.hub-main{padding:56px 0 100px;}

/* The full stop is the one mark in the headline that carries the accent.
   It is tinted, not filled: the accent is white, so a filled bar reads
   as a slab of nothing sitting in the middle of the sentence. */
[data-app] .hub-dot{
  color:var(--vz-acc);
  background:none;
  padding:0;
}

/* ═══════════════════════════════════════════════════════════════════
   VIDEO GENERATOR
   The reference this was modelled on is a dark tool with a magenta
   action colour. This is the same information architecture in the Vitonize
   palette: theme surfaces, yellow reserved for the one action, and the
   capability chips carrying the detail instead of colour.
   ═══════════════════════════════════════════════════════════════════ */
.vg-shell{position:relative;display:flex;gap:18px;align-items:flex-start;padding-bottom:60px;}

/* An author display: rule outranks the user-agent [hidden] rule, so every
   element here that gets toggled with .hidden needs to say so explicitly.
   Without this the model and output panels render side by side and both
   input modes show at once. */
.vg-panel[hidden],
.vg-block[hidden],
.vg-frame-full[hidden],
.vg-frame-empty[hidden],
.vg-note[hidden],
.vg-empty[hidden]{display:none !important;}

.vg{
  flex:0 0 430px;max-width:430px;width:100%;
  display:flex;flex-direction:column;gap:12px;
  padding:18px;border-radius:20px;
  background:var(--a-panel);
  box-shadow:inset 0 0 0 1px var(--a-line),var(--lift-2);
}
.vg-head{display:flex;align-items:center;gap:10px;}
.vg-title{font-size:16px;font-weight:600;letter-spacing:-.01em;color:var(--a-ink);margin:0;flex:1;}

/* ── mode tabs ─────────────────────────────── */
.vg-modes{display:grid;grid-template-columns:1fr 1fr;gap:8px;}
.vg-mode{
  display:flex;flex-direction:column;align-items:center;gap:7px;
  padding:13px 8px;border-radius:13px;cursor:pointer;
  background:var(--a-sunk);box-shadow:inset 0 0 0 1px var(--a-line);
  font-size:12.5px;font-weight:600;letter-spacing:-.01em;color:var(--a-mute);
  transition:color .2s var(--e-out),box-shadow .2s var(--e-out),background-color .2s var(--e-out);
}
.vg-mode-ic{width:24px;height:24px;display:block;}
.vg-mode-ic svg{width:100%;height:100%;}
.vg-mode:hover{color:var(--a-ink);}
.vg-mode.is-on{
  color:var(--a-ink);
  background:color-mix(in srgb,var(--vz-acc) 16%,var(--a-panel));
  box-shadow:inset 0 0 0 1.5px var(--vz-acc);
}

/* ── rows ──────────────────────────────────── */
.vg-row{
  display:flex;align-items:center;gap:11px;width:100%;
  padding:11px 13px;border-radius:13px;cursor:pointer;text-align:left;
  background:var(--a-sunk);box-shadow:inset 0 0 0 1px var(--a-line);
  transition:box-shadow .2s var(--e-out);
}
.vg-row:hover{box-shadow:inset 0 0 0 1px var(--a-mute);}
.vg-row.is-flat{cursor:default;}
.vg-row.is-flat:hover{box-shadow:inset 0 0 0 1px var(--a-line);}
.vg-row.is-off{opacity:.45;}
.vg-row-ic{width:20px;height:20px;flex:0 0 auto;color:var(--a-mute);}
.vg-row-ic svg{width:100%;height:100%;}
.vg-row-mark{
  width:26px;height:26px;border-radius:8px;flex:0 0 auto;
  display:flex;align-items:center;justify-content:center;
  font-size:12px;font-weight:700;
}
.vg-row-txt{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px;}
.vg-row-txt em{font-style:normal;font-size:11px;color:var(--a-mute);}
.vg-row-txt b{font-size:13.5px;font-weight:600;color:var(--a-ink);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.vg-chev{width:15px;height:15px;flex:0 0 auto;color:var(--a-mute);}
.vg-duo{display:grid;grid-template-columns:1fr 1fr;gap:8px;}

/* ── blocks ────────────────────────────────── */
.vg-block{display:flex;flex-direction:column;gap:9px;}
.vg-block.is-off{opacity:.45;pointer-events:none;}
.vg-h{font-size:13px;font-weight:600;letter-spacing:-.01em;color:var(--a-ink);margin:0;}
.vg-h-row{display:flex;align-items:center;justify-content:space-between;gap:10px;}
.vg-note{font-size:11.5px;line-height:1.5;color:var(--a-mute);margin:0;}

/* ── motion transfer ───────────────────────────
   Source on the left, character on the right, an arrow between them. The
   arrow is a grid column of its own rather than an overlay, so nothing
   sits on top of either drop target and neither cell can be pushed to a
   second row — the same mistake the frame swap button made. */
.vg-mc{
  display:grid;
  grid-template-columns:1fr 34px 1fr;
  align-items:center;gap:6px;
}
.vg-mc-cell{
  position:relative;display:block;cursor:pointer;
  min-height:158px;border-radius:14px;overflow:hidden;
  background:var(--a-sunk);box-shadow:inset 0 0 0 1px var(--a-line);
  transition:box-shadow .2s var(--e-out),transform .2s var(--e-out);
}
.vg-mc-cell:hover{box-shadow:inset 0 0 0 1.5px var(--vz-acc);}
.vg-mc-cell.is-filled{box-shadow:inset 0 0 0 1.5px var(--a-line-2,var(--a-line));}

.vg-mc-empty{
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:3px;height:100%;padding:16px 12px 30px;text-align:center;
}
.vg-mc-ic{
  display:grid;place-items:center;
  width:44px;height:44px;margin-bottom:5px;border-radius:12px;
  background:var(--a-chip);color:var(--a-mute);
  transition:color .2s var(--e-out),background-color .2s var(--e-out);
}
.vg-mc-ic.is-round{border-radius:50%;}
.vg-mc-ic svg{width:22px;height:22px;}
.vg-mc-cell:hover .vg-mc-ic{background:var(--a-chip-2);color:var(--a-ink);}
.vg-mc-empty b{font-size:12.5px;font-weight:650;color:var(--a-ink);}
.vg-mc-empty em{font-style:normal;font-size:11px;line-height:1.4;color:var(--a-mute);max-width:19ch;}

/* the filled state covers the cell; the caption stays legible over it */
.vg-mc-full{position:absolute;inset:0;display:block;}
.vg-mc-full img,.vg-mc-full video{width:100%;height:100%;object-fit:cover;display:block;}

/* pinned to the bottom edge so it reads as a spec, not as body copy */
.vg-mc-meta{
  position:absolute;left:0;right:0;bottom:0;
  padding:7px 10px;
  font-size:10.5px;letter-spacing:.02em;text-align:center;
  color:var(--a-mute);background:var(--a-sunk);
  border-top:1px solid var(--a-line);
}
.vg-mc-cell.is-filled .vg-mc-meta{
  color:var(--a-ink);background:var(--a-panel);
}

.vg-mc-arrow{display:grid;place-items:center;color:var(--a-mute);}
.vg-mc-arrow svg{width:30px;height:14px;}

/* narrow: stack, and turn the arrow a quarter turn so it still points
   from the source to the target rather than off the side of the screen */
@media (max-width:520px){
  .vg-mc{grid-template-columns:1fr;grid-template-rows:auto 22px auto;}
  .vg-mc-arrow{transform:rotate(90deg);}
}

/* ── switch ────────────────────────────────────
   Used by scene control. The knob carries the state; the row's own label
   also changes wording, so the meaning does not rest on colour alone. */
.vg-toggle{
  flex:0 0 auto;width:40px;height:23px;padding:0;
  border-radius:999px;cursor:pointer;
  background:var(--a-chip-2);
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:background-color .22s var(--e-out);
}
.vg-toggle i{
  display:block;width:17px;height:17px;margin:3px;border-radius:50%;
  background:var(--a-panel);box-shadow:var(--lift-1);
  transition:transform .22s var(--e-out);
}
.vg-toggle[aria-checked="true"]{background:var(--vz-acc);}
.vg-toggle[aria-checked="true"] i{transform:translateX(17px);}

/* a second-level heading inside a block that already has one */
.vg-h-sub{margin-top:2px;}

/* ── start / end frames ────────────────────── */
.vg-frames{position:relative;display:grid;grid-template-columns:1fr 1fr;gap:8px;}
.vg-frame{
  position:relative;display:block;cursor:pointer;
  min-height:132px;border-radius:14px;overflow:hidden;
  background:var(--a-sunk);box-shadow:inset 0 0 0 1px var(--a-line);
  transition:box-shadow .2s var(--e-out);
}
.vg-frame:hover{box-shadow:inset 0 0 0 1.5px var(--vz-acc);}
.vg-frame.is-off{opacity:.4;pointer-events:none;}
.vg-frame-empty{
  position:absolute;inset:0;display:flex;flex-direction:column;
  align-items:center;justify-content:center;gap:6px;padding:12px;text-align:center;
}
.vg-frame-ic{position:relative;width:26px;height:26px;color:var(--a-mute);}
.vg-frame-ic svg{width:100%;height:100%;}
.vg-frame-ic i{
  position:absolute;right:-6px;bottom:-4px;
  font-style:normal;font-size:13px;font-weight:700;line-height:1;color:var(--a-ink);
}
.vg-frame-empty b{font-size:12.5px;font-weight:600;color:var(--a-ink);}
.vg-frame-hist{
  font-size:11.5px;color:var(--a-mute);text-decoration:underline;
  text-underline-offset:2px;cursor:pointer;
}
.vg-frame-hist:hover{color:var(--a-ink);}
.vg-frame-full{position:absolute;inset:0;}
.vg-frame-full img{width:100%;height:100%;object-fit:cover;display:block;}
.vg-frame-x{
  position:absolute;top:6px;right:6px;width:22px;height:22px;border-radius:50%;
  background:rgba(12,12,12,.7);color:#fff;font-size:11px;line-height:1;cursor:pointer;
  display:flex;align-items:center;justify-content:center;
}


/* ── reference tray ────────────────────────── */
.vg-refs{
  display:flex;align-items:center;gap:11px;cursor:pointer;
  padding:11px 13px;border-radius:14px;
  background:var(--a-sunk);box-shadow:inset 0 0 0 1.5px var(--vz-acc);
  transition:box-shadow .2s var(--e-out);
}
.vg-refs.is-off{opacity:.4;pointer-events:none;box-shadow:inset 0 0 0 1px var(--a-line);}
.vg-refs-strip{display:flex;flex:0 0 auto;}
.vg-refs-strip i{
  width:26px;height:32px;border-radius:5px;display:block;
  background:var(--a-chip-2) center/cover no-repeat;
  box-shadow:0 0 0 2px var(--a-sunk);
}
.vg-refs-strip i + i{margin-left:-9px;}
.vg-refs-txt{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px;}
.vg-refs-txt b{font-size:13px;font-weight:600;color:var(--a-ink);}
.vg-refs-txt b i{
  font-style:normal;font-size:10px;font-weight:600;
  padding:2px 6px;border-radius:5px;margin-left:6px;
  background:var(--a-chip-2);color:var(--a-ink);
}
.vg-refs-txt span{font-size:11px;color:var(--a-mute);}
.vg-refs-n{flex:0 0 auto;font-size:11.5px;color:var(--a-mute);}
.vg-refs-n b{color:var(--a-ink);font-weight:600;}

/* ── prompt ────────────────────────────────── */
.vg-prompt{
  border-radius:14px;overflow:hidden;
  background:var(--a-sunk);box-shadow:inset 0 0 0 1px var(--a-line);
  transition:box-shadow .2s var(--e-out);
}
.vg-prompt:focus-within{box-shadow:inset 0 0 0 1px var(--a-mute);}
.vg-prompt textarea{
  display:block;width:100%;border:0;background:transparent;resize:none;
  padding:13px 14px 4px;font-family:inherit;font-size:13.5px;line-height:1.55;
  color:var(--a-ink);min-height:86px;
}
.vg-prompt.is-tall textarea{min-height:240px;}
.vg-prompt textarea::placeholder{color:var(--a-mute);}
.vg-prompt textarea:focus{outline:none;}
.vg-prompt-bar{display:flex;align-items:center;gap:8px;padding:6px 10px 9px;}
.vg-camera{
  display:inline-flex;align-items:center;gap:6px;cursor:pointer;
  padding:5px 10px;border-radius:8px;
  font-size:12px;font-weight:600;color:var(--a-ink);
  background:var(--a-chip);
}
.vg-camera svg{width:14px;height:14px;}
.vg-camera:hover{background:var(--a-chip-2);}
.vg-prompt-tools{display:flex;align-items:center;gap:2px;margin-right:auto;}
.vg-icon{
  width:28px;height:28px;border-radius:8px;cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  color:var(--a-mute);transition:color .2s var(--e-out),background-color .2s var(--e-out);
}
.vg-icon svg{width:15px;height:15px;}
.vg-icon:hover{color:var(--a-ink);background:var(--a-chip);}

/* ── switch ────────────────────────────────── */
.vg-switch{
  display:inline-flex;align-items:center;gap:8px;cursor:pointer;
  font-size:12px;font-weight:600;color:var(--a-mute);
}
.vg-switch input{position:absolute;opacity:0;width:0;height:0;}
.vg-switch-track{
  position:relative;width:34px;height:19px;border-radius:100px;flex:0 0 auto;
  background:var(--a-chip-2);transition:background-color .22s var(--e-out);
}
.vg-switch-track::after{
  content:"";position:absolute;top:2.5px;left:2.5px;width:14px;height:14px;
  border-radius:50%;background:var(--a-panel);
  box-shadow:0 1px 2px rgba(0,0,0,.3);
  transition:transform .22s var(--e-out);
}
.vg-switch input:checked + .vg-switch-track{background:var(--vz-acc);}
.vg-switch input:checked + .vg-switch-track::after{transform:translateX(15px);}
.vg-switch input:disabled + .vg-switch-track{opacity:.4;}
.vg-switch input:focus-visible + .vg-switch-track{outline:2px solid var(--vz-acc);outline-offset:2px;}

/* ── submit ────────────────────────────────── */
.vg-foot{display:flex;align-items:center;gap:10px;padding-top:2px;}
.vg-qty{
  display:flex;align-items:center;gap:2px;flex:0 0 auto;
  padding:4px;border-radius:11px;
  background:var(--a-sunk);box-shadow:inset 0 0 0 1px var(--a-line);
}
.vg-qty button{
  width:28px;height:28px;border-radius:8px;cursor:pointer;
  font-size:15px;line-height:1;color:var(--a-ink);
}
.vg-qty button:hover{background:var(--a-chip-2);}
.vg-qty span{font-size:12.5px;color:var(--a-mute);padding:0 6px;font-variant-numeric:tabular-nums;}
.vg-qty b{color:var(--a-ink);font-weight:700;}
.vg-legal{font-size:11px;line-height:1.5;color:var(--a-mute);margin:0;text-align:center;}

/* ── panels ────────────────────────────────── */
.vg-panel{
  flex:1 1 auto;min-width:0;align-self:stretch;
  display:flex;flex-direction:column;
  max-height:calc(100vh - 120px);
  border-radius:20px;overflow:hidden;
  background:var(--a-panel);
  box-shadow:inset 0 0 0 1px var(--a-line),var(--lift-2);
}
.vg-panel.is-narrow{flex:0 0 470px;max-width:470px;}
.vg-panel-head{
  display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:16px 18px;border-bottom:1px solid var(--a-line);flex:0 0 auto;
}
.vg-panel-head h2{font-size:16px;font-weight:600;letter-spacing:-.01em;color:var(--a-ink);margin:0;}
/* min-height:0 or the body will not scroll inside the flex column */
.vg-panel-body{flex:1 1 auto;min-height:0;overflow-y:auto;padding:16px 18px 22px;}
.vg-panel-h{
  font-size:10px;font-weight:700;letter-spacing:.11em;text-transform:uppercase;
  color:var(--a-mute);margin:0 0 8px;
}
.vg-panel-h + *{margin-bottom:14px;}

/* recommended */
.vg-feat{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(200px,100%),1fr));gap:10px;}
.vg-feat-card{
  display:flex;flex-direction:column;gap:4px;cursor:pointer;text-align:left;
  padding:16px 14px;border-radius:14px;min-height:104px;justify-content:flex-end;
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:transform .3s var(--e-out),box-shadow .3s var(--e-out);
}
.vg-feat-card:hover{transform:translateY(-2px);box-shadow:inset 0 0 0 1px var(--a-line),var(--lift-2);}
.vg-feat-card.is-on{box-shadow:inset 0 0 0 2px var(--vz-acc);}
.vg-feat-name{font-size:15px;font-weight:700;letter-spacing:-.02em;color:#fff;}
.vg-feat-desc{font-size:11.5px;line-height:1.4;color:rgba(255,255,255,.82);}

/* filters */
.vg-filters{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:12px;}
.vg-chip{
  padding:7px 14px;border-radius:100px;cursor:pointer;
  font-size:12.5px;font-weight:600;color:var(--a-ink);
  background:var(--a-chip);
}
.vg-chip.is-on{background:var(--a-btn);color:var(--a-btn-ink);}
.vg-select{
  padding:7px 10px;border-radius:9px;cursor:pointer;
  font-family:inherit;font-size:12.5px;color:var(--a-ink);
  background:var(--a-sunk);border:1px solid var(--a-line);
}
.vg-search{
  flex:1 1 200px;min-width:0;
  display:flex;align-items:center;gap:8px;
  padding:7px 11px;border-radius:10px;
  background:var(--a-sunk);box-shadow:inset 0 0 0 1px var(--a-line);
  color:var(--a-mute);
}
.vg-search svg{width:15px;height:15px;flex:0 0 auto;}
.vg-search input{
  flex:1;border:0;background:transparent;font-family:inherit;font-size:13px;color:var(--a-ink);
}
.vg-search input:focus{outline:none;}

/* the list */

.vg-item{
  display:flex;align-items:center;gap:12px;width:100%;text-align:left;cursor:pointer;
  padding:11px 12px;border-radius:12px;
  transition:background-color .16s var(--e-out);
}
.vg-item:hover{background:var(--a-chip);}
.vg-item.is-on{background:var(--a-chip-2);box-shadow:inset 0 0 0 1px var(--a-line);}
.vg-mark,.vg-row-mark{color:#fff;}
.vg-mark{
  width:30px;height:30px;border-radius:9px;flex:0 0 auto;
  display:flex;align-items:center;justify-content:center;
  font-size:13px;font-weight:700;
}
.vg-item-txt{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:2px;}
.vg-item-name{
  display:flex;align-items:center;gap:7px;
  font-size:13.5px;font-weight:600;letter-spacing:-.01em;color:var(--a-ink);
}
.vg-item-desc{font-size:11.5px;line-height:1.4;color:var(--a-mute);}
.vg-tag{
  font-style:normal;font-size:8.5px;font-weight:700;letter-spacing:.06em;
  text-transform:uppercase;padding:2.5px 5px;border-radius:5px;line-height:1;
  background:var(--vz-acc);color:var(--vz-acc-ink);
}
.vg-tag.is-fast{background:var(--a-chip-2);color:var(--a-ink);}
.vg-caps{display:flex;flex-wrap:wrap;gap:4px;justify-content:flex-end;flex:0 0 auto;max-width:52%;}
.vg-cap{
  font-size:10.5px;font-weight:600;white-space:nowrap;
  padding:3px 7px;border-radius:6px;
  background:var(--a-chip);color:var(--a-ink);
}
.vg-cap.is-plain{background:transparent;color:var(--a-mute);}
.vg-item.is-on .vg-item-desc,
.vg-item.is-on .vg-cap.is-plain{color:var(--a-ink);}
.vg-empty{font-size:13px;color:var(--a-mute);padding:22px 0;text-align:center;margin:0;}

/* provider marks are flat tones, not the vendors' logos */
/* ── provider marks ──
   These were twelve brand colours — blue, crimson, green, teal, violet.
   In monochrome they become a ladder of greys instead. Nothing is lost,
   because the colour was never what identified the provider: the badge
   carries its letter, and that is what people actually read. Every step
   stays dark enough to hold white letters at 4.5:1. */
[data-tone="a"]{background:#141414;}
[data-tone="b"]{background:#3d3d3d;}
[data-tone="c"]{background:#565656;}
[data-tone="d"]{background:#111111;}
[data-tone="e"]{background:#6b6b6b;}
[data-tone="f"]{background:#282828;}
[data-tone="g"]{background:#4a4a4a;}
[data-tone="h"]{background:#5f5f5f;}
[data-tone="i"]{background:#333333;}
[data-tone="j"]{background:#464646;}
[data-tone="k"]{background:#1f1f1f;}
[data-tone="l"]{background:#727272;}
.vg-feat-card[data-tone]{background-image:linear-gradient(150deg,rgba(0,0,0,.05),rgba(0,0,0,.55));}

/* ── output ────────────────────────────────── */
.vg-ratios{display:grid;grid-template-columns:repeat(7,1fr);gap:6px;}
.vg-ratio{
  display:flex;flex-direction:column;align-items:center;gap:7px;cursor:pointer;
  padding:11px 4px;border-radius:11px;
  background:var(--a-sunk);box-shadow:inset 0 0 0 1px var(--a-line);
  font-size:11px;font-weight:600;color:var(--a-mute);
  transition:color .18s var(--e-out),box-shadow .18s var(--e-out);
}
.vg-ratio-box{display:flex;align-items:center;justify-content:center;width:24px;height:24px;}
.vg-ratio-box i{display:block;border-radius:3px;box-shadow:inset 0 0 0 1.5px currentColor;}
.vg-ratio:hover{color:var(--a-ink);}
.vg-ratio.is-on{
  color:var(--a-ink);
  background:color-mix(in srgb,var(--vz-acc) 16%,var(--a-panel));
  box-shadow:inset 0 0 0 1.5px var(--vz-acc);
}
.vg-seg{
  display:grid;grid-template-columns:repeat(4,1fr);gap:3px;
  padding:3px;border-radius:11px;background:var(--a-sunk);
  box-shadow:inset 0 0 0 1px var(--a-line);
}
.vg-seg-b{
  padding:9px 4px;border-radius:9px;cursor:pointer;
  font-size:12.5px;font-weight:600;color:var(--a-mute);
  transition:color .18s var(--e-out),background-color .18s var(--e-out);
}
.vg-seg-b:hover:not(:disabled){color:var(--a-ink);}
.vg-seg-b.is-on{background:var(--a-btn);color:var(--a-btn-ink);}
.vg-seg-b:disabled{opacity:.35;cursor:not-allowed;}
.vg-dur{display:flex;align-items:center;gap:14px;}
.vg-dur input[type=range]{flex:1;accent-color:var(--vz-acc);}
.vg-dur-val{
  flex:0 0 auto;min-width:46px;text-align:center;
  padding:8px 10px;border-radius:9px;
  background:var(--a-sunk);box-shadow:inset 0 0 0 1px var(--a-line);
  font-size:13px;font-weight:600;color:var(--a-ink);font-variant-numeric:tabular-nums;
}
.vg-dur-note{font-size:11.5px;color:var(--a-mute);margin:8px 0 0;}

@media (max-width:1080px){
  .vg-shell{flex-direction:column;}
  .vg,.vg-panel,.vg-panel.is-narrow{flex:1 1 auto;max-width:none;width:100%;}
  .vg-panel{max-height:none;}
  .vg-ratios{grid-template-columns:repeat(4,1fr);}
}

/* ── the stage ─────────────────────────────
   The right-hand default. It is the one place on the page that shows the
   shape of the thing being made, so it gets the room and the quiet. */
.vg-stage{
  flex:1 1 auto;min-width:0;align-self:stretch;
  display:flex;flex-direction:column;gap:14px;
  padding:18px;border-radius:20px;
  background:var(--a-panel);
  box-shadow:inset 0 0 0 1px var(--a-line),var(--lift-2);
}
.vg-stage[hidden]{display:none !important;}
.vg-stage-top{display:flex;align-items:center;gap:10px;}
.vg-stage-mark{
  width:24px;height:24px;border-radius:7px;flex:0 0 auto;color:#fff;
  display:flex;align-items:center;justify-content:center;
  font-size:11px;font-weight:700;
}
.vg-stage-name{font-size:13.5px;font-weight:600;color:var(--a-ink);}
.vg-stage-spec{
  margin-left:auto;font-size:12px;color:var(--a-mute);
  font-variant-numeric:tabular-nums;
}

/* the frame is centred in whatever room is left, at its true ratio */
.vg-stage-hold{
  flex:1 1 auto;height:clamp(280px,52vh,520px);
  display:flex;align-items:center;justify-content:center;
  padding:8px;border-radius:16px;
  background:var(--a-sunk);
}
.vg-stage-frame{
  position:relative;
  max-width:100%;max-height:100%;
  border-radius:12px;overflow:hidden;
  background:var(--a-panel);
  box-shadow:inset 0 0 0 1px var(--a-line),var(--lift-2);
}
.vg-stage-frame img{width:100%;height:100%;object-fit:cover;display:block;}
.vg-stage-frame img[hidden]{display:none !important;}
.vg-stage-empty{
  position:absolute;inset:0;
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:7px;
  padding:24px;text-align:center;
}
.vg-stage-empty[hidden]{display:none !important;}
.vg-stage-ic{width:42px;height:42px;color:var(--a-mute);opacity:.7;}
.vg-stage-ic svg{width:100%;height:100%;}
.vg-stage-empty b{font-size:14px;font-weight:600;color:var(--a-ink);}
.vg-stage-empty span{font-size:12.5px;line-height:1.5;color:var(--a-mute);max-width:34ch;}
.vg-stage-ratio{
  position:absolute;left:10px;bottom:10px;
  padding:4px 9px;border-radius:7px;
  background:var(--a-chip-2);color:var(--a-ink);
  font-size:11px;font-weight:600;font-variant-numeric:tabular-nums;
}
.vg-stage-foot{display:flex;flex-wrap:wrap;gap:6px;}
.vg-stage-chip{
  padding:5px 11px;border-radius:8px;
  background:var(--a-chip);color:var(--a-mute);
  font-size:11.5px;font-weight:600;
}

/* ── page ground ───────────────────────────
   One soft wash of the accent behind the top of the tool, so the panels
   sit on something rather than on flat paper. Kept far below the text so
   it can never affect legibility. */
.vid-main{position:relative;}
/* no wash: the ground stays the theme colour, and the accent is spent
   only on the action */
.vid-main > *{position:relative;z-index:1;}
.vid-hero{background:none;}
.vid-hero .container{padding-top:38px;padding-bottom:26px;}
.vid-sub{max-width:52ch;}

@media (max-width:1080px){
  .vg-stage{flex:1 1 auto;width:100%;}
  .vg-stage-hold{height:clamp(220px,46vh,420px);}
}

/* ═══ THE [hidden] RULE, ENFORCED ═══
   The user-agent stylesheet says [hidden]{display:none}, but that is a
   plain UA rule — ANY author `display:` on the same element outranks it,
   and the element stays on screen while the code believes it is gone.

   This has now caused three separate visible bugs: both video panels
   rendering at once, both input modes showing together, and a broken
   image's alt text sitting in the stage. A sweep for elements carrying
   [hidden] whose computed display was not none also turned it up on the
   upload grid of all seven wizard pages, where it predates this work.

   Settling it once for the whole app is cheaper and safer than finding
   the next one by eye. */
[hidden]{display:none !important;}

/* ═══ COMPOSER, MERGED ═══
   The reference's arrangement — tabs, a look card, an element grid, three
   quick pills, one big action — in the Vitonize palette. The differences that
   matter: no magenta, the accent used once, and every control tied to a
   real capability rather than decoration. */

/* ── tabs ──────────────────────────────────
   Labels with a rule that slides between them. The rule is measured from
   the active label rather than assuming equal widths, so it fits whatever
   the labels say and survives translation. */
.vg-tabs{
  position:relative;display:flex;gap:4px;
  padding-bottom:10px;margin-bottom:2px;
  border-bottom:1px solid var(--a-line);
}
.vg-tab{
  padding:6px 10px;border-radius:8px;cursor:pointer;
  font-size:13.5px;font-weight:600;letter-spacing:-.01em;
  color:var(--a-mute);
  transition:color .2s var(--e-out);
}
.vg-tab:hover{color:var(--a-ink);}
.vg-tab.is-on{color:var(--a-ink);}
.vg-tab-rule{
  position:absolute;left:0;bottom:-1px;height:2px;width:0;
  border-radius:2px;background:var(--vz-acc);
  transition:transform .42s var(--e-out),width .42s var(--e-out);
}

/* ── the look ──────────────────────────────
   One image at the top so the panel opens on something to look at rather
   than a wall of controls. */
.vg-look{
  position:relative;height:132px;border-radius:16px;overflow:hidden;
  box-shadow:inset 0 0 0 1px var(--a-line);
}
.vg-look img{
  position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  transition:transform .8s var(--e-out);
}
.vg-look:hover img{transform:scale(1.04);}
.vg-look::after{
  content:"";position:absolute;inset:0;
  background:linear-gradient(180deg,rgba(8,7,6,.1) 30%,rgba(8,7,6,.86));
}
.vg-look-body{
  position:absolute;left:14px;bottom:12px;z-index:2;
  display:flex;flex-direction:column;gap:1px;
}
.vg-look-body b{
  font-size:19px;font-weight:800;letter-spacing:.01em;text-transform:uppercase;
  color:var(--vz-acc);
  text-shadow:0 1px 10px rgba(0,0,0,.5);
}
.vg-look-body em{font-style:normal;font-size:12px;color:rgba(255,255,255,.88);}
.vg-look-change{
  position:absolute;top:11px;right:11px;z-index:2;
  display:inline-flex;align-items:center;gap:6px;cursor:pointer;
  padding:7px 12px;border-radius:9px;
  background:rgba(12,11,10,.62);
  -webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);
  color:#fff;font-size:12px;font-weight:600;
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.16);
  transition:background-color .2s var(--e-out);
}
.vg-look-change svg{width:13px;height:13px;}
.vg-look-change:hover{background:rgba(12,11,10,.82);}

/* look picker */
.vg-looks{display:grid;grid-template-columns:repeat(auto-fill,minmax(120px,1fr));gap:10px;}
.vg-lookcard{
  position:relative;height:96px;border-radius:13px;overflow:hidden;cursor:pointer;
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:transform .3s var(--e-out),box-shadow .3s var(--e-out);
}
.vg-lookcard img{width:100%;height:100%;object-fit:cover;display:block;}
.vg-lookcard span{
  position:absolute;left:0;right:0;bottom:0;padding:20px 10px 8px;
  background:linear-gradient(180deg,transparent,rgba(8,7,6,.85));
  color:#fff;font-size:12.5px;font-weight:700;text-align:left;
}
.vg-lookcard:hover{transform:translateY(-2px);box-shadow:inset 0 0 0 1px var(--a-line),var(--lift-2);}
.vg-lookcard.is-on{box-shadow:inset 0 0 0 2px var(--vz-acc);}

/* ── element tiles ─────────────────────────
   A grid that always ends in an empty tile, so adding is the same gesture
   whether the grid is empty or nearly full. */
.vg-tiles{display:grid;grid-template-columns:repeat(4,1fr);gap:8px;}
.vg-tile{
  position:relative;aspect-ratio:1;border-radius:11px;overflow:hidden;
  background:var(--a-sunk);box-shadow:inset 0 0 0 1px var(--a-line);
  display:block;
}
.vg-tile img{width:100%;height:100%;object-fit:cover;display:block;}
.vg-tile-x{
  position:absolute;top:3px;right:3px;width:18px;height:18px;border-radius:50%;
  background:rgba(12,12,12,.72);color:#fff;font-size:9px;line-height:1;cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  opacity:0;transition:opacity .2s var(--e-out);
}
.vg-tile:hover .vg-tile-x{opacity:1;}
.vg-tile.is-add{
  display:flex;align-items:center;justify-content:center;cursor:pointer;
  font-size:20px;line-height:1;color:var(--a-mute);
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:color .2s var(--e-out),box-shadow .2s var(--e-out);
}
.vg-tile.is-add:hover{color:var(--a-ink);box-shadow:inset 0 0 0 1.5px var(--vz-acc);}
.vg-h-n{font-size:11.5px;color:var(--a-mute);}
.vg-h-n b{color:var(--a-ink);font-weight:600;}

/* ── camera moves ──────────────────────────*/

/* ── prompt ────────────────────────────────*/
.vg-prompt-h{
  display:flex;align-items:center;justify-content:space-between;
  padding:11px 12px 0;
  font-size:12px;font-weight:600;color:var(--a-mute);
}
.vg-pill-s{
  display:inline-flex;align-items:center;gap:6px;cursor:pointer;
  padding:5px 10px;border-radius:8px;
  font-size:11.5px;font-weight:600;color:var(--a-mute);
  background:var(--a-chip);
  transition:color .2s var(--e-out),background-color .2s var(--e-out);
}
.vg-pill-s svg{width:13px;height:13px;}
.vg-pill-s:hover:not(:disabled){color:var(--a-ink);background:var(--a-chip-2);}
.vg-pill-s.is-on{color:var(--vz-acc-ink);background:var(--vz-acc);}
.vg-pill-s:disabled{opacity:.45;cursor:not-allowed;}

/* ── the three quick settings ──────────────*/
/* auto-fit rather than a fixed three, because Motion Control drops the
   duration control and a fixed grid would leave a hole where it was */
.vg-trio{display:grid;grid-auto-flow:column;grid-auto-columns:1fr;gap:8px;}
.vg-tri{
  display:flex;align-items:center;justify-content:center;gap:7px;cursor:pointer;
  padding:11px 6px;border-radius:12px;
  background:var(--a-sunk);box-shadow:inset 0 0 0 1px var(--a-line);
  transition:box-shadow .2s var(--e-out);
}
.vg-tri svg{width:15px;height:15px;color:var(--a-mute);flex:0 0 auto;}
.vg-tri b{font-size:13px;font-weight:600;color:var(--a-ink);font-variant-numeric:tabular-nums;}
.vg-tri:hover{box-shadow:inset 0 0 0 1.5px var(--vz-acc);}

/* ── bitrate badge ─────────────────────────*/
.vg-spark{
  display:inline-flex;align-items:center;gap:4px;flex:0 0 auto;
  padding:4px 9px;border-radius:7px;
  background:color-mix(in srgb,var(--vz-acc) 26%,transparent);
  color:var(--acc-text,var(--vz-acc));
  font-size:11px;font-weight:700;
}

/* ── generate ──────────────────────────────
   The one saturated thing on the panel, and the only place the accent is
   used at full strength. */
.vg-create{
  display:flex;align-items:center;justify-content:center;gap:12px;
  flex:0 0 auto;width:100%;height:58px;border-radius:16px;cursor:pointer;
  font-size:17px;font-weight:700;letter-spacing:-.02em;
  background:linear-gradient(180deg,var(--vz-acc),var(--vz-acc-2));
  color:var(--vz-acc-ink);
  text-shadow:0 1px 0 rgba(255,255,255,.32);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.5),
    inset 0 -1px 0 rgba(0,0,0,.13),
    0 10px 26px -12px color-mix(in srgb,var(--vz-acc) 90%,transparent);
  transition:transform .18s var(--e-out),box-shadow .18s var(--e-out);
}
.vg-create:hover{
  transform:translateY(-1px);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.55),
    inset 0 -1px 0 rgba(0,0,0,.13),
    0 16px 34px -14px color-mix(in srgb,var(--vz-acc) 95%,transparent);
}
.vg-create:active{transform:translateY(1px);transition-duration:.08s;}
.vg-create-c{
  display:inline-flex;align-items:center;gap:6px;
  padding:5px 12px;border-radius:100px;
  background:rgba(0,0,0,.17);
  font-size:14px;font-weight:700;font-variant-numeric:tabular-nums;
}
.vg-create-c svg{width:13px;height:13px;}
/* the sweep runs once on hover, so the button feels lit rather than flat */
.vg-create{position:relative;overflow:hidden;}
.vg-create::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(105deg,transparent 34%,rgba(255,255,255,.5) 50%,transparent 66%);
  transform:translateX(-120%);
}
.vg-create:hover::after{transform:translateX(120%);transition:transform .75s var(--e-out);}
@media (prefers-reduced-motion: reduce){.vg-create::after{display:none;}}
.vg-foot{padding-top:0;}
.vg-foot .vg-qty{margin-left:auto;}

.vg-hint{font-size:11.5px;line-height:1.5;color:var(--a-mute);margin:10px 0 0;}

@media (max-width:1080px){
  .vg-resgrid{grid-template-columns:repeat(3,1fr);}
}

/* ═══ WORKSPACE ═══
   With the hero gone this stops being a page with a tool on it and
   becomes a workspace. The shell takes the viewport under the nav, each
   column scrolls on its own, and the action is pinned so it stays
   reachable however long the composer gets. */
.vid-main{
  height:calc(100vh - 60px);
  overflow:hidden;
  padding:0;
}
.vid-main > .container{
  height:100%;
  max-width:none;
  padding:14px 18px;
  display:flex;
}
/* min-width:0 or the shell keeps its min-content width and the open panel
   runs off the right of the window */
.vg-shell{
  flex:1;min-width:0;min-height:0;
  gap:14px;align-items:stretch;padding-bottom:0;
}

/* the composer scrolls inside its own column, not the page */
.vg{
  align-self:stretch;
  min-height:0;
  overflow-y:auto;
  scrollbar-width:thin;
  padding-bottom:0;
}
/* the action sits below the scroll, always in reach */
.vg-stick{
  position:sticky;bottom:0;z-index:3;
  margin:6px -18px -18px;padding:12px 18px 16px;
  display:flex;flex-direction:column;gap:8px;
  background:linear-gradient(180deg,transparent,var(--a-panel) 26%);
}

/* the stage takes whatever is left and stays put */
.vg-stage,.vg-panel{align-self:stretch;min-height:0;max-height:none;}
.vg-stage-hold{height:auto;flex:1;min-height:0;}

/* ── samples in the empty stage ─────────────
   The gallery used to sit below the fold, where it was never scrolled to.
   Here it fills the wait with actual work, and each tile plays on hover. */
.vg-samples{
  display:grid;grid-template-columns:repeat(4,1fr);gap:8px;
  width:min(100%,440px);margin-bottom:4px;
}
.vg-sample{
  position:relative;display:block;aspect-ratio:3/4;
  border-radius:10px;overflow:hidden;
  background:var(--a-chip-2);
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:transform .45s var(--e-out),box-shadow .45s var(--e-out);
}
.vg-sample video{width:100%;height:100%;object-fit:cover;display:block;}
.vg-sample:hover{transform:translateY(-3px) scale(1.03);box-shadow:inset 0 0 0 1px var(--a-line),var(--lift-2);}
.vg-samples-note{
  font-style:normal;font-size:10.5px;letter-spacing:.05em;text-transform:uppercase;
  color:var(--a-mute);opacity:.75;
}
.vg-stage-empty b{font-size:15px;}

/* ── panel chrome ──────────────────────────
   Headers stay put while their bodies scroll, so you always know which
   panel you are in. */
.vg-panel-head{position:sticky;top:0;z-index:2;background:var(--a-panel);}

/* ── refinements ───────────────────────────*/
.vg-look{height:120px;}
.vg-tabs{position:sticky;top:0;z-index:4;background:var(--a-panel);padding-top:2px;margin-top:-2px;}
.vg-prompt textarea{min-height:78px;}

/* a hairline between the composer and the stage, rather than a gap alone */
.vg-shell::before{
  content:"";position:absolute;left:calc(430px + 7px);top:0;bottom:0;width:1px;
  background:linear-gradient(180deg,transparent,var(--a-line) 12%,var(--a-line) 88%,transparent);
  pointer-events:none;
}

@media (max-width:1080px){
  .vid-main{height:auto;overflow:visible;}
  .vid-main > .container{display:block;height:auto;padding:14px;}
  .vg{overflow:visible;}
  .vg-stick{position:static;margin:6px 0 0;padding:0;background:none;}
  .vg-shell::before{display:none;}
  .vg-stage-hold{height:clamp(220px,46vh,420px);flex:0 0 auto;}
  .vg-samples{grid-template-columns:repeat(4,1fr);width:100%;}
}

/* ═══ OUTPUT AND LOOK AS POPOVERS ═══
   These two hold a handful of controls, so a full-height column left most
   of the panel empty and made a small decision feel like a page change.
   They are now compact cards that pop in near the control that opened
   them, sized to their content. The engine picker keeps the column — it
   really does have thirty-odd rows to compare. */
.vg-panel.is-pop{
  position:fixed;z-index:70;
  flex:0 0 auto;align-self:auto;
  width:min(470px,calc(100vw - 24px));
  max-height:min(78vh,720px);
  border-radius:18px;
  background:var(--a-panel);
  box-shadow:
    inset 0 0 0 1px var(--a-line),
    0 2px 6px rgba(12,10,9,.10),
    0 28px 60px -18px rgba(12,10,9,.34);
  transform-origin:bottom left;
  z-index:200;
  animation:vg-pop .34s var(--e-out) both;
}
[data-app="dark"] .vg-panel.is-pop{
  box-shadow:
    inset 0 0 0 1px var(--a-line),
    0 2px 8px rgba(0,0,0,.5),
    0 30px 64px -18px rgba(0,0,0,.8);
}
/* short, so it reads as the panel arriving rather than travelling */
@keyframes vg-pop{
  from{opacity:0;transform:translateY(8px) scale(.97);}
  to  {opacity:1;transform:translateY(0) scale(1);}
}
.vg-panel.is-pop .vg-panel-head{padding:14px 16px;}
.vg-panel.is-pop .vg-panel-body{padding:14px 16px 18px;}
.vg-panel.is-pop .vg-panel-h{margin-bottom:8px;}
.vg-panel.is-pop .vg-panel-h + *{margin-bottom:16px;}
.vg-panel.is-pop .vg-resgrid{grid-template-columns:repeat(3,1fr);}


@media (prefers-reduced-motion: reduce){
  .vg-panel.is-pop{animation:none;}
}

/* ═══ IMAGE COMPOSER, REBUILT ═══
   It was a thin dark strip with a white button. Three things were wrong:
   it was too small to type into comfortably, the pills showed values with
   no clue what they controlled, and the action was white — the one moment
   the brand colour should appear, and it wasn't there.

   The bar now sits on the page rather than floating over it flatly: a
   frosted ground, a lit top edge, and a real shadow beneath. It grows
   when you focus it, so typing gets room without the bar being large
   while it waits. */
.gc{
  padding:16px 16px 14px;
  border-radius:24px;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.14),
    inset 0 0 0 1px var(--a-line),
    0 2px 8px rgba(10,9,8,.16),
    0 26px 60px -22px rgba(10,9,8,.5);
  transition:box-shadow .35s var(--e-out),transform .35s var(--e-out);
}
[data-app="dark"] .gc{
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.09),
    inset 0 0 0 1px var(--a-line),
    0 2px 10px rgba(0,0,0,.55),
    0 30px 70px -22px rgba(0,0,0,.85);
}
/* focus is the moment to give it presence, not before */
.gc:focus-within{
  transform:translateY(-2px);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.16),
    inset 0 0 0 1px var(--a-mute),
    0 2px 8px rgba(10,9,8,.18),
    0 34px 74px -22px rgba(10,9,8,.55);
}

.gc-top{gap:14px;align-items:flex-start;}

/* ── prompt ────────────────────────────────
   Bigger type and real room. It starts at three lines and grows, so the
   bar is not oversized while it sits empty. */
.gc-input{
  padding:10px 6px 4px;
  font-size:15.5px;line-height:1.5;
  min-height:26px;max-height:200px;
}
.gc-input::placeholder{color:var(--a-mute);}

/* ── references ────────────────────────────*/
.gc-ref{width:52px;height:52px;border-radius:14px;}
.gc-refs{gap:8px;max-width:260px;}
.gc-ref-add{
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:box-shadow .2s var(--e-out),color .2s var(--e-out);
}
.gc-ref-add:hover{box-shadow:inset 0 0 0 1.5px var(--vz-acc);}
.gc-ref-add svg{width:20px;height:20px;}

/* ── the control row ───────────────────────*/
.gc-bar{gap:12px;padding-top:12px;margin-top:12px;border-top:1px solid var(--a-line);}
.gc-opts{gap:7px;}

/* Each pill states what it controls above what it is set to. A row of
   bare values reads as tags; a row of labelled values reads as settings. */
.gc-opt,.gc-count{
  height:46px;padding:0 14px;border-radius:13px;
  transition:box-shadow .2s var(--e-out),background-color .2s var(--e-out);
}
.gc-opt{box-shadow:inset 0 0 0 1px transparent;}
.gc-opt:hover{box-shadow:inset 0 0 0 1px var(--a-line);}
.gc-opt[aria-expanded="true"]{box-shadow:inset 0 0 0 1.5px var(--vz-acc);}
.gc-opt-txt{
  display:flex;flex-direction:column;align-items:flex-start;gap:1px;
  line-height:1.15;text-align:left;
}
.gc-opt-txt em{
  font-style:normal;font-size:8.5px;font-weight:700;
  letter-spacing:.09em;text-transform:uppercase;
  color:var(--a-mute);
}
.gc-opt-txt > span{font-size:13px;font-weight:600;color:var(--a-ink);white-space:nowrap;}
.gc-count{gap:8px;}
.gc-count .gc-opt-txt > span{font-variant-numeric:tabular-nums;}
.gc-step{width:26px;height:26px;}

/* ── the action ────────────────────────────
   Yellow, like every other primary action in the studio. It was white,
   which made the one branded moment on the page generic. */
.gc-go{
  height:54px;padding:0 30px;border-radius:16px;gap:13px;
  font-size:15.5px;font-weight:700;letter-spacing:-.012em;
  background:linear-gradient(180deg,var(--vz-acc),var(--vz-acc-2))!important;
  color:var(--vz-acc-ink)!important;
  text-shadow:0 1px 0 rgba(255,255,255,.3);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.5),
    inset 0 -1px 0 rgba(0,0,0,.13),
    0 10px 26px -12px color-mix(in srgb,var(--vz-acc) 90%,transparent);
}
.gc-go:hover{
  transform:translateY(-1px);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.55),
    inset 0 -1px 0 rgba(0,0,0,.13),
    0 16px 34px -14px color-mix(in srgb,var(--vz-acc) 95%,transparent)!important;
}
.gc-go-c{
  display:inline-flex;align-items:center;gap:5px;
  padding:5px 11px;border-radius:100px;
  background:rgba(0,0,0,.16);
  font-size:13px;font-variant-numeric:tabular-nums;
}
.gc-go-c svg{width:12px;height:12px;}


@media (max-width:720px){
  .gc{padding:12px 12px 10px;border-radius:20px;}
  .gc-bar{flex-wrap:wrap;}
  .gc-opt-txt em{display:none;}
  .gc-opt,.gc-count{height:42px;}
  /* it stays the biggest thing on the bar at every width */
  .gc-go{height:48px;flex:1;justify-content:center;padding:0 20px;}
}

/* ═══ NO DOUBLE FOCUS RING ON FRAMED FIELDS ═══
   The global :focus-visible ring is right for buttons and links, where
   nothing else marks focus. It is wrong for a text field that sits inside
   a container which already reacts — the composer firms its hairline and
   lifts, so the field drew a second, louder box inside the first.

   Suppressed only where the wrapper genuinely indicates focus, so focus
   is never left invisible. Note these fields still show the caret.

   Worth recording how this was missed the first time: a programmatic
   .focus() does NOT put a text field into :focus-visible, so measuring
   after el.focus() reported no ring while a real click showed one. It has
   to be tested with an actual click. */
[data-app] .gc-input:focus-visible,
[data-app] .cmp-input:focus-visible,
[data-app] .vg-prompt textarea:focus-visible,
[data-app] .vg-search input:focus-visible,
[data-app] .tpl-search input:focus-visible,
[data-app] .as-search input:focus-visible,
[data-app] .set-field input:focus-visible,
[data-app] .as-modal-new input:focus-visible{
  outline:none;
}

/* ═══ RESOLUTION: LABELS ONLY ═══
   The pixel maths was information nobody was going to use while choosing.
   The tier name is the decision. */
.vg-resgrid{display:flex;gap:6px;}
.vg-res{
  flex:1;min-width:0;
  display:flex;align-items:center;justify-content:center;gap:6px;
  padding:14px 8px;border-radius:12px;cursor:pointer;
  background:var(--a-sunk);box-shadow:inset 0 0 0 1px var(--a-line);
  transition:box-shadow .2s var(--e-out),background-color .2s var(--e-out),transform .2s var(--e-out);
}
.vg-res b{font-size:14px;font-weight:700;color:var(--a-ink);letter-spacing:-.01em;}
.vg-res-max{
  font-style:normal;font-size:8px;font-weight:700;
  letter-spacing:.06em;text-transform:uppercase;line-height:1;
  padding:3px 5px;border-radius:4px;
  background:var(--vz-acc);color:var(--vz-acc-ink);
}
.vg-res:hover:not(:disabled){transform:translateY(-1px);box-shadow:inset 0 0 0 1px var(--a-mute);}
.vg-res.is-on{
  background:color-mix(in srgb,var(--vz-acc) 16%,var(--a-panel));
  box-shadow:inset 0 0 0 1.5px var(--vz-acc);
}
.vg-res.is-off{opacity:.32;cursor:not-allowed;}

/* ═══ DURATION: A RULER ═══
   Duration is a whole number of seconds over a short range, so a
   continuous slider was the wrong instrument — it implied precision that
   does not exist and hid where the engine's limits are. This is a ruler:
   one tick per second, taller every fifth, filled up to the chosen value.
   Every tick is clickable, so the preset chips underneath became
   redundant and went. */
.vg-ruler-w{display:flex;align-items:flex-end;gap:16px;}
.vg-ruler{
  flex:1;min-width:0;
  display:flex;flex-direction:column;gap:5px;
  position:relative;cursor:pointer;
  touch-action:none;
}
.vg-ruler-bars{display:flex;align-items:flex-end;gap:2px;height:32px;}
/* one cell per second, so the numbers line up with the ticks above */
.vg-ruler-scale{display:flex;gap:2px;}
.vg-scale-c{
  flex:1;min-width:0;text-align:center;
  font-size:9.5px;font-weight:600;color:var(--a-mute);
  font-variant-numeric:tabular-nums;line-height:1;
}
.vg-scale-c.is-at{color:var(--a-ink);}

.vg-tick{
  position:relative;flex:1;min-width:0;
  height:14px;border-radius:3px 3px 0 0;cursor:pointer;
  background:var(--a-chip-2);
  transition:background-color .16s var(--e-out),height .18s var(--e-out);
}
.vg-tick.is-major{height:22px;}
.vg-tick.is-fill{background:var(--vz-acc);}
.vg-tick:hover{background:var(--a-mute);}
.vg-tick.is-fill:hover{background:var(--vz-acc-2);}


/* the current position gets a cap so the value is findable at a glance */
.vg-tick.is-at{height:30px;background:var(--vz-acc);}
.vg-tick.is-at::after{
  content:"";position:absolute;left:50%;top:-7px;transform:translateX(-50%);
  width:11px;height:11px;border-radius:50%;
  background:var(--vz-acc);
  box-shadow:0 0 0 3px var(--a-panel),0 2px 6px rgba(0,0,0,.3);
}
.vg-ruler:focus-visible{outline:none;}
.vg-ruler:focus-visible::before{
  content:"";position:absolute;inset:-6px -4px;border-radius:12px;
  box-shadow:inset 0 0 0 2px color-mix(in srgb,var(--vz-acc) 60%,transparent);
}

/* the read-out, sized to be the thing you look at */
.vg-ruler-read{
  flex:0 0 auto;display:flex;align-items:baseline;gap:2px;
}
.vg-ruler-read > b{
  font-size:30px;font-weight:700;letter-spacing:-.04em;
  color:var(--a-ink);font-variant-numeric:tabular-nums;line-height:1;
}
.vg-ruler-read > i{font-style:normal;font-size:15px;font-weight:600;color:var(--a-ink);}
.vg-ruler-of{
  margin-left:8px;font-size:11px;color:var(--a-mute);
  font-variant-numeric:tabular-nums;align-self:flex-end;
}

@media (prefers-reduced-motion: reduce){
  .vg-tick{transition:none;}
}

/* ═══ MODEL PICKER, REBUILT ═══
   The list was one engine per full-width row: name pinned left,
   capabilities pinned right, a void between. On a wide panel that means
   crossing the whole screen to read one engine, and crossing it twice to
   compare two. Cards keep each engine's facts in one place, and the grid
   puts comparable things side by side. */
/* The sheet used to run the full width of a 1900px window: seven columns
   of thin text boxes with nothing to fix the eye on, which is what made
   it read as scattered. Capping the column at 1440 puts it at four, and
   stops the three recommended cards being 630px letterboxes. */
.vg-panel[data-vg-panel="model"] .vg-panel-body > *{max-width:1440px;margin-inline:auto;}
/* ── grouped by house ──
   Kling next to Kling, Seedance next to Seedance. The list is a stack of
   shelves now, each with its own mark and count, rather than one wall of
   thirty-four cards with each family scattered through it. */
.vg-list{display:flex;flex-direction:column;gap:16px;}
.vg-group-h{display:flex;align-items:center;gap:8px;margin:0 0 8px;}
.vg-group-ico{
  flex:0 0 auto;width:20px;height:20px;border-radius:6px;
  display:grid;place-items:center;
  background:var(--a-chip);color:var(--a-ink);
  box-shadow:inset 0 0 0 1px var(--a-line);
}
.vg-group-ico svg{width:11px;height:11px;}
.vg-group-ico:has(img){background:#fff;}
.vg-group-h b{
  font-size:10px;font-weight:700;letter-spacing:.11em;text-transform:uppercase;
  color:var(--a-ink);white-space:nowrap;
}
.vg-group-h em{
  font-style:normal;font-size:10px;font-weight:600;
  padding:1.5px 6px;border-radius:100px;
  background:var(--a-chip);color:var(--a-mute);
  font-variant-numeric:tabular-nums;
}
/* the rule runs out to the edge, so the header reads as a shelf label
   rather than a floating word */
.vg-group-h i{flex:1;height:1px;background:var(--a-line);}
.vg-group-g{
  display:grid;
  /* min() so a 250px column is a preference, never a floor on how narrow
     the panel is allowed to get */
  grid-template-columns:repeat(auto-fill,minmax(min(250px,100%),1fr));
  gap:8px;
}
.vg-card{
  display:grid;grid-template-rows:auto auto auto;gap:7px;
  padding:11px;border-radius:12px;cursor:pointer;text-align:left;
  background:var(--a-sunk);
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:transform .22s var(--e-out),box-shadow .22s var(--e-out);
}
.vg-card-top{display:flex;align-items:center;gap:9px;min-width:0;}
.vg-card .vg-item-name{font-size:12.5px;gap:6px;}
.vg-card .vg-card-by{font-size:9.5px;}
.vg-card-id{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px;}

/* the house mark — one drawn glyph per family, so Seedance and Kling are
   told apart before their names are read */
.vg-card-ico{
  flex:0 0 auto;width:27px;height:27px;border-radius:9px;
  display:grid;place-items:center;
  background:var(--a-chip);color:var(--a-ink);
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:background-color .22s var(--e-out),color .22s var(--e-out);
}
.vg-card-ico svg{width:15px;height:15px;}
/* a vendor's own file is full-colour and carries its own ground rules, so
   the tile goes white in both themes and nothing recolours the mark */
.vg-card-ico.has-logo{background:#fff;}
.vg-card-ico img,.vg-row-mark img,.vg-stage-mark img,.vg-group-ico img{
  width:70%;height:70%;object-fit:contain;display:block;
}
.vg-row-mark:has(img),.vg-stage-mark:has(img){background:#fff;}
.vg-row-mark svg{width:15px;height:15px;}
.vg-stage-mark svg{width:14px;height:14px;}
.vg-card-ico.is-letter{font-size:11px;font-weight:700;}
.vg-card:hover .vg-card-ico{background:var(--a-chip-2);}
.vg-card.is-on .vg-card-ico{background:var(--vz-acc);color:var(--vz-acc-ink);}
.vg-card:hover{transform:translateY(-2px);box-shadow:inset 0 0 0 1px var(--a-mute),var(--lift-2);}
.vg-card.is-on{
  background:color-mix(in srgb,var(--vz-acc) 12%,var(--a-panel));
  box-shadow:inset 0 0 0 1.5px var(--vz-acc);
}

.vg-card-head{display:flex;align-items:center;gap:10px;}
.vg-card-id{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px;}
.vg-card-by{
  font-size:10.5px;letter-spacing:.04em;text-transform:uppercase;
  color:var(--a-mute);
}
/* a tick, so the chosen engine is obvious without reading the border */
.vg-card-on{
  flex:0 0 auto;width:20px;height:20px;border-radius:50%;
  display:flex;align-items:center;justify-content:center;
  background:var(--vz-acc);color:var(--vz-acc-ink);
}
.vg-card-on svg{width:11px;height:11px;}

.vg-card .vg-item-desc{
  font-size:11.5px;line-height:1.38;color:var(--a-ink);
  /* exactly two lines, whether the text needs one or three */
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;
  overflow:hidden;height:2.76em;
}
/* glyphs on the left, the spec on the right. The dividing rule is gone:
   at this size the gap does the same work without the extra 10px. */
.vg-card-foot{
  display:flex;align-items:center;justify-content:space-between;gap:8px;
  min-height:20px;
}
.vg-card .vg-caps{max-width:none;justify-content:flex-start;gap:5px;min-height:0;}
.vg-cap.is-ico{
  width:20px;height:20px;padding:0;border-radius:6px;
  display:grid;place-items:center;
  background:var(--a-chip);color:var(--a-ink);
}
.vg-cap.is-ico svg{width:11.5px;height:11.5px;}
/* the capability word, out of sight but still in the button's name */
.vg-sr{
  position:absolute;width:1px;height:1px;margin:-1px;padding:0;border:0;
  overflow:hidden;white-space:nowrap;clip-path:inset(50%);
}
.vg-card.is-on .vg-cap.is-ico{background:var(--a-chip-2,var(--a-chip));}
.vg-card-spec{
  font-size:10px;color:var(--a-mute);
  font-variant-numeric:tabular-nums;letter-spacing:.01em;
}

/* ── recommended ────────────────────────────
   Taller, with a heavier scrim: the sample frames have their own text and
   branding in them, and a thin gradient let that fight the model name. */
.vg-feat{grid-template-columns:repeat(auto-fit,minmax(min(210px,100%),1fr));gap:10px;}
.vg-feat-card{
  min-height:112px;padding:13px;
  background-size:cover;background-position:center;
}
.vg-feat-card[data-tone]{
  background-image:linear-gradient(180deg,rgba(8,7,6,.25) 20%,rgba(8,7,6,.9));
}
.vg-feat-name{font-size:16px;}
.vg-feat-desc{
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
}

/* ── filter row ─────────────────────────────*/
.vg-count{
  font-size:12px;font-weight:600;color:var(--a-mute);margin-left:auto;
}
.vg-count b{
  padding:4px 9px;border-radius:100px;
  background:var(--a-chip);color:var(--a-ink);
  font-weight:600;font-variant-numeric:tabular-nums;
}

@media (max-width:1240px){
  .vg-group-g{grid-template-columns:repeat(auto-fill,minmax(min(230px,100%),1fr));}
}
@media (max-width:700px){
  .vg-group-g{grid-template-columns:1fr;}
}

/* ═══ TOOLTIPS ═══
   Icon-only controls have to say what they are. The native title attribute
   does this, but it waits about a second, cannot be styled, and never
   appears for keyboard users — so this is a CSS tooltip on [data-tip],
   shown on hover AND on keyboard focus.

   aria-hidden on both layers: the control already carries its own
   aria-label, and a screen reader announcing the same words twice is
   worse than not having the tooltip at all. */
[data-tip]{position:relative;}
[data-tip]::after,
[data-tip]::before{
  position:absolute;left:50%;bottom:calc(100% + 8px);
  opacity:0;pointer-events:none;
  transform:translate(-50%,4px);
  transition:opacity .16s var(--e-out),transform .16s var(--e-out);
  z-index:300;
}
[data-tip]::after{
  content:attr(data-tip);
  white-space:nowrap;
  padding:6px 10px;border-radius:8px;
  background:var(--a-ink);color:var(--a-panel);
  font-size:11.5px;font-weight:600;letter-spacing:-.01em;line-height:1;
  box-shadow:0 6px 18px -6px rgba(0,0,0,.5);
}
/* the little arrow, drawn as a rotated square tucked under the bubble */
[data-tip]::before{
  content:"";width:8px;height:8px;
  bottom:calc(100% + 4.5px);
  background:var(--a-ink);
  transform:translate(-50%,4px) rotate(45deg);
  border-radius:1px;
}
[data-tip]:hover::after,
[data-tip]:hover::before,
[data-tip]:focus-visible::after,
[data-tip]:focus-visible::before{
  opacity:1;
  transform:translate(-50%,0);
}
[data-tip]:focus-visible::before,
[data-tip]:hover::before{transform:translate(-50%,0) rotate(45deg);}

/* a disabled control still explains itself — that is when you most want
   to know why it will not respond */
[data-tip]:disabled:hover::after,
[data-tip]:disabled:hover::before{opacity:1;transform:translate(-50%,0);}
[data-tip]:disabled:hover::before{transform:translate(-50%,0) rotate(45deg);}

/* near the top of a panel there is no room above, so it flips below */
[data-tip-below]::after{bottom:auto;top:calc(100% + 8px);}
[data-tip-below]::before{bottom:auto;top:calc(100% + 4.5px);}

/* A rail down the right edge of a frame has nothing above it and the
   frame clips its own overflow, so those tips open inward instead. */
[data-tip-left]::after{left:auto;right:calc(100% + 9px);bottom:auto;top:50%;transform:translate(4px,-50%);}
[data-tip-left]::before{left:auto;right:calc(100% + 5.5px);bottom:auto;top:50%;transform:translate(4px,-50%) rotate(45deg);}
[data-tip-left]:hover::after,[data-tip-left]:focus-visible::after{transform:translate(0,-50%);}
[data-tip-left]:hover::before,[data-tip-left]:focus-visible::before{transform:translate(0,-50%) rotate(45deg);}

@media (prefers-reduced-motion: reduce){
  [data-tip]::after,[data-tip]::before{transition:none;}
}
@media (hover:none){
  [data-tip]::after,[data-tip]::before{display:none;}
}


/* ═══ THE SELECTION RING ═══
   Nothing is drawn until the card is chosen. On selection the black frame
   wipes UPWARD into place: the ring exists at full size the whole time,
   and a clip-path reveals it from the bottom edge up.

   clip-path is doing the work rather than a height or a border animation,
   because both of those change layout every frame. This one runs on the
   compositor and cannot shift anything around it. */
.app-model-ring{
  position:absolute;inset:0;z-index:3;
  border-radius:16px;              /* matches .app-model-card */
  pointer-events:none;
  box-shadow:inset 0 0 0 2.5px var(--a-ink);
  /* inset(100% 0 0 0) = the visible band is a zero-height sliver at the
     BOTTOM, so opening it to inset(0) travels upward */
  clip-path:inset(100% 0 0 0);
}
.app-model-card.is-selected .app-model-ring{
  animation:mdl-wipe .52s cubic-bezier(.22,1,.36,1) forwards;
}
@keyframes mdl-wipe{
  from{clip-path:inset(100% 0 0 0);}
  to  {clip-path:inset(0 0 0 0);}
}

/* only the soft depth shadow on the card itself — the frame is the marker */
.app-model-card.is-selected{box-shadow:0 20px 40px -28px rgba(0,0,0,.35);}

/* the tick lands after the frame has closed */
.app-model-card.is-selected::after{
  animation:mdl-tick .26s var(--e-out) .3s both;
}
@keyframes mdl-tick{
  from{opacity:0;transform:scale(.5);}
  to  {opacity:1;transform:scale(1);}
}

@media (prefers-reduced-motion: reduce){
  .app-model-card.is-selected .app-model-ring{animation:none;clip-path:inset(0 0 0 0);}
  .app-model-card.is-selected::after{animation:none;}
}

/* ═══ MODEL PICKER, POLISHED ═══ */

/* the name sits on its own quiet band, so the photograph ends cleanly
   instead of bleeding into the label */
[data-app] .app-model-name{
  padding:12px 6px;
  background:var(--a-sunk);
  border-top:1px solid var(--a-line);
  font-size:13px;font-weight:600;letter-spacing:-.01em;
  color:var(--a-ink);
  transition:background-color .3s var(--e-out),color .3s var(--e-out);
}
[data-app] .app-model-card{
  background:var(--a-panel);
  box-shadow:inset 0 0 0 1px var(--a-line), var(--lift-1);
  transition:transform .4s var(--e-out),box-shadow .4s var(--e-out);
}
[data-app] .app-model-card:hover{
  transform:translateY(-3px);
  box-shadow:inset 0 0 0 1px var(--a-line), var(--lift-3);
}
[data-app] .app-model-card:hover .app-model-name{background:var(--a-chip);}
[data-app] .app-model-img{background:var(--a-sunk);}

/* Chosen: a shade up from the resting band, not black. The black frame is
   already the marker — repeating it in the label made the whole bottom of
   the card read as a second, competing signal. This is just enough to say
   "this one" without shouting. */
[data-app] .app-model-card.is-selected .app-model-name{
  background:var(--a-chip-2);
  color:var(--a-ink);
  font-weight:700;
}
[data-app] .app-model-card.is-selected{
  box-shadow:inset 0 0 0 1px transparent, var(--lift-2);
}

/* ── the wipe, softened ──
   Slower, and on a curve with no overshoot at either end. The previous
   one started instantly; this eases in as well as out, which is what
   reads as smooth rather than fast. */
.app-model-ring{
  box-shadow:inset 0 0 0 2px var(--a-ink);
  border-radius:16px;
}
.app-model-card.is-selected .app-model-ring{
  animation:mdl-wipe .68s cubic-bezier(.45,.05,.15,1) forwards;
}

/* the tick fades rather than pops, and waits for the frame to arrive */
@keyframes mdl-tick{
  from{opacity:0;transform:scale(.72);}
  to  {opacity:1;transform:scale(1);}
}
[data-app] .app-model-card.is-selected::after{
  background:var(--a-ink);color:var(--a-panel);
  animation:mdl-tick .34s cubic-bezier(.22,1,.36,1) .42s both;
}

/* the grid itself: even gutters and a sensible minimum, so the rows do
   not go ragged as the panel width changes */
[data-app] .app-model-grid{
  display:grid;
  grid-template-columns:repeat(auto-fill,minmax(132px,1fr));
  gap:14px;
}

/* ═══ THE EMPTY STATE ═══
   What the Image page opens on before anything has been made: a fan of
   frames, the engine you are about to use named in the accent, and one
   line telling you what to type. The sample wall stays below it, so
   there is work to scroll to rather than a void. */
.gw-empty{
  display:flex;flex-direction:column;align-items:center;
  gap:6px;text-align:center;
  padding:8vh 24px 6vh;
}

/* ── the fan ────────────────────────────────
   Four prints splayed as if dropped on a table. The angles and offsets
   are per-tile custom properties so the arrangement can be retuned in
   the markup without touching this rule. */
.gw-fan{
  display:flex;align-items:center;justify-content:center;
  margin-bottom:26px;
  perspective:900px;
}
.gw-fan-i{
  position:relative;z-index:var(--z,1);
  width:clamp(96px,11vw,148px);
  aspect-ratio:3/4;
  margin:0 -12px;
  border-radius:14px;overflow:hidden;
  transform:rotate(var(--r,0deg)) translate(var(--x,0),var(--y,0));
  box-shadow:
    0 0 0 1px rgba(255,255,255,.1),
    0 2px 6px rgba(0,0,0,.3),
    0 22px 44px -18px rgba(0,0,0,.7);
  transition:transform .5s var(--e-out);
}
[data-app="light"] .gw-fan-i{
  box-shadow:
    0 0 0 1px var(--a-line),
    0 2px 6px rgba(12,10,9,.1),
    0 22px 44px -18px rgba(12,10,9,.32);
}
/* one round frame breaks the row of rectangles */
.gw-fan-i.is-round{
  border-radius:50%;
  aspect-ratio:1;
  width:clamp(84px,9.5vw,124px);
}
.gw-fan-i img{width:100%;height:100%;object-fit:cover;display:block;}
/* the fan opens a little on hover — the whole group, not one tile */
.gw-fan:hover .gw-fan-i{transform:rotate(calc(var(--r,0deg) * 1.5)) translate(calc(var(--x,0px) * 1.7),var(--y,0));}

/* ── words ──────────────────────────────────*/
.gw-empty-h{
  margin:0;
  font-size:clamp(22px,3vw,34px);
  font-weight:800;letter-spacing:-.02em;line-height:1.1;
  text-transform:uppercase;
  color:var(--a-ink);
}
/* the engine name is the one accent on the screen, and it changes with
   the picker so the page always names what you are about to run */
.gw-empty-h b{
  display:block;font-weight:800;
  color:var(--acc-text,var(--vz-acc));
}
[data-app="dark"] .gw-empty-h b{color:var(--vz-acc);}
.gw-empty-p{
  margin:10px 0 0;max-width:46ch;
  font-size:14.5px;line-height:1.55;color:var(--a-mute);
}
.gw-empty-note{
  margin:14px 0 0;max-width:52ch;
  font-size:11.5px;line-height:1.5;color:var(--a-mute);opacity:.75;
}

/* once something has been generated the fan gives way to the results */
.gw-empty[hidden]{display:none !important;}

@media (max-width:640px){
  .gw-empty{padding:5vh 18px 4vh;}
  .gw-fan-i{margin:0 -8px;}
}

/* ── input switch + multi-shot ──────────────
   Only appear for engines that genuinely offer the choice: the switch for
   the nine that take both references and frames, the shot stepper for the
   six that can cut between shots. */
.vg-switchrow{
  display:grid;grid-template-columns:1fr 1fr;gap:3px;
  padding:3px;border-radius:12px;
  background:var(--a-sunk);box-shadow:inset 0 0 0 1px var(--a-line);
}
.vg-switchrow[hidden]{display:none !important;}
.vg-seg2{
  padding:9px 6px;border-radius:9px;cursor:pointer;
  font-size:12.5px;font-weight:600;color:var(--a-mute);
  transition:color .18s var(--e-out),background-color .18s var(--e-out);
}
.vg-seg2:hover{color:var(--a-ink);}
.vg-seg2.is-on{background:var(--a-btn);color:var(--a-btn-ink);}

.vg-shotsteps{display:flex;gap:2px;flex:0 0 auto;}
.vg-shotsteps button{
  width:28px;height:28px;border-radius:8px;cursor:pointer;
  font-size:15px;line-height:1;color:var(--a-ink);
  background:var(--a-chip);
}
.vg-shotsteps button:hover{background:var(--a-chip-2);}

/* ═══════════════════════════════════════════
   MOTION CONTROL
   ═══════════════════════════════════════════
   Deliberately unlike the two pages either side of it. The video
   composer is a dense column of controls because it has thirty engines
   and a dozen settings; the UGC flow is a wizard because it asks four
   questions in order. This page has exactly two inputs and one
   relationship between them, so it is laid out as that sentence — wide,
   spare, and readable from across the room.
   ═══════════════════════════════════════════ */
.mc-main{padding:38px 0 90px;}

/* ── head ── */
.mc-head{max-width:680px;margin-bottom:44px;}
.mc-kicker{
  display:inline-block;margin-bottom:14px;
  font-size:10px;font-weight:700;letter-spacing:.16em;text-transform:uppercase;
  color:var(--a-mute);
}
.mc-h1{
  margin:0;font-size:clamp(30px,4.4vw,50px);line-height:1.06;
  font-weight:600;letter-spacing:-.035em;color:var(--a-ink);
}
.mc-h1 b{font-weight:600;color:var(--a-mute);}
.mc-sub{
  margin:18px 0 0;max-width:52ch;
  font-size:15px;line-height:1.6;color:var(--a-mute);
}

/* ── the two slots ──
   Sized by aspect rather than a fixed height so the pair stays balanced
   at any width, and the arrow sits in its own column so neither slot can
   ever be pushed onto a second row. */
.mc-flow{
  display:grid;grid-template-columns:1fr 96px 1fr;
  align-items:center;gap:0;margin-bottom:34px;
}
.mc-slot{
  position:relative;display:block;cursor:pointer;
  aspect-ratio:4/3;
  border-radius:20px;overflow:hidden;
  background:var(--a-sunk);
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:box-shadow .28s var(--e-out),transform .28s var(--e-out);
}
.mc-slot:hover{box-shadow:inset 0 0 0 1.5px var(--a-mute);transform:translateY(-2px);}
.mc-slot.is-over{box-shadow:inset 0 0 0 2px var(--vz-acc);transform:translateY(-2px);}
.mc-slot.is-filled{box-shadow:inset 0 0 0 1.5px var(--a-line);}
/* the target reads as the destination: a hair brighter than the source */
.mc-slot.is-target{background:var(--a-panel);}

.mc-slot-tag{
  position:absolute;top:14px;left:16px;z-index:2;
  padding:4px 9px;border-radius:100px;
  font-size:9.5px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;
  color:var(--a-mute);background:var(--a-chip);
}
.mc-slot.is-filled .mc-slot-tag{background:var(--a-panel);color:var(--a-ink);}

.mc-slot-empty{
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:4px;height:100%;padding:34px 26px 46px;text-align:center;
}
.mc-slot-ic{
  display:grid;place-items:center;
  width:66px;height:66px;margin-bottom:12px;border-radius:16px;
  background:var(--a-chip);color:var(--a-mute);
  transition:color .28s var(--e-out),background-color .28s var(--e-out);
}
.mc-slot-ic.is-round{border-radius:50%;}
.mc-slot-ic svg{width:32px;height:32px;}
.mc-slot:hover .mc-slot-ic{background:var(--a-chip-2);color:var(--a-ink);}
.mc-slot-empty b{font-size:16px;font-weight:600;letter-spacing:-.01em;color:var(--a-ink);}
.mc-slot-empty em{font-style:normal;font-size:12.5px;line-height:1.5;color:var(--a-mute);max-width:26ch;}

.mc-slot-full{position:absolute;inset:0;display:block;}
.mc-slot-full video,.mc-slot-full img{width:100%;height:100%;object-fit:cover;display:block;}
.mc-slot-x{
  position:absolute;top:12px;right:12px;z-index:3;
  width:28px;height:28px;border-radius:50%;cursor:pointer;
  display:grid;place-items:center;font-size:12px;
  background:rgba(0,0,0,.62);color:#fff;
  backdrop-filter:blur(6px);
}
.mc-slot-foot{
  position:absolute;left:0;right:0;bottom:0;z-index:2;
  padding:10px 14px;
  font-size:11px;letter-spacing:.01em;text-align:center;
  color:var(--a-mute);background:var(--a-sunk);
  border-top:1px solid var(--a-line);
}
.mc-slot.is-filled .mc-slot-foot{color:var(--a-ink);background:var(--a-panel);}
.mc-slot.is-target .mc-slot-foot{background:var(--a-panel);}

/* ── the arrow ──
   The only piece of the page whose job is to be read as a sentence
   rather than used. */
.mc-arrow{
  display:flex;flex-direction:column;align-items:center;gap:8px;
  color:var(--a-mute);padding:0 8px;
}
.mc-arrow svg{width:52px;height:22px;}
.mc-arrow em{
  font-style:normal;font-size:9.5px;font-weight:600;
  letter-spacing:.09em;text-transform:uppercase;text-align:center;
}

/* ── settings ──
   One card with hairline dividers instead of four separate boxes. Four
   floating panels for four settings reads as clutter at this size; the
   card gives them one edge and lets the dividers do the separating. */
/* The entrance animation puts a transform on this section, and a
   transform creates a stacking context — which traps the popover's
   z-index inside it. Without an explicit order the Generate button, a
   later sibling with a stacking context of its own, painted straight
   over the open engine list. The sections below are pinned under it. */
/* ── the control bar ──
   One card the same width as the slots, but packed rather than
   stretched. The previous pass spread four settings and a submit button
   across 1200px, which left every cell mostly air and turned Generate
   into a slab. Segments with hairline dividers use the same width and
   read as one instrument.

   The entrance animation puts a transform on this section, and a
   transform creates a stacking context — which traps the popovers'
   z-index inside it. The sections below are pinned under it explicitly. */
.mc-set{
  position:relative;z-index:30;
  margin:0 0 56px;
  border-radius:18px;overflow:visible;
  background:var(--a-panel);
  box-shadow:inset 0 0 0 1px var(--a-line);
}
/* Each control that opens a panel needs its own positioned ancestor, or
   the panel hangs off the whole card instead of off the control. */
.mc-field{position:relative;}

.mc-bar{
  display:grid;
  grid-template-columns:minmax(0,1.7fr) minmax(0,1fr) minmax(0,1.15fr);
  border-bottom:1px solid var(--a-line);
}
.mc-seg + .mc-seg{border-left:1px solid var(--a-line);}

.mc-row,.mc-tile{
  display:flex;width:100%;cursor:pointer;text-align:left;
  background:none;
  transition:background-color .2s var(--e-out);
}
.mc-row{align-items:center;gap:11px;padding:13px 15px;border-radius:18px 0 0 0;}
.mc-row:hover,.mc-tile:hover{background:var(--a-chip);}
.mc-row-mark{
  flex:0 0 auto;display:grid;place-items:center;
  width:31px;height:31px;border-radius:9px;
  font-size:13px;font-weight:700;color:#fff;background:#333;
}
.mc-row-txt,.mc-tile-txt{display:flex;flex-direction:column;gap:2px;min-width:0;}
.mc-row-txt em,.mc-tile em,.mc-tile-txt em{
  font-style:normal;font-size:9px;font-weight:700;letter-spacing:.12em;
  text-transform:uppercase;color:var(--a-mute);
}
/* the engine name is the longest label on the bar and must not wrap the
   row to two lines — it clips instead, and the panel shows it in full */
.mc-row-txt b{
  font-size:13.5px;font-weight:600;color:var(--a-ink);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.mc-chev{width:14px;height:14px;flex:0 0 auto;margin-left:auto;color:var(--a-mute);}

.mc-tile{flex-direction:column;gap:3px;align-items:flex-start;padding:13px 15px;}
.mc-tile b{font-size:13.5px;font-weight:600;color:var(--a-ink);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.mc-tile-v{display:flex;align-items:center;justify-content:space-between;gap:8px;width:100%;min-width:0;}
.mc-tile-v svg{width:13px;height:13px;flex:0 0 auto;color:var(--a-mute);}

.mc-seg-switch{
  display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:13px 15px;
}
.mc-tile-txt b{font-size:13.5px;font-weight:600;color:var(--a-ink);}

/* ── scene control ──
   Revealed by the toggle in the bar. Off, the background is whatever the
   motion clip already had and there is nothing to choose, so the row is
   absent rather than present and disabled. */
.mc-scene{
  display:flex;align-items:center;gap:16px;flex-wrap:wrap;
  padding:12px 15px;
  border-bottom:1px solid var(--a-line);
  background:var(--a-sunk);
}
.mc-seg2{
  display:inline-flex;flex:0 0 auto;gap:3px;padding:3px;border-radius:11px;
  background:var(--a-chip);
}
.mc-seg2 button{
  display:inline-flex;align-items:center;gap:6px;
  padding:7px 15px;border-radius:8px;cursor:pointer;
  font-size:12.5px;font-weight:600;color:var(--a-mute);
  transition:background-color .2s var(--e-out),color .2s var(--e-out);
}
.mc-seg2 button svg{width:14px;height:14px;}
.mc-seg2 button:hover{color:var(--a-ink);}
.mc-seg2 button.is-on{background:var(--a-panel);color:var(--a-ink);box-shadow:var(--lift-1,0 1px 3px rgba(0,0,0,.25));}
.mc-scene-hint{
  margin:0;flex:1;min-width:220px;
  font-size:11.5px;line-height:1.5;color:var(--a-mute);
}

/* ── second row: notes and submit share it ── */
.mc-foot{
  display:grid;grid-template-columns:minmax(0,1fr) 300px;
  gap:0;align-items:stretch;
}
.mc-note-f{
  display:flex;flex-direction:column;gap:7px;min-width:0;
  padding:13px 15px 15px;
}
.mc-note-f > span{
  font-size:9px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;
  color:var(--a-mute);
}
.mc-note-f i{font-style:normal;opacity:.62;}
.mc-note-f textarea{
  width:100%;flex:1;resize:none;min-height:62px;
  padding:11px 13px;border-radius:11px;
  background:var(--a-sunk);color:var(--a-ink);
  box-shadow:inset 0 0 0 1px var(--a-line);
  font:inherit;font-size:13px;line-height:1.5;
}
/* the field already looks like a field — a ring inside it is noise */
.mc-note-f textarea:focus{outline:none;box-shadow:inset 0 0 0 1.5px var(--a-mute);}
.mc-note-f textarea::placeholder{color:var(--a-mute);}

.mc-submit{
  display:flex;flex-direction:column;justify-content:center;gap:8px;
  padding:13px 15px 15px;
  border-left:1px solid var(--a-line);
}

/* ── popovers ── */
/* The panel has to sit above the Generate button, which comes later in
   the document and would otherwise paint over it. Its own surface is
   raised a step from the card so the two edges do not merge, and it is
   opaque — a translucent panel over a button reads as a rendering fault,
   not as depth. */
.mc-pop{
  position:absolute;left:0;top:calc(100% + 7px);z-index:90;
  width:max(280px,100%);padding:6px;
  border-radius:16px;
  background:var(--a-nav,var(--a-panel));
  box-shadow:
    inset 0 0 0 1px var(--a-line),
    0 2px 6px rgba(0,0,0,.18),
    0 30px 60px -22px rgba(0,0,0,.6);
  max-height:min(420px,58vh);overflow-y:auto;
}
/* the engine list is wider than its row, and hangs left so it cannot
   run off the right edge of the card */
.mc-pop[data-mc-pop="model"]{width:min(470px,92vw);}
.mc-pop-sm{width:max(230px,100%);}
/* flipped above its button when there is no room below it */
.mc-pop.is-up{top:auto;bottom:calc(100% + 7px);}
.mc-pop-head{
  padding:9px 10px 6px;
  font-size:9.5px;font-weight:700;letter-spacing:.11em;text-transform:uppercase;
  color:var(--a-mute);
}
.mc-mrow{
  display:flex;align-items:flex-start;gap:11px;width:100%;
  padding:10px;border-radius:12px;cursor:pointer;text-align:left;
  transition:background-color .18s var(--e-out);
}
.mc-mrow:hover{background:var(--a-chip);}
.mc-mrow.is-on{background:var(--a-chip-2);}
.mc-mrow-mark{
  flex:0 0 auto;display:grid;place-items:center;
  width:30px;height:30px;border-radius:9px;
  font-size:13px;font-weight:700;color:#fff;background:#333;
}
.mc-mrow-main{display:flex;flex-direction:column;gap:2px;min-width:0;}
.mc-mrow-name{font-size:13.5px;font-weight:600;color:var(--a-ink);
  display:flex;align-items:center;gap:7px;}
.mc-mrow-name em{
  font-style:normal;font-size:9px;font-weight:700;letter-spacing:.08em;
  text-transform:uppercase;padding:2px 6px;border-radius:100px;
  background:var(--vz-acc);color:var(--vz-acc-ink);
}
.mc-mrow-note{font-size:12px;line-height:1.45;color:var(--a-mute);}
.mc-mrow-spec{font-size:10.5px;color:var(--a-mute);opacity:.8;padding-top:2px;}

.mc-orow{
  display:flex;flex-direction:column;gap:1px;width:100%;
  padding:10px 12px;border-radius:11px;cursor:pointer;text-align:left;
  font-size:13.5px;color:var(--a-ink);
  transition:background-color .18s var(--e-out);
}
.mc-orow:hover{background:var(--a-chip);}
.mc-orow.is-on{background:var(--a-chip-2);font-weight:600;}
.mc-orow span{font-size:11.5px;color:var(--a-mute);font-weight:400;}
/* The panel sits on a darker surface than the card it hangs off, so the
   muted tone has to lift with it — on the panel it measured 4.48:1,
   two hundredths under. Raised only where that surface applies. */
[data-app="dark"] .mc-pop{--a-mute:#a8a8a8;}

/* ── submit ── */
.mc-go{
  display:flex;align-items:center;justify-content:center;gap:10px;
  width:100%;padding:14px 18px;border-radius:12px;cursor:pointer;
  font-size:14.5px;font-weight:650;letter-spacing:-.01em;line-height:1.25;
  background:var(--a-btn);color:var(--a-btn-ink);
  transition:transform .24s var(--e-out),opacity .24s var(--e-out);
}
.mc-go:hover{transform:translateY(-1px);}
.mc-go:active{transform:translateY(0);}
/* still missing an input: it stays pressable and says what is needed,
   rather than going grey and explaining nothing */
.mc-go.is-waiting{opacity:.55;}
.mc-go.is-waiting .mc-go-c{display:none;}
.mc-go-c{
  display:inline-flex;align-items:center;gap:5px;flex:0 0 auto;
  padding:3px 9px;border-radius:100px;
  background:rgba(127,127,127,.28);
  font-size:13px;font-variant-numeric:tabular-nums;
}
.mc-go-c svg{width:12px;height:12px;}
.mc-legal{margin:0;font-size:10.5px;line-height:1.45;color:var(--a-mute);text-align:center;}

/* ── samples ── */

@media (max-width:1000px){
  .mc-strip{grid-template-columns:repeat(3,1fr);}
  .mc-sample:nth-child(n+4){display:none;}
}
@media (max-width:820px){
  /* stacked: the arrow turns a quarter so it still points from the
     source to the target rather than off the side of the screen */
  .mc-bar{grid-template-columns:1fr 1fr;}
  .mc-seg-engine{grid-column:1 / -1;}
  .mc-seg:nth-child(2){border-left:0;}
  .mc-seg:nth-child(n+2){border-top:1px solid var(--a-line);}
  .mc-foot{grid-template-columns:1fr;}
  .mc-submit{border-left:0;border-top:1px solid var(--a-line);}
  .mc-flow{grid-template-columns:1fr;grid-template-rows:auto 74px auto;}
  .mc-arrow{flex-direction:row;gap:12px;}
  .mc-arrow svg{transform:rotate(90deg);width:36px;}
  .mc-slot{aspect-ratio:16/10;}
  .mc-grid{grid-template-columns:1fr;}
  .mc-row-note{display:none;}
}

/* ═══════════════════════════════════════════
   CAMPAIGN STUDIO
   ═══════════════════════════════════════════ */
.cs-main{padding:0 0 90px;}
.cs-hero{padding:34px 0 60px;text-align:center;}

/* ── the deck ──
   Six cards fanned from the centre. The rotation and offset come from
   --i, the card's distance from the middle, so the arrangement is one
   formula rather than six hand-tuned rules. An even count has no whole
   middle, so --i runs in halves (±0.5, ±1.5, ±2.5) and the z-index
   formula doubles to land back on integers. */
.cs-deck{
  display:flex;align-items:center;justify-content:center;
  margin-bottom:34px;perspective:1400px;
}
.cs-card{
  position:relative;display:block;flex:0 0 auto;
  width:clamp(132px,15vw,208px);aspect-ratio:4/5;
  margin:0 -22px;border-radius:14px;
  z-index:calc(6 - 2 * max(var(--i), -1 * var(--i)));
  overflow:hidden;
  transform:
    rotate(calc(var(--i) * 5deg))
    translateY(calc(max(var(--i), -1 * var(--i)) * 13px))
    scale(calc(1 - max(var(--i), -1 * var(--i)) * 0.05));
  box-shadow:
    0 0 0 1px var(--a-line),
    0 3px 8px rgba(0,0,0,.28),
    0 26px 50px -22px rgba(0,0,0,.62);
  transition:transform .5s var(--e-out),box-shadow .5s var(--e-out);
}
.cs-card img{width:100%;height:100%;object-fit:cover;display:block;}
/* the hovered card leaves the fan rather than the fan opening around it */
.cs-card:hover,.cs-card:focus-visible{
  transform:rotate(0deg) translateY(-14px) scale(1.06);
  z-index:9;
  box-shadow:0 0 0 1px var(--a-line),0 6px 14px rgba(0,0,0,.3),0 40px 70px -26px rgba(0,0,0,.75);
}
.cs-card-tag{
  position:absolute;left:8px;bottom:8px;
  padding:4px 9px;border-radius:100px;
  font-size:9.5px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;
  color:#fff;background:rgba(0,0,0,.62);
  backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);
}

/* ── headline ── */
.cs-h1{
  margin:0 0 30px;
  font-size:clamp(26px,3.9vw,46px);line-height:1.08;
  font-weight:600;letter-spacing:-.035em;text-transform:uppercase;
  color:var(--a-ink);
}
.cs-h1 span{display:block;}
.cs-h1 b{display:block;font-weight:600;color:var(--a-mute);}

/* ── start bar ── */
.cs-start{max-width:820px;margin:0 auto;}
.cs-kindsw{
  display:inline-flex;gap:3px;padding:3px;margin-bottom:12px;
  border-radius:11px;background:var(--a-chip);
}
.cs-kindsw button{
  display:inline-flex;align-items:center;gap:6px;
  padding:7px 15px;border-radius:8px;cursor:pointer;
  font-size:12.5px;font-weight:600;color:var(--a-mute);
  transition:background-color .2s var(--e-out),color .2s var(--e-out);
}
.cs-kindsw button svg{width:14px;height:14px;}
.cs-kindsw button:hover{color:var(--a-ink);}
.cs-kindsw button.is-on{background:var(--a-panel);color:var(--a-ink);}

.cs-bar{
  display:flex;align-items:center;gap:12px;
  padding:9px 9px 9px 18px;border-radius:15px;
  background:var(--a-panel);
  box-shadow:inset 0 0 0 1px var(--a-line),0 20px 44px -30px rgba(0,0,0,.6);
}
.cs-bar input{
  flex:1;min-width:0;background:none;border:0;padding:11px 0;
  font:inherit;font-size:14.5px;color:var(--a-ink);
}
/* the field is plainly a field and the bar already frames it */
.cs-bar input:focus{outline:none;}
.cs-bar input::placeholder{color:var(--a-mute);}
.cs-bar-r{display:flex;align-items:center;gap:10px;flex:0 0 auto;}
.cs-pick{
  padding:5px 11px;border-radius:100px;
  font-size:11px;font-weight:600;letter-spacing:.04em;
  color:var(--a-mute);background:var(--a-chip);
  white-space:nowrap;
}
.cs-go{
  display:inline-flex;align-items:center;gap:8px;
  padding:12px 18px;border-radius:11px;cursor:pointer;
  font-size:13.5px;font-weight:650;
  background:var(--a-btn);color:var(--a-btn-ink);
  transition:transform .22s var(--e-out);
}
.cs-go b{font-weight:650;}
.cs-go svg{width:14px;height:14px;}
.cs-go:hover{transform:translateY(-1px);}
.cs-note{margin:11px 0 0;font-size:11.5px;color:var(--a-mute);}

/* ── templates ── */
.cs-tpl{padding-top:8px;}
.cs-tpl-h{display:flex;align-items:baseline;justify-content:space-between;gap:16px;margin-bottom:14px;}
.cs-tpl-h h2{
  margin:0;font-size:15px;font-weight:700;letter-spacing:.09em;text-transform:uppercase;
  color:var(--a-ink);
}
.cs-tpl-all{
  display:inline-flex;align-items:center;gap:6px;flex:0 0 auto;
  font-size:12.5px;font-weight:600;color:var(--a-mute);
  transition:color .2s var(--e-out);
}
.cs-tpl-all svg{width:13px;height:13px;}
.cs-tpl-all:hover{color:var(--a-ink);}

/* ── one row per section ──
   The filter chips and the single grid are gone. Twelve tiles taken off
   the front of a list ordered by product meant twelve mascara shots, so
   the page advertised one product instead of a library. A row each, six
   wide, shows the range in the same space. */
.cs-row{margin-bottom:30px;}
.cs-row:last-child{margin-bottom:0;}
.cs-row-h{
  display:flex;align-items:baseline;justify-content:space-between;gap:16px;
  margin-bottom:10px;
}
.cs-row-h h3{
  margin:0;font-size:14px;font-weight:650;letter-spacing:-.01em;color:var(--a-ink);
}
.cs-row-h a{
  display:inline-flex;align-items:center;gap:6px;flex:0 0 auto;
  font-size:12px;color:var(--a-mute);
  transition:color .2s var(--e-out);
}
.cs-row-h a svg{width:12px;height:12px;}
.cs-row-h a:hover{color:var(--a-ink);}
.cs-row-g{display:grid;grid-template-columns:repeat(6,1fr);gap:10px;}

.cs-t{
  position:relative;display:block;border-radius:14px;overflow:hidden;
  aspect-ratio:3/4;background:var(--a-sunk);
  box-shadow:inset 0 0 0 1px var(--a-line);
}
.cs-t img{
  width:100%;height:100%;object-fit:cover;display:block;
  transition:transform 1s var(--e-out);
}
.cs-t:hover img{transform:scale(1.05);}
.cs-empty{padding:34px;text-align:center;font-size:13px;color:var(--a-mute);}

@media (max-width:1100px){
  .cs-row-g{grid-template-columns:repeat(4,1fr);}
  .cs-row-g .cs-t:nth-child(n+5){display:none;}

}
@media (max-width:820px){
  .cs-row-g{grid-template-columns:repeat(3,1fr);}
  .cs-row-g .cs-t:nth-child(n+4){display:none;}
  .cs-bar{flex-wrap:wrap;padding:12px;}
  .cs-bar input{flex:1 0 100%;padding:4px 4px 10px;}
  .cs-bar-r{width:100%;justify-content:space-between;}
  /* the fan is too tight for six at this width — the outer pair goes */
  .cs-card[style*="--i:-2.5"],.cs-card[style*="--i:2.5"]{display:none;}
}
@media (max-width:560px){
  .cs-row-g{grid-template-columns:repeat(2,1fr);}
  .cs-row-g .cs-t:nth-child(n+3){display:none;}
  .cs-card{margin:0 -14px;}
}

/* ═══ REMOVE BACKGROUND — bigger stage, tools on the picture ═══ */

/* The stage was 440px tall, which left the picture small with wide empty
   bands either side of it. It now takes what the window can give. */
/* A definite height, not a minimum. As a minimum the picture pushed
   the panel taller, which let the picture grow, which pushed the
   panel again — a 896x1200 upload ended up on a 1231px stage. With
   a fixed box the image caps against it instead. */
.ut-stage{height:min(74vh,760px);min-height:0;}
.ut-result{padding:12px 12px 44px;}   /* the toolbar floats over the last few px */

/* ── the toolbar ──
   Floats under the picture, over the stage, so the controls you reach for
   while inspecting an edge are next to the edge rather than across the
   page in a side panel. */
.ut-tools{
  position:absolute;left:50%;bottom:10px;transform:translateX(-50%);
  z-index:20;display:flex;align-items:center;gap:4px;
  padding:6px;border-radius:14px;
  /* Fixed dark, not a theme token: this bar floats over the picture
     like a player control, so it has to read against a photograph
     rather than against the page. Bound to --a-nav it turned white
     in the light theme and took its own labels with it. */
  background:rgba(18,18,18,.94);
  backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);
  box-shadow:
    inset 0 0 0 1px rgba(255,255,255,.09),
    0 2px 6px rgba(0,0,0,.2),
    0 22px 44px -20px rgba(0,0,0,.7);
}
.ut-tools[hidden]{display:none;}
.ut-tool{
  display:grid;place-items:center;
  width:34px;height:34px;border-radius:9px;cursor:pointer;
  color:rgba(255,255,255,.72);background:none;
  transition:background-color .18s var(--e-out),color .18s var(--e-out);
}
.ut-tool svg{width:17px;height:17px;}
.ut-tool:hover{background:rgba(255,255,255,.1);color:#fff;}
.ut-tool.is-on,.ut-tool[aria-pressed="true"]{background:#fff;color:#111;}
.ut-tool:disabled{opacity:.32;cursor:default;}
.ut-tool:disabled:hover{background:none;color:rgba(255,255,255,.72);}

.ut-tools-brush{display:flex;align-items:center;gap:4px;}
.ut-tools-brush[hidden]{display:none;}
.ut-tools-size,.ut-tools-zoom{
  padding:0 8px;font-size:11.5px;font-variant-numeric:tabular-nums;
  color:rgba(255,255,255,.66);white-space:nowrap;
}
.ut-tools-size b,.ut-tools-zoom{font-weight:600;color:#fff;}
.ut-tools-div{width:1px;height:20px;background:rgba(255,255,255,.14);margin:0 2px;}

/* ── the picture ──
   Zoom is a scale on the wrapper, so the canvas bitmap is untouched and
   the brush keeps mapping pointer position to image pixels correctly. */
.ut-canvas-w{
  transition:transform .38s var(--e-out);
  transform-origin:center center;
}
.ut-canvas-w.is-zoomed{transform:translate(var(--px,0px),var(--py,0px)) scale(var(--z,2));}
/* The eased transform is right for the zoom itself and wrong for a drag:
   every pointer move would arrive .38s late. */
.ut-canvas-w.is-panning{transition:none;}

/* Only a brush turns the pointer into a brush. Off, the picture is
   something you look at and click to zoom. */
.ut-canvas-w canvas{cursor:zoom-in;}
.ut-result.is-brushing .ut-canvas-w canvas{cursor:none;}
.ut-result.is-zoomed .ut-canvas-w canvas{cursor:grab;}
.ut-canvas-w.is-panning canvas{cursor:grabbing;}

/* the ring only exists while the brush is on */
.ut-brushdot{
  transition:width .12s var(--e-out),height .12s var(--e-out);
}

/* ═══ REMOVE BACKGROUND — the colour picker ═══
   Behind "Other". A saturation/brightness square over a hue strip is
   every colour there is, which is what a shortlist of four presets was
   not. The two sweeps live in here as well, because they are backgrounds
   in exactly the way a flat colour is. */
.ut-bgopt-chev{width:14px;height:14px;margin-left:auto;opacity:.6;}

.ut-colour{
  margin-top:10px;padding:12px;border-radius:14px;
  background:var(--a-sunk,#f4f4f4);
  box-shadow:inset 0 0 0 1px var(--a-line,rgba(0,0,0,.1));
}
.ut-colour[hidden]{display:none;}

/* the square: white → hue left to right, transparent → black top to
   bottom, which is the standard construction and needs no canvas */
.ut-sv{
  position:relative;height:132px;border-radius:10px;cursor:crosshair;
  background:
    linear-gradient(to top, #000, rgba(0,0,0,0)),
    linear-gradient(to right, #fff, hsl(var(--hue,0) 100% 50%));
  touch-action:none;
}
.ut-sv-dot,.ut-hue-dot{
  position:absolute;width:14px;height:14px;border-radius:50%;
  transform:translate(-50%,-50%);pointer-events:none;
  border:2px solid #fff;
  box-shadow:0 0 0 1px rgba(0,0,0,.35),0 1px 3px rgba(0,0,0,.4);
}
.ut-hue-dot{top:50%;}

.ut-hue{
  position:relative;height:14px;margin-top:10px;border-radius:100px;
  cursor:pointer;touch-action:none;
  background:linear-gradient(to right,
    #f00 0%,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,#f00 100%);
}

.ut-hexrow{display:flex;align-items:center;gap:9px;margin-top:11px;}
.ut-hexpv{
  width:28px;height:28px;border-radius:8px;flex:0 0 auto;
  box-shadow:inset 0 0 0 1px rgba(0,0,0,.18);
}
.ut-hexrow input{
  flex:1;min-width:0;padding:8px 11px;border-radius:9px;
  font:inherit;font-size:13px;font-variant-numeric:tabular-nums;
  letter-spacing:.04em;text-transform:uppercase;
  color:var(--a-ink,#121212);background:var(--a-panel,#fff);
  box-shadow:inset 0 0 0 1px var(--a-line,rgba(0,0,0,.1));
}
/* the field is plainly a field and the row already frames it */
.ut-hexrow input:focus{outline:none;box-shadow:inset 0 0 0 1.5px var(--a-mute,#6b6b6b);}

.ut-swatches{display:flex;flex-wrap:wrap;gap:6px;margin-top:11px;}
.ut-chip{
  width:24px;height:24px;border-radius:7px;cursor:pointer;
  box-shadow:inset 0 0 0 1px rgba(0,0,0,.16);
  transition:transform .16s var(--e-out);
}
.ut-chip:hover{transform:scale(1.1);}

.ut-presetrow{display:grid;grid-template-columns:1fr 1fr;gap:7px;margin-top:11px;}
.ut-preset{
  display:flex;align-items:center;gap:8px;
  padding:8px 10px;border-radius:10px;cursor:pointer;
  font-size:12px;font-weight:500;text-align:left;
  color:var(--a-ink,#121212);background:var(--a-panel,#fff);
  box-shadow:inset 0 0 0 1px var(--a-line,rgba(0,0,0,.1));
  transition:box-shadow .18s var(--e-out);
}
.ut-preset span{
  width:18px;height:18px;border-radius:5px;flex:0 0 auto;
  box-shadow:inset 0 0 0 1px rgba(0,0,0,.14);
}
.ut-preset:hover{box-shadow:inset 0 0 0 1.5px var(--a-mute,#6b6b6b);}
.ut-preset.is-on{box-shadow:inset 0 0 0 2px var(--a-ink,#121212);}

/* ═══ ACCOUNT MENU — credits ═══
   Two readings of one number. The ring around the avatar is the ambient
   one, there every time the menu opens; the block below is the precise
   one, with the figure itself doing the talking instead of fourteen
   dashes that had to be counted. */

/* ── the ring ── */
.acc-face-w{
  position:relative;flex:0 0 auto;
  width:48px;height:48px;display:grid;place-items:center;
}
.acc-ring{
  position:absolute;inset:0;width:100%;height:100%;
  transform:rotate(-90deg);          /* start the arc at twelve o'clock */
  overflow:visible;
}
.acc-ring circle{fill:none;stroke-width:2.5;stroke-linecap:round;}
.acc-ring-t{stroke:var(--a-chip-2,rgba(255,255,255,.14));}
/* pathLength=100 makes the dash array a straight percentage, so the arc
   is set from the credit figure without knowing the circumference */
.acc-ring-f{
  stroke:var(--vz-acc,#fff);
  transition:stroke-dasharray .6s var(--e-out);
}
.acc-face-w.is-low .acc-ring-f{stroke-dasharray:2 4 !important;opacity:.85;}

.acc-face-w .acc-face{
  width:38px;height:38px;
}

/* ── the block ── */
.acc-credits{
  display:block;padding:13px 14px;border-radius:14px;
  background:var(--a-chip,rgba(255,255,255,.06));
  transition:background-color .2s var(--e-out);
}
.acc-credits:hover{background:var(--a-chip-2,rgba(255,255,255,.12));}
.acc-credits-h{
  display:flex;align-items:center;justify-content:space-between;
  font-size:9.5px;font-weight:700;letter-spacing:.13em;text-transform:uppercase;
  color:var(--a-mute,#9a9a9a);
}
.acc-credits-h svg{width:12px;height:12px;}

/* the figure leads: it is the thing being asked about */
.acc-credits-fig{
  display:flex;align-items:baseline;gap:7px;padding:6px 0 9px;
}
.acc-credits-fig b{
  font-size:30px;font-weight:600;letter-spacing:-.04em;line-height:1;
  font-variant-numeric:tabular-nums;
  color:var(--a-ink,#fff);
}
.acc-credits-fig em{
  font-style:normal;font-size:12px;font-variant-numeric:tabular-nums;
  color:var(--a-mute,#9a9a9a);
}

/* one continuous track, not a row of segments to count */
.acc-track{
  display:block;height:5px;border-radius:100px;overflow:hidden;
  background:var(--a-chip-2,rgba(255,255,255,.14));
}
.acc-track i{
  display:block;height:100%;border-radius:100px;
  background:var(--vz-acc,#fff);
  transition:width .6s var(--e-out);
}
/* low: the bar goes striped, because there is no red in this palette to
   reach for and a shorter bar alone is easy to miss */
.acc-credits.is-low .acc-track i{
  background:repeating-linear-gradient(115deg,
    var(--vz-acc,#fff) 0 4px, transparent 4px 8px);
}
.acc-credits-note{
  display:block;padding-top:8px;
  font-size:11px;line-height:1.4;color:var(--a-mute,#9a9a9a);
}

/* ── the same ring on the nav avatar ──
   Drawn with a conic gradient and masked to a ring, so no page markup
   has to change to carry it — account.js only sets --credit. */
.app-avatar{position:relative;}
.app-avatar::after{
  content:"";position:absolute;inset:-4px;border-radius:50%;
  pointer-events:none;
  background:conic-gradient(var(--vz-acc,#fff) calc(var(--credit,1) * 360deg),
                            var(--a-chip-2,rgba(255,255,255,.16)) 0);
  -webkit-mask:radial-gradient(farthest-side,transparent calc(100% - 2px),#000 calc(100% - 2px));
  mask:radial-gradient(farthest-side,transparent calc(100% - 2px),#000 calc(100% - 2px));
  transition:background .6s var(--e-out);
}
.app-avatar.is-low::after{opacity:.9;}


/* ═══ VIDEO TOOL TABS ═══
   Create, Edit and Motion Control are three jobs of equal standing. A rule
   under the live label rather than a row of boxes: the boxes would compete
   with the composer's own controls sitting six pixels below them. */
.vt{
  display:flex;align-items:center;gap:2px;
  margin:0 0 14px;
  border-bottom:1px solid var(--a-line);
}
.vt.is-wide{margin-bottom:18px;}
.vt a{
  position:relative;padding:8px 12px 10px;
  font-size:13px;font-weight:600;letter-spacing:-.01em;
  color:var(--a-mute);text-decoration:none;white-space:nowrap;
  transition:color .2s var(--e-out);
}
.vt a:hover{color:var(--a-ink);}
.vt a.is-on{color:var(--a-ink);}
.vt a::after{
  content:"";position:absolute;left:12px;right:12px;bottom:-1px;height:2px;
  border-radius:2px;background:var(--vz-acc);
  transform:scaleX(0);
  transition:transform .28s var(--e-out);
}
.vt a.is-on::after{transform:scaleX(1);}

/* ═══ EDIT VIDEO ═══ */

/* ── the two wells ──
   The clip is the lead: without it there is nothing to edit, so it is the
   taller of the two and Generate stays held back until it is filled. */
.vge-drop{
  display:block;position:relative;
  border-radius:14px;cursor:pointer;overflow:hidden;
  background:var(--a-sunk);
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:box-shadow .22s var(--e-out),background-color .22s var(--e-out);
}
.vge-drop:hover{box-shadow:inset 0 0 0 1px var(--a-mute);}
.vge-drop.is-over{box-shadow:inset 0 0 0 1.5px var(--vz-acc);}
.vge-drop.is-off{opacity:.5;pointer-events:none;}
.vge-drop-empty{
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:7px;padding:22px 16px;text-align:center;
}
.vge-drop.is-lead .vge-drop-empty{padding:34px 16px;}
.vge-drop-empty b{font-size:14px;font-weight:600;color:var(--a-ink);}
.vge-drop-empty em{font-style:normal;font-size:12px;color:var(--a-mute);}
.vge-drop-ic{
  display:grid;place-items:center;
  width:44px;height:44px;border-radius:50%;margin-bottom:2px;
  background:var(--a-chip);color:var(--a-ink);
}
.vge-drop-ic svg{width:21px;height:21px;}
/* two rings, slightly overlapped — one for pictures, one for sound */
.vge-drop-ic.is-pair{
  width:auto;height:auto;background:none;border-radius:0;
  display:flex;gap:0;
}
.vge-drop-ic.is-pair i{
  display:grid;place-items:center;
  width:40px;height:40px;border-radius:50%;
  background:var(--a-chip);color:var(--a-ink);
  box-shadow:0 0 0 3px var(--a-panel);
}
.vge-drop-ic.is-pair i + i{margin-left:-11px;}
.vge-drop-ic.is-pair svg{width:18px;height:18px;}

.vge-drop-full{display:block;position:relative;}
.vge-drop-full video{
  display:block;width:100%;max-height:210px;
  object-fit:cover;background:#000;
}
.vge-drop-meta{
  display:flex;align-items:baseline;gap:8px;
  padding:9px 12px;
}
.vge-drop-meta b{
  font-size:12.5px;font-weight:600;color:var(--a-ink);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.vge-drop-meta em{
  font-style:normal;font-size:11px;color:var(--a-mute);
  font-variant-numeric:tabular-nums;flex:0 0 auto;margin-left:auto;
}
.vge-drop-x{
  position:absolute;top:8px;right:8px;
  width:24px;height:24px;border-radius:50%;
  display:grid;place-items:center;
  font-size:11px;line-height:1;cursor:pointer;
  color:#fff;background:rgba(8,7,6,.66);
  backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);
}
.vge-drop-x:hover{background:rgba(8,7,6,.85);}

/* an audio element has no thumbnail, so its tile carries the glyph */
.vge-tile-audio{
  display:grid;place-items:center;width:100%;height:100%;
  background:var(--a-chip);color:var(--a-mute);
}
.vge-tile-audio svg{width:20px;height:20px;}

/* ── resolution and bitrate, the only two settings here ── */
.vge-pair{display:grid;grid-template-columns:auto 1fr;gap:8px;align-items:stretch;}
.vge-pair .vg-tri{margin:0;}

/* the prompt field can be given more room without a modal */
.vg-prompt.is-tall textarea{min-height:200px;}

/* Generate before a clip is in: still pressable, because pressing it is how
   you find out what it wants — it says so rather than going dead. */
.vg-create.is-waiting{opacity:.62;}

/* The Create page draws its stage to the aspect you picked. There is no
   aspect to pick here, so the frame carries the shape of the clip you
   handed over — 16:9 until there is one. */
.vge-stage .vg-stage-frame{
  width:100%;height:auto;
  max-width:100%;max-height:100%;
  aspect-ratio:var(--ar, 16 / 9);
}
.vge-stage .vg-stage-frame video{
  width:100%;height:100%;object-fit:contain;
  display:block;background:#000;
}

/* An engine on the Edit shelf that is not an editor: the card carries an
   arrow instead of a tick, and says Create, so the jump is not a surprise. */
/* outlined rather than filled: it has to clear 4.5:1 at 8.5px, and it
   should not read as the same kind of badge as New or Fast */
.vg-tag.is-out{
  background:transparent;color:var(--a-ink);
  box-shadow:inset 0 0 0 1px var(--a-line);
}
.vg-card-out{
  flex:0 0 auto;width:20px;height:20px;border-radius:50%;
  display:flex;align-items:center;justify-content:center;
  background:var(--a-chip);color:var(--a-mute);
}
.vg-card-out svg{width:11px;height:11px;}
.vg-card.is-out:hover .vg-card-out{background:var(--a-chip-2);color:var(--a-ink);}


/* ═══════════════════════════════════════════
   UGC PRODUCT AD

   Three questions down the left, the brief being written up on the right.
   The steps are an accordion rather than a wizard: answering one does not
   hide the others, so you can go back and change the product without
   losing the script you already wrote.
   ═══════════════════════════════════════════ */
.ua-main{padding:24px 0 90px;color:var(--a-ink);}

/* ── the opening ── */
.ua-head{
  display:flex;align-items:center;justify-content:space-between;gap:32px;
  padding:14px 0 30px;
}
.ua-eyebrow{
  display:block;margin-bottom:12px;
  font-size:10px;font-weight:700;letter-spacing:.16em;text-transform:uppercase;
  color:var(--a-mute);
}
.ua-h1{
  margin:0 0 12px;font-size:clamp(26px,3.5vw,40px);line-height:1.08;
  font-weight:600;letter-spacing:-.035em;color:var(--a-ink);
}
.ua-sub{margin:0;max-width:56ch;font-size:14.5px;line-height:1.55;color:var(--a-mute);}
/* three frames splayed like prints, so the page opens on the thing it makes */
.ua-head-art{display:flex;flex:0 0 auto;perspective:800px;}
.ua-head-art span{
  display:block;width:clamp(72px,8vw,104px);aspect-ratio:3/4;
  margin:0 -10px;border-radius:12px;overflow:hidden;
  transform:rotate(var(--r,0deg));
  box-shadow:0 0 0 1px var(--a-line),0 20px 40px -20px rgba(0,0,0,.6);
}
.ua-head-art img{width:100%;height:100%;object-fit:cover;display:block;}
@media (max-width:900px){.ua-head-art{display:none;}}

.ua-shell{
  display:grid;gap:20px;
  grid-template-columns:minmax(0,1fr) minmax(0,340px);
  align-items:start;
}
@media (max-width:1000px){.ua-shell{grid-template-columns:1fr;}}

/* ── a step ── */
.ua-steps{display:flex;flex-direction:column;gap:12px;min-width:0;}
.ua-step{
  border-radius:16px;overflow:hidden;
  background:var(--a-panel);
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:box-shadow .25s var(--e-out);
}
.ua-step.is-open{box-shadow:inset 0 0 0 1px var(--a-mute),var(--a-shadow);}
.ua-step-h{
  display:flex;align-items:center;gap:13px;width:100%;
  padding:16px 18px;cursor:pointer;text-align:left;
}
.ua-step-n{
  flex:0 0 auto;width:26px;height:26px;border-radius:50%;
  display:grid;place-items:center;
  font-size:12px;font-weight:700;font-variant-numeric:tabular-nums;
  background:var(--a-chip);color:var(--a-mute);
  transition:background-color .25s var(--e-out),color .25s var(--e-out);
}
.ua-step.is-open .ua-step-n{background:var(--vz-acc);color:var(--vz-acc-ink);}
/* a finished step keeps its number but stops asking for attention */
.ua-step.is-done:not(.is-open) .ua-step-n{background:var(--a-chip-2);color:var(--a-ink);}
.ua-step-t{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px;}
.ua-step-t b{font-size:15px;font-weight:600;letter-spacing:-.01em;color:var(--a-ink);}
.ua-step-t em{
  font-style:normal;font-size:12.5px;color:var(--a-mute);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.ua-step.is-done:not(.is-open) .ua-step-t em{color:var(--a-ink);}
.ua-step-chev{
  flex:0 0 auto;width:15px;height:15px;color:var(--a-mute);
  transition:transform .3s var(--e-out);
}
.ua-step.is-open .ua-step-chev{transform:rotate(180deg);}
.ua-step-b{display:none;padding:2px 18px 18px;}
.ua-step.is-open .ua-step-b{display:block;}
.ua-step-foot{display:flex;justify-content:flex-end;padding-top:16px;}
.ua-next{
  padding:9px 20px;border-radius:100px;cursor:pointer;
  font-family:inherit;font-size:13px;font-weight:600;
  background:var(--a-btn);color:var(--a-btn-ink);
  transition:transform .2s var(--e-out);
}
.ua-next:hover{transform:translateY(-1px);}

/* ── segmented control ── */
.ua-seg{
  display:inline-flex;gap:3px;margin-bottom:16px;
  padding:3px;border-radius:100px;background:var(--a-sunk);
  box-shadow:inset 0 0 0 1px var(--a-line);
}
.ua-seg button{
  padding:7px 15px;border-radius:100px;cursor:pointer;
  font-family:inherit;font-size:12.5px;font-weight:600;
  color:var(--a-mute);background:transparent;
  transition:background-color .2s var(--e-out),color .2s var(--e-out);
}
.ua-seg button:hover{color:var(--a-ink);}
.ua-seg button.is-on{background:var(--a-panel);color:var(--a-ink);}

.ua-lbl{
  margin:0 0 9px;font-size:10px;font-weight:700;
  letter-spacing:.14em;text-transform:uppercase;color:var(--a-mute);
}
.ua-note{margin:10px 0 0;font-size:12px;line-height:1.5;color:var(--a-mute);}

/* ── the link row ── */
.ua-linkrow{
  display:flex;align-items:center;gap:10px;
  padding:8px 8px 8px 14px;border-radius:12px;
  background:var(--a-sunk);box-shadow:inset 0 0 0 1px var(--a-line);
  color:var(--a-mute);
}
.ua-linkrow svg{width:17px;height:17px;flex:0 0 auto;}
.ua-linkrow input{
  flex:1;min-width:0;border:0;background:transparent;
  font-family:inherit;font-size:13.5px;color:var(--a-ink);
}
.ua-linkrow input:focus{outline:none;}
.ua-read{
  flex:0 0 auto;padding:8px 16px;border-radius:9px;cursor:pointer;
  font-family:inherit;font-size:12.5px;font-weight:600;
  background:var(--a-btn);color:var(--a-btn-ink);
}

/* what the address gave up, editable because it is a guess */
.ua-found{
  margin-top:14px;padding:14px;border-radius:12px;
  background:var(--a-sunk);box-shadow:inset 0 0 0 1px var(--a-line);
}
.ua-found-h{
  display:flex;align-items:center;gap:7px;margin-bottom:12px;
  font-size:10px;font-weight:700;letter-spacing:.13em;text-transform:uppercase;
  color:var(--a-ink);
}
.ua-found-h svg{width:13px;height:13px;}
.ua-found-grid{display:grid;grid-template-columns:1.4fr 1fr 1fr;gap:10px;}
@media (max-width:700px){.ua-found-grid{grid-template-columns:1fr;}}
.ua-field{display:flex;flex-direction:column;gap:5px;min-width:0;}
.ua-field span{font-size:10.5px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--a-mute);}
.ua-field input,.ua-field select{
  width:100%;padding:9px 11px;border-radius:9px;
  border:0;box-shadow:inset 0 0 0 1px var(--a-line);
  background:var(--a-panel);color:var(--a-ink);
  font-family:inherit;font-size:13px;
}
.ua-field input:focus,.ua-field select:focus{outline:none;box-shadow:inset 0 0 0 1.5px var(--vz-acc);}

/* ── the product photos ── */
.ua-shots{display:grid;grid-template-columns:1.35fr 1fr 1fr;gap:10px;}
@media (max-width:640px){.ua-shots{grid-template-columns:1fr 1fr;}}
.ua-shot{
  position:relative;display:block;aspect-ratio:1;
  border-radius:13px;overflow:hidden;cursor:pointer;
  background:var(--a-sunk);
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:box-shadow .22s var(--e-out);
}
.ua-shot:hover{box-shadow:inset 0 0 0 1px var(--a-mute);}
.ua-shot.is-over{box-shadow:inset 0 0 0 1.5px var(--vz-acc);}
.ua-shot-empty{
  position:absolute;inset:0;
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:6px;
  padding:14px;text-align:center;color:var(--a-mute);
}
.ua-shot-empty svg{width:24px;height:24px;margin-bottom:2px;}
.ua-shot.is-lead .ua-shot-empty svg{width:30px;height:30px;}
.ua-shot-empty b{font-size:12.5px;font-weight:600;color:var(--a-ink);}
.ua-shot-empty em{font-style:normal;font-size:11px;}
.ua-shot-full{position:absolute;inset:0;display:block;}
.ua-shot-full img{width:100%;height:100%;object-fit:cover;display:block;}
.ua-shot-x{
  position:absolute;top:7px;right:7px;width:23px;height:23px;border-radius:50%;
  display:grid;place-items:center;font-size:11px;line-height:1;cursor:pointer;
  color:#fff;background:rgba(8,7,6,.66);
  backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);
}
.ua-shot-x:hover{background:rgba(8,7,6,.86);}

/* ── the cast ── */
.ua-cast{
  display:grid;gap:9px;
  grid-template-columns:repeat(auto-fill,minmax(min(104px,100%),1fr));
  max-height:326px;overflow-y:auto;
  /* Room for a chosen card to move outside its own box. It lifts 3px and
     its ring arrives 7% oversized, and this is a scroll container — one
     axis set to auto forces the other, so nothing can spill. Without the
     padding the top row came out shaved along its top edge, and column
     one lost the left of its ring. The negative margin puts the grid back
     where it was, flush with the tab strip above it. */
  padding:9px 8px 7px 7px;
  margin:-9px -8px -7px -7px;
}
.ua-face{
  position:relative;display:block;aspect-ratio:3/4;cursor:pointer;
  border-radius:12px;overflow:hidden;
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:transform .22s var(--e-out),box-shadow .22s var(--e-out);
}
.ua-face img{
  width:100%;height:100%;object-fit:cover;display:block;
  transition:transform .5s var(--e-out);
}
.ua-face:hover{transform:translateY(-2px);}

/* ── choosing a face ──
   Four things move, and none of them could move while the grid was
   rebuilt on every click: a replaced button arrives already selected,
   with no previous frame to animate from, so the ring simply blinked on.
   js/ugc-ad.js toggles the class in place for exactly this reason.

     · the ring drops onto the card from slightly too large
     · the tick pops, then draws itself
     · the face pushes in, so the chosen one has depth the others lack
     · one accent wash passes through and is gone

   The card lifts to -3px and stays there. The hover rule above is the
   same specificity, so these come after it on purpose: a chosen card
   under the pointer must not drop back to the hover height. */
.ua-face::after{
  content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;
  box-shadow:inset 0 0 0 2.5px var(--vz-acc);
  opacity:0;transform:scale(1.07);
  transition:opacity .18s var(--e-out),transform .34s cubic-bezier(.34,1.5,.64,1);
}
.ua-face.is-on::after{opacity:1;transform:none;}
.ua-face.is-on{transform:translateY(-3px);}
.ua-face.is-on img{transform:scale(1.055);}

.ua-face-tick{
  position:absolute;top:7px;right:7px;width:22px;height:22px;border-radius:50%;
  display:grid;place-items:center;pointer-events:none;
  background:var(--vz-acc);color:var(--vz-acc-ink);
  opacity:0;transform:scale(.3);
  transition:opacity .14s var(--e-out),transform .36s cubic-bezier(.34,1.62,.64,1);
}
.ua-face-tick svg{width:12px;height:12px;}
/* the stroke is ~11 units long; 13 is over it, so it starts fully hidden */
.ua-face-tick path{
  stroke-dasharray:13;stroke-dashoffset:13;
  transition:stroke-dashoffset .28s .09s var(--e-out);
}
.ua-face.is-on .ua-face-tick{opacity:1;transform:none;}
.ua-face.is-on .ua-face-tick path{stroke-dashoffset:0;}

/* The wash is ::before, so it sits under the name and the tick — both are
   real children and paint after it. ::after is the last generated child,
   so the ring stays on top of the wash too. An outward halo was the other
   option and this card clips its own overflow, so it would never be seen. */
.ua-face::before{
  content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;
  background:var(--vz-acc);opacity:0;
}
.ua-face.is-picking::before{animation:ua-wash .44s var(--e-out);}
.ua-face.is-picking{animation:ua-press .34s var(--e-out);}
@keyframes ua-wash{from{opacity:.42;}to{opacity:0;}}
/* lands on the same -3px the .is-on rule holds, so nothing jumps when
   the animation hands the card back to the stylesheet */
@keyframes ua-press{
  0%{transform:scale(1) translateY(0);}
  34%{transform:scale(.945) translateY(0);}
  100%{transform:scale(1) translateY(-3px);}
}
@media (prefers-reduced-motion: reduce){
  .ua-face,.ua-face img,.ua-face::after,.ua-face-tick,.ua-face-tick path{transition:none;}
  .ua-face.is-picking,.ua-face.is-picking::before{animation:none;}
}
.ua-face-n{
  position:absolute;left:0;right:0;bottom:0;padding:16px 8px 7px;
  font-size:11.5px;font-weight:600;color:#fff;text-align:left;
  /* The name sits on the photo, so the scrim under it carries the
     contrast rather than the page ground. The stops matter: the glyphs
     start at about 43% down this box, and at the old .5-at-45% the top of
     a name over a pale studio wall measured 3.7:1. Deeper and earlier puts
     the worst case at 6.4:1. */
  background:linear-gradient(180deg,transparent,rgba(8,7,6,.62) 38%,rgba(8,7,6,.92));
}
.ua-face.is-locked img{filter:grayscale(1) brightness(.55);}
.ua-face-lock{
  position:absolute;top:7px;right:7px;width:21px;height:21px;border-radius:50%;
  display:grid;place-items:center;color:#fff;background:rgba(8,7,6,.7);
}
.ua-face-lock svg{width:11px;height:11px;}

.ua-own{
  position:relative;display:block;width:180px;aspect-ratio:3/4;
  border-radius:14px;overflow:hidden;cursor:pointer;
  background:var(--a-sunk);box-shadow:inset 0 0 0 1px var(--a-line);
}
.ua-own:hover{box-shadow:inset 0 0 0 1px var(--a-mute);}
.ua-own.is-over{box-shadow:inset 0 0 0 1.5px var(--vz-acc);}
.ua-own-empty{
  position:absolute;inset:0;
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:6px;
  padding:16px;text-align:center;color:var(--a-mute);
}
.ua-own-empty svg{width:32px;height:32px;}
.ua-own-empty b{font-size:13px;font-weight:600;color:var(--a-ink);}
.ua-own-empty em{font-style:normal;font-size:11px;line-height:1.4;}
.ua-own-full{position:absolute;inset:0;display:block;}
.ua-own-full img{width:100%;height:100%;object-fit:cover;display:block;}

/* ── the angle ── */

/* ── the script ── */
.ua-prompt{
  border-radius:13px;padding:13px 14px 12px;margin-bottom:20px;
  background:var(--a-sunk);box-shadow:inset 0 0 0 1px var(--a-line);
}
.ua-prompt-h{
  display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:9px;
}
.ua-prompt-h span{font-size:10px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;color:var(--a-mute);}
.ua-write{
  display:inline-flex;align-items:center;gap:6px;cursor:pointer;
  padding:6px 13px;border-radius:100px;
  font-family:inherit;font-size:11.5px;font-weight:600;
  background:var(--vz-acc);color:var(--vz-acc-ink);
  transition:transform .2s var(--e-out);
}
.ua-write:hover{transform:translateY(-1px);}
.ua-write svg{width:12px;height:12px;}
.ua-prompt textarea{
  width:100%;border:0;background:transparent;resize:vertical;
  font-family:inherit;font-size:13.5px;line-height:1.55;color:var(--a-ink);
}
.ua-prompt textarea:focus{outline:none;}
.ua-prompt textarea::placeholder{color:var(--a-mute);}

/* ── format ── */
.ua-opts{display:flex;gap:8px;flex-wrap:wrap;}
.ua-opt{display:flex;gap:3px;padding:3px;border-radius:100px;background:var(--a-sunk);box-shadow:inset 0 0 0 1px var(--a-line);}
.ua-chip{
  padding:6px 13px;border-radius:100px;cursor:pointer;
  font-family:inherit;font-size:12px;font-weight:600;
  color:var(--a-mute);background:transparent;
  font-variant-numeric:tabular-nums;
  transition:background-color .2s var(--e-out),color .2s var(--e-out);
}
.ua-chip:hover{color:var(--a-ink);}
.ua-chip.is-on{background:var(--a-btn);color:var(--a-btn-ink);}

/* ── the brief ── */
.ua-brief{position:sticky;top:76px;}
.ua-brief-card{
  border-radius:16px;padding:14px;
  background:var(--a-panel);
  box-shadow:inset 0 0 0 1px var(--a-line),var(--a-shadow);
}
/* the two things the ad is made of, shown as they arrive */
.ua-brief-stage{
  position:relative;aspect-ratio:9/16;max-height:300px;margin:0 auto 14px;
  border-radius:12px;overflow:hidden;
  background:var(--a-sunk);box-shadow:inset 0 0 0 1px var(--a-line);
  display:grid;place-items:center;
}
.ua-brief-face{position:absolute;inset:0;}
.ua-brief-face img{width:100%;height:100%;object-fit:cover;display:block;}
.ua-brief-prod{
  position:absolute;right:10px;bottom:10px;width:38%;aspect-ratio:1;
  border-radius:9px;overflow:hidden;
  box-shadow:0 0 0 2px var(--a-panel),0 10px 24px -10px rgba(0,0,0,.7);
}
.ua-brief-prod img{width:100%;height:100%;object-fit:cover;display:block;}
.ua-brief-empty{
  display:flex;flex-direction:column;align-items:center;gap:9px;
  font-size:11.5px;color:var(--a-mute);text-align:center;padding:16px;
}
.ua-brief-empty svg{width:34px;height:34px;}

.ua-brief-list{margin:0 0 14px;display:flex;flex-direction:column;gap:0;}
.ua-brief-list > div{
  display:flex;align-items:baseline;justify-content:space-between;gap:12px;
  padding:8px 0;border-bottom:1px solid var(--a-line);
}
.ua-brief-list > div:last-child{border-bottom:0;}
.ua-brief-list dt{
  flex:0 0 auto;font-size:10.5px;font-weight:600;
  letter-spacing:.08em;text-transform:uppercase;color:var(--a-mute);
}
.ua-brief-list dd{
  margin:0;min-width:0;text-align:right;
  font-size:13px;font-weight:500;color:var(--a-ink);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}

.ua-go{
  display:flex;align-items:center;justify-content:center;gap:10px;
  width:100%;padding:14px;border-radius:12px;cursor:pointer;
  font-family:inherit;font-size:14px;font-weight:600;
  background:var(--a-btn);color:var(--a-btn-ink);
  transition:transform .2s var(--e-out),opacity .2s var(--e-out);
}
.ua-go:hover{transform:translateY(-1px);}
/* still pressable when something is missing — pressing it is how you find
   out what, and the line underneath says so */
.ua-go.is-waiting{opacity:.6;}
.ua-go-c{display:inline-flex;align-items:center;gap:4px;font-variant-numeric:tabular-nums;}
.ua-go-c svg{width:12px;height:12px;}
.ua-legal{margin:10px 0 0;font-size:11px;line-height:1.45;color:var(--a-mute);text-align:center;}

/* ── the shop's own photos ──
   Shown under the fields the link filled in. Tapping one drops it into a
   product slot, so the common path — paste, pick two, carry on — never
   touches the file picker. */
.ua-shopnote{
  margin:12px 0 0;font-size:12px;line-height:1.5;color:var(--a-mute);
}
.ua-simgs{
  display:grid;gap:8px;margin-top:10px;
  grid-template-columns:repeat(auto-fill,minmax(min(84px,100%),1fr));
}
.ua-simg{
  position:relative;display:block;aspect-ratio:1;cursor:pointer;
  border-radius:10px;overflow:hidden;
  background:var(--a-panel);
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:transform .2s var(--e-out),box-shadow .2s var(--e-out);
}
.ua-simg img{width:100%;height:100%;object-fit:contain;display:block;background:#fff;}
.ua-simg:hover{transform:translateY(-2px);}
.ua-simg.is-on{box-shadow:inset 0 0 0 2.5px var(--vz-acc);}
.ua-simg-tick{
  position:absolute;top:6px;right:6px;width:19px;height:19px;border-radius:50%;
  display:grid;place-items:center;opacity:0;
  background:var(--vz-acc);color:var(--vz-acc-ink);
  transition:opacity .18s var(--e-out);
}
.ua-simg-tick svg{width:10px;height:10px;}
.ua-simg.is-on .ua-simg-tick{opacity:1;}

/* the three format groups need air between them; the first one sits
   straight under the script and does not */
.ua-lbl-sp{margin-top:22px;}
.ua-main .vg-ruler-w{margin-top:2px;}


/* ── trimming step three ──
   Everything below is scoped to .ua-main. The Video page uses the same
   components at their full size, where the panel is the whole screen and
   that size is right. */

/* angles: one row of chips, and the chosen one explains itself underneath */
.ua-main .ua-angles{
  display:flex;flex-wrap:wrap;gap:4px;margin-bottom:8px;
}
.ua-main .ua-angle{
  display:inline-flex;flex-direction:row;align-items:center;gap:6px;
  white-space:nowrap;cursor:pointer;
  padding:7px 11px;border-radius:100px;
  font-size:12.5px;font-weight:600;color:var(--a-mute);
  background:var(--a-sunk);box-shadow:inset 0 0 0 1px var(--a-line);
  transition:background-color .18s var(--e-out),color .18s var(--e-out);
}
.ua-main .ua-angle:hover{color:var(--a-ink);background:var(--a-chip);}
.ua-main .ua-angle.is-on{
  background:var(--a-btn);color:var(--a-btn-ink);
  box-shadow:none;
}
.ua-anglenote{
  margin:0 0 20px;font-size:12.5px;line-height:1.5;color:var(--a-mute);
}

/* ratio tiles small enough that all seven sit on one line */
.ua-main .vg-ratios{grid-template-columns:repeat(6,1fr);gap:5px;}
@media (max-width:560px){.ua-main .vg-ratios{grid-template-columns:repeat(3,1fr);}}
.ua-main .vg-ratio{
  padding:7px 4px 6px;border-radius:10px;gap:5px;
}
.ua-main .vg-ratio-box{height:24px;}
.ua-main .vg-ratio-l{font-size:10.5px;}

/* resolution as pills, like every other setting here */
.ua-main .vg-resgrid{display:flex;flex-wrap:wrap;gap:6px;}
.ua-main .vg-res{
  flex:0 0 auto;padding:7px 15px;border-radius:100px;min-height:0;
  gap:6px;
}
.ua-main .vg-res b{font-size:12.5px;}
.ua-main .vg-res-max{font-size:8.5px;padding:2px 5px;}

/* a shorter ruler; the read-out still carries the number */
.ua-main .vg-ruler-bars{height:26px;}
.ua-main .vg-tick{height:11px;}
.ua-main .vg-tick.is-major{height:17px;}
.ua-main .vg-tick.is-at{height:23px;}
.ua-main .vg-ruler-read > b{font-size:25px;}

.ua-main .ua-lbl-sp{margin-top:16px;}
.ua-main .ua-prompt{margin-bottom:16px;}

/* the angle that works for the widest range of products, marked rather than
   pre-selected — an angle is optional here */
.ua-angle-dot{
  width:5px;height:5px;border-radius:50%;flex:0 0 auto;
  background:var(--vz-acc);
}
.ua-main .ua-angle.is-on .ua-angle-dot{background:var(--a-btn-ink);}
.ua-anglenote b{color:var(--a-ink);font-weight:600;}

/* ═══ STUDIO NAV MENUS ═══
   Appended to <body> rather than nested in the bar: .anav-links scrolls
   sideways, and an overflow container clips anything drawn out of it. */
.anav-caret{
  width:9px;height:9px;flex:0 0 auto;opacity:.6;
  transition:transform .22s var(--ease),opacity .22s var(--ease);
}
.anav-link[aria-expanded="true"] .anav-caret{transform:rotate(180deg);opacity:1;}
.anav-link[data-anav-menu]{cursor:pointer;}

.anav-menu{
  position:fixed;z-index:400;
  min-width:268px;max-width:320px;
  padding:7px;border-radius:14px;
  background:var(--a-panel);
  box-shadow:inset 0 0 0 1px var(--a-line),var(--a-shadow);
  opacity:0;transform:translateY(-6px);
  transition:opacity .18s var(--e-out),transform .18s var(--e-out);
  max-height:calc(100vh - 90px);overflow-y:auto;
}
.anav-menu.is-in{opacity:1;transform:none;}

.anav-menu-h{
  margin:8px 0 4px;padding:0 10px;
  font-size:9.5px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;
  color:var(--a-mute);
}
.anav-menu-h:first-child{margin-top:3px;}

.anav-menu-i{
  display:flex;align-items:center;gap:11px;
  padding:8px 10px;border-radius:9px;text-decoration:none;
  transition:background-color .16s var(--ease);
}
/* a drawn mark of what the tool does, so eleven rows are a set of things
   to pick from rather than a list to read */
.anav-menu-ic{
  flex:0 0 auto;width:30px;height:30px;border-radius:9px;
  display:grid;place-items:center;
  background:var(--a-chip);color:var(--a-ink);
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:background-color .16s var(--ease);
}
.anav-menu-ic svg{width:16px;height:16px;}
.anav-menu-i:hover .anav-menu-ic{background:var(--a-chip-2);}
.anav-menu-i.is-on .anav-menu-ic{background:var(--vz-acc);color:var(--vz-acc-ink);}
.anav-menu-t{display:flex;flex-direction:column;gap:1px;min-width:0;}
.anav-menu-i:hover,.anav-menu-i:focus-visible{background:var(--a-chip);outline:none;}
.anav-menu-i b{font-size:13px;font-weight:600;color:var(--a-ink);letter-spacing:-.01em;}
.anav-menu-i em{font-style:normal;font-size:11.5px;line-height:1.35;color:var(--a-mute);}
/* The page you are on. --a-chip-2 lifted the ground far enough that the
   muted description line fell to 4.05:1, so the row is marked with a bar
   and the lighter fill instead. */
.anav-menu-i.is-on{
  background:var(--a-chip);
  box-shadow:inset 2px 0 0 var(--vz-acc);
}

@media (prefers-reduced-motion: reduce){
  .anav-menu,.anav-caret{transition:none;}
}

/* ── the house mark on a model row ──
   Twenty-eight rows of two text lines gave the eye nothing to land on and
   no way to tell a Google row from a ByteDance one without reading it. */
.cmp-mrow{align-items:center;gap:11px;}
.cmp-mrow-ic{
  flex:0 0 auto;width:30px;height:30px;border-radius:9px;
  display:grid;place-items:center;
  background:var(--a-chip);color:var(--a-ink);
  box-shadow:inset 0 0 0 1px var(--a-line);
  font-size:12px;font-weight:700;
  transition:background-color .16s var(--ease),color .16s var(--ease);
}
.cmp-mrow-ic svg{width:16px;height:16px;}
.cmp-mrow:hover .cmp-mrow-ic{background:var(--a-chip-2);}
.cmp-mrow.is-on .cmp-mrow-ic{background:var(--vz-acc);color:var(--vz-acc-ink);}
.cmp-mrow-main{flex:1;}

/* ── an engine this plan cannot run ──
   Dimmed, not hidden. The locked names are the reason to upgrade, so
   they have to stay legible: the whole row drops to a muted weight
   rather than the text fading to grey on grey, and the tick column
   carries a lock. Still focusable and still clickable — clicking says
   what it costs to unlock. */
.cmp-mrow.is-locked{opacity:.5;}
.cmp-mrow.is-locked:hover,.cmp-mrow.is-locked:focus-visible{opacity:.72;}
.cmp-mrow.is-locked .cmp-mrow-ic{background:transparent;box-shadow:inset 0 0 0 1px var(--a-line);}
.cmp-mrow.is-locked .cmp-mrow-tick{opacity:1;color:var(--a-mute);}

/* the featured band reads as a recommendation, not another house */
.cmp-pop-group.is-feat{
  display:flex;align-items:center;gap:6px;
  color:var(--a-ink);
}
.cmp-pop-group.is-feat svg{width:11px;height:11px;}


/* ── the veil behind the model picker ──
   Grey-black and light enough to read the work through: this is a picker,
   not a modal, and blacking the page out for it would overstate what is
   being asked. Sits under the composer bar and over everything else. */
.cmp-scrim{
  position:fixed;inset:0;z-index:40;
  background:radial-gradient(120% 90% at 22% 100%,rgba(12,12,13,.16),rgba(12,12,13,.40));
  backdrop-filter:blur(1px);-webkit-backdrop-filter:blur(1px);
  opacity:0;transition:opacity .24s var(--e-out);
}
.cmp-scrim.is-in{opacity:1;}
[data-app="light"] .cmp-scrim{
  background:radial-gradient(120% 90% at 22% 100%,rgba(24,24,26,.07),rgba(24,24,26,.20));
}
@media (prefers-reduced-motion: reduce){
  .cmp-scrim{transition:none;}
}


/* ═══ CARRYING A FRAME DOWN TO THE COMPOSER ═══
   Dragging a picture off the wall and dropping it on the bar makes it a
   reference, the same as uploading one. Two states, because a drop target
   you cannot find is not a target: the bar outlines itself the moment a
   frame leaves the wall, then fills in once the pointer is actually over
   it. Pointer-only by nature — the Reference button on the tile and in the
   open window is the same move for touch and for the keyboard. */
.gc{transition:outline-color .2s var(--e-out);}
.gc.is-armed{
  /* outline rather than box-shadow: the bar's own shadow is doing three
     jobs already and a ring bolted into it would have to restate them */
  outline:1.5px dashed color-mix(in srgb,var(--vz-acc) 50%,transparent);
  outline-offset:4px;
}
.gc.is-drop{
  outline:2px solid var(--vz-acc);
  outline-offset:4px;
}

.gc-drop{
  position:absolute;inset:0;border-radius:inherit;z-index:3;
  pointer-events:none;                       /* never eats the drop itself */
  display:grid;place-items:center;
  background:color-mix(in srgb,var(--a-panel) 86%,var(--vz-acc));
  opacity:0;transition:opacity .18s var(--e-out);
}
.gc.is-drop .gc-drop{opacity:1;}
.gc-drop-in{
  display:inline-flex;align-items:center;gap:10px;
  font-size:14.5px;font-weight:600;letter-spacing:-.012em;color:var(--a-ink);
  transform:scale(.95);
  transition:transform .3s cubic-bezier(.34,1.5,.64,1);
}
.gc.is-drop .gc-drop-in{transform:none;}
.gc-drop-in svg{width:18px;height:18px;flex:none;}

/* the frame that is being carried stays behind, dimmed, so it is obvious
   which one is in flight */
.gw-cell.is-carrying{opacity:.4;}
.gw-cell.is-carrying img{filter:brightness(.65);}

@media (prefers-reduced-motion: reduce){
  .gc,.gc-drop,.gc-drop-in{transition:none;}
}

/* the bar while a run is in flight */
.gc.is-working .gc-go{opacity:.55;cursor:progress;}
.gc-go[disabled]{pointer-events:none;}
/* a frame that just came back, so the new ones are obvious among the old */
.gw-cell.is-fresh{animation:gw-in .5s var(--e-out) backwards;}

/* ── the shape beside each aspect ratio ──
   A fixed 18px square holds every outline, so the shapes sit in one column
   and can be compared against each other; the outline inside it carries
   the real proportion. Drawn with an inset ring rather than a border so
   the box keeps its size whatever the ring weight. */
.cmp-ratio-ico{
  flex:none;width:22px;height:22px;
  display:grid;place-items:center;
}
.cmp-ratio-ico i{
  display:block;border-radius:2.5px;
  box-shadow:inset 0 0 0 1.4px var(--a-mute);
  transition:box-shadow .2s var(--ease);
}
.cmp-row.is-on .cmp-ratio-ico i,
.cmp-row:hover .cmp-ratio-ico i{box-shadow:inset 0 0 0 1.4px var(--a-ink);}

/* ── the aspect-ratio rows ──
   Shape, number, and a tick on the one in use. Nothing else: the outline
   already says what the words used to, and it says it faster. */
/* Ten rows at the shared 40px came to 430px against a 420px cap, so the
   list scrolled to hide the last one. These rows carry a shape and a
   number and nothing else, so they do not need the height a two-line row
   does — at 34px all ten are on screen at once. */
.cmp-row-r{padding:6px 10px;}
.cmp-row-r b{min-width:38px;}
.cmp-row-tick{
  width:14px;height:14px;flex:none;margin-left:auto;
  color:var(--a-ink);
}
/* the credit mark, matched to the Generate button's */
.cmp-row-cost{display:inline-flex;align-items:center;gap:5px;}
.cmp-row-star{width:10px;height:10px;flex:none;opacity:.75;}
.cmp-row.is-on .cmp-row-star{opacity:1;}

/* ═══ PLANS AND CREDITS ═══
   Cards, because that is what this category has trained people to read —
   but each one carries its own hue on the edge, its conversions in plain
   units, and a sheen that crosses once on hover. The part worth having is
   the finder underneath. */
.pr{position:relative;padding:0 0 110px;}

/* fine grain over the whole sheet; at 3% it is felt rather than seen */
.pr::before{
  content:"";position:fixed;inset:0;z-index:0;pointer-events:none;opacity:.03;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}
.pr > *{position:relative;z-index:1;}


/* ── hero ── */
/* A line and a switch, so it does not need the room a three-paragraph
   hero did. */
.pk-hero{padding:56px 0 40px;max-width:760px;}
.pk-tag-line{
  margin-bottom:26px;font-size:16px;line-height:1.5;color:var(--a-mute);
  animation:pk-rise .7s .26s var(--e-out) backwards;
}
.pk-eyebrow{
  font-size:10.5px;font-weight:700;letter-spacing:.2em;text-transform:uppercase;
  color:var(--a-mute);margin-bottom:18px;
  animation:pk-rise .6s .06s var(--e-out) backwards;
}
.pk-h1{
  font-size:clamp(38px,6.4vw,72px);font-weight:600;letter-spacing:-.045em;
  line-height:.98;color:var(--a-ink);margin-bottom:14px;
}
.pk-w{display:inline-block;animation:pk-word .8s var(--e-out) backwards;animation-delay:var(--d);}
@keyframes pk-word{
  from{opacity:0;transform:translate3d(0,28px,0);filter:blur(7px);}
  to{opacity:1;transform:none;filter:none;}
}
@keyframes pk-rise{from{opacity:0;transform:translate3d(0,14px,0);}to{opacity:1;transform:none;}}
.pk-lede{
  max-width:58ch;font-size:16px;line-height:1.62;color:var(--a-mute);
  animation:pk-rise .7s .38s var(--e-out) backwards;
}
.pk-cycle{
  display:inline-flex;gap:2px;padding:3px;border-radius:100px;
  background:var(--a-sunk);box-shadow:inset 0 0 0 1px var(--a-line);
  animation:pk-rise .7s .36s var(--e-out) backwards;
}
.pk-cyc{
  display:inline-flex;align-items:center;gap:8px;
  padding:9px 20px;border-radius:100px;cursor:pointer;
  font-family:inherit;font-size:13px;font-weight:600;color:var(--a-mute);
  transition:background-color .25s var(--ease),color .25s var(--ease);
}
.pk-cyc i{
  font-style:normal;padding:2px 7px;border-radius:100px;font-size:10.5px;font-weight:700;
  background:var(--vz-acc);color:var(--vz-acc-ink);
}
.pk-cyc.is-on{background:var(--a-panel);color:var(--a-ink);box-shadow:0 1px 4px rgba(0,0,0,.28);}
.pk-have{
  display:inline-flex;align-items:center;gap:7px;margin-top:16px;font-size:12.5px;color:var(--a-mute);
  animation:pk-rise .7s .38s var(--e-out) backwards;
}
.pk-have svg{width:11px;height:11px;color:var(--vz-acc);}
.pk-have b{color:var(--a-ink);font-weight:600;}

/* ── cards ──
   Seven shared rows, so the price, the button, the pool and the first
   feature line up across all four. margin-top:auto only pins within a
   card, and one two-line tagline pushed its neighbours out of step. */
.pk-grid{
  /* Capped rather than stretched to the container. Across 1,500px each
     card came out 355px wide for content that needs 285, and four wide
     boxes read as sprawl however tidy the insides are. */
  /* Columns keep their gap; rows do not. The row gap was landing on top
     of each part's own margin, so a 7px space under the box came out at
     21px and the button floated away from the card it belongs to. Each
     part sets its own distance now. */
  display:grid;column-gap:14px;row-gap:0;max-width:1180px;margin-bottom:26px;
  grid-template-columns:repeat(auto-fit,minmax(min(230px,100%),1fr));
  /* Three in-flow parts per column — the box, the ticks, the numbers.
     The button moved inside the box: a price and the button that buys it
     belong in one frame, and apart the button read as a caption under a
     picture rather than the end of the offer. */
  grid-template-rows:repeat(3,auto);
}
/* ── one frame, three sections ──
   The offer, the ticks and the numbers were each in a box of their own,
   which divided them but also cut the column into three loose objects.
   The border belongs to the column: inside it the sections are separated
   by rules, which says "these belong together, in this order" rather than
   "here are three things about the same plan".

   overflow:hidden so the coloured head of a recommended card is cut by
   the same radius the frame draws. */
.pk-card{
  position:relative;overflow:hidden;
  display:grid;grid-row:span 3;grid-template-rows:subgrid;align-content:start;
  border-radius:16px;
  background:var(--a-panel);
  box-shadow:inset 0 0 0 1px var(--a-line);
  animation:pk-card-in .75s var(--e-out) backwards;
  animation-delay:calc(.18s + var(--i) * .08s);
}
/* A pop, not a slide. The cards used to rise 28px, which reads as the
   page settling; scaling up from 94% with a short overshoot reads as each
   card arriving. The overshoot is 2% and 90ms — enough to feel sprung,
   too small to look bouncy. */
@keyframes pk-card-in{
  0%{opacity:0;transform:translate3d(0,14px,0) scale(.94);}
  70%{opacity:1;transform:translate3d(0,0,0) scale(1.02);}
  100%{opacity:1;transform:none;}
}
/* One lift for all four. The recommended card used to rise twice as far
   as its neighbours, which made the row look uneven on the way past
   rather than making that card look chosen. */
.pk-card{transition:transform .28s var(--e-out),box-shadow .28s var(--e-out);}
.pk-card:hover{transform:translateY(-6px);box-shadow:inset 0 0 0 1px var(--a-mute),0 30px 64px -34px rgba(0,0,0,.75);}
/* the hue lives on the top edge only — four cards, four tones, one ladder */
/* ── Starter: a hint of its colour, not a fill ──
   It carries no band, so the hue only ever reached the hairline and the
   card read as one of the two grey ones. A wash across the head gives it
   a place in the warm ladder without promoting it to the pair being
   recommended — the whole point is that it is visibly less than they are.

   Roughly a fifth of their strength, gone by the time the sub-lines
   start, so nothing sits on tinted ground and no contrast changes. */
[data-app="dark"] .pk-card[data-plan="starter"] .pk-box{
  background:
    linear-gradient(180deg,
      hsl(var(--hue) 58% 40% / .22) 0%,
      hsl(var(--hue) 50% 30% / .08) 34%,
      transparent 58%),
    var(--a-panel);
}
[data-app="light"] .pk-card[data-plan="starter"] .pk-box,
:root:not([data-app="dark"]) .pk-card[data-plan="starter"] .pk-box{
  background:
    linear-gradient(180deg,
      hsl(var(--hue) 92% 72% / .40) 0%,
      hsl(var(--hue) 95% 85% / .22) 34%,
      transparent 58%),
    var(--a-panel);
}

/* Free sits outside the warm ladder: it is the plan nobody is being
   sold, so its hairline stays neutral and the three paid tones read as
   one family. */
.pk-card[data-plan="free"] .pk-edge{
  background:linear-gradient(90deg,
    rgba(255,255,255,.10),rgba(255,255,255,.30),rgba(255,255,255,.10));
}
.pk-edge{
  position:absolute;left:0;right:0;top:0;height:3px;
  background:linear-gradient(90deg,
    hsl(var(--hue) 70% 58% / .3),
    hsl(var(--hue) 78% 62% / .95),
    hsl(var(--hue) 70% 58% / .3));
}
.pk-card.is-best .pk-edge{height:4px;}
/* The ring and the panel are the column frame’s job now. What is left
   here is only the head fill, which the theme rules below set. */



/* the recommendation from the finder marks a card without moving it */
/* The highlight rings the offer, not the column. On the article it ran
   the full height and boxed in the tick list and the numbers, which are
   reference rows and not part of what is being recommended. */
.pk-card.is-rec .pk-box{box-shadow:inset 0 0 0 1.5px var(--vz-acc),0 26px 60px -34px rgba(0,0,0,.8);}

/* ── the sheen, once, on the way through ──
   On .pk-box, not on the column. It parks at translateX(-120%) waiting to
   be swept, which only works if something clips it: the box has
   overflow:hidden, the column does not. Sitting on the column it was
   never cut off, so the diagonal band simply stood beside every card,
   permanently, instead of crossing one on hover.

   Wanting it on the box is also the right answer for its own sake — the
   sheen belongs to the offer, not to the rows of reference under it. */
.pk-box::after{
  content:"";position:absolute;inset:0;z-index:2;pointer-events:none;
  background:linear-gradient(115deg,transparent 38%,
    color-mix(in srgb,var(--a-ink) 7%,transparent) 50%,transparent 62%);
  transform:translateX(-120%);
}
.pk-card.is-best .pk-box::after{
  background:linear-gradient(115deg,transparent 38%,
    color-mix(in srgb,var(--vz-acc) 18%,transparent) 50%,transparent 62%);
}
.pk-card:hover .pk-box::after{transition:transform .95s var(--e-out);transform:translateX(120%);}

@media (prefers-reduced-motion:reduce){
  .pk-box::after{display:none;}
}

.pk-flags{display:flex;flex-wrap:wrap;gap:6px;min-height:20px;margin-bottom:10px;}
.pk-off,.pk-tag{
  padding:3px 9px;border-radius:100px;
  font-size:9.5px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;
  white-space:nowrap;
}
/* A band across the head of the box rather than a pill dropped on it.
   A pill has to be dodged — the name needed padding under it and still
   sat close; a band owns its own strip and nothing has to move around
   it. Out of the grid either way, so it costs the column no row. */
.pk-tag{
  position:absolute;top:0;left:0;right:0;z-index:3;
  display:flex;align-items:center;justify-content:center;gap:5px;
  padding:7px 10px;border-radius:0;
  font-size:9.5px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;
  /* The plan's own hue, the same one the top edge is drawn from. A white
     band over a dark card read as a separate strip sitting above it
     rather than as part of it — colour is what joins the two. */
  background:linear-gradient(90deg,
    hsl(var(--hue) 62% 46%),
    hsl(var(--hue) 68% 52%));
  color:#fff;
}
/* the band replaces the hairline on the cards that have one */
.pk-card:has(.pk-tag) .pk-edge{display:none;}
/* ── the two cards that are being recommended ──
   Filled in their own hue rather than tinted at the top. A plan grid is
   read fast, and colour is the only thing in it that works before the
   words do — a band alone was not enough to say "this one".

   Deep rather than bright: at 30% lightness the fill is saturated enough
   to be unmistakably gold or magenta and dark enough to carry white text
   at the ratio the rest of the page holds. A bright card would have to
   flip to dark ink, and then the two highlighted plans would read as a
   different product from the other two. */
/* ── the two recommended cards ──
   Colour at the head, the page's own ground by the foot. Which ground
   that is depends on the theme, so the fill is written twice: down into
   black in the studio's dark, down into white in its light. Writing it
   once meant two black cards sitting on a white page.

   The ink flips with it. At the top the card is saturated enough to
   carry white in dark mode and dark ink in light; by the time the price
   arrives the fill has become the page and the normal colours apply. */
[data-app="dark"] .pk-card:has(.pk-tag) .pk-box{
  --a-ink:#ffffff;
  --a-mute:rgba(255,255,255,.8);
  --a-line:rgba(255,255,255,.18);
  background:linear-gradient(180deg,
    hsl(var(--hue) 62% 32%) 0%,
    hsl(var(--hue) 55% 22%) 26%,
    hsl(var(--hue) 40% 11%) 46%,
    #0d0d0d 66%);
  box-shadow:inset 0 0 0 1px hsl(var(--hue) 55% 60% / .22),
             0 30px 68px -34px hsl(var(--hue) 70% 10% / .8);
}

[data-app="light"] .pk-card:has(.pk-tag) .pk-box,
:root:not([data-app="dark"]) .pk-card:has(.pk-tag) .pk-box{
  /* Dark ink here: the fill is a tint, not a slab, so the card stays part
     of a white page rather than becoming a hole in it. */
  --a-ink:#121212;
  --a-mute:rgba(18,18,18,.62);
  --a-line:rgba(18,18,18,.14);
  background:linear-gradient(180deg,
    hsl(var(--hue) 88% 72%) 0%,
    hsl(var(--hue) 92% 84%) 26%,
    hsl(var(--hue) 95% 94%) 46%,
    #ffffff 66%);
  box-shadow:inset 0 0 0 1px hsl(var(--hue) 60% 55% / .3),
             0 26px 60px -34px hsl(var(--hue) 60% 40% / .45);
}
/* the ring the recommendation used to draw is now the fill itself */
.pk-card.is-best .pk-box,
.pk-card.is-rec .pk-box{
  box-shadow:inset 0 0 0 1px hsl(var(--hue) 55% 60% / .26),
             0 30px 68px -34px hsl(var(--hue) 70% 10% / .8);
}
/* the band sits on top of its own colour, so it lightens rather than
   repeating the same value */
/* Darker than it looks like it needs to be. The label is 9.5px, which
   the guidelines treat as small text, and at the lightness this band
   started on, white sat at 3.8:1 against the orange — legible to me and
   not to everyone. */
.pk-card:has(.pk-tag) .pk-tag{
  background:linear-gradient(90deg,
    hsl(var(--hue) 66% 34%),
    hsl(var(--hue) 72% 42%));
}
/* the sheen has a lighter card to cross now */
.pk-card:has(.pk-tag) .pk-box::after{
  background:linear-gradient(115deg,transparent 38%,
    rgba(255,255,255,.14) 50%,transparent 62%);
}
/* The badge floats over the card, so a card that has one needs its
   heading pushed clear of it — otherwise PLUS and ULTRA read through the
   pill. Only the two cards that carry a badge pay the space; the other
   two keep their original top and all four still line up, because the
   header occupies the same subgrid row either way. */
.pk-off{background:var(--a-chip-2);color:var(--a-ink);}


.pk-name{
  /* Was 15px uppercase with wide tracking, which reads as a section label
     rather than a name. A plan is called Free or Plus; set it the size
     someone would say it. */
  font-size:23px;font-weight:600;letter-spacing:-.02em;
  color:var(--a-ink);line-height:1.1;
}
.pk-line{margin-top:6px;font-size:12.5px;line-height:1.45;color:var(--a-mute);}

.pk-price{
  /* align-self was end, which in the box’s flex column means the right
     edge — it read as a right-aligned price against left-aligned copy.
     The push to the bottom is margin-top:auto on .pk-box .pk-price. */
  align-self:flex-start;display:flex;align-items:baseline;flex-wrap:wrap;gap:9px;
  margin:20px 0 0;
}
.pk-price .pk-was{flex:0 0 100%;}
.pk-price b{font-size:38px;font-weight:650;letter-spacing:-.04em;color:var(--a-ink);line-height:1;}
/* Fixed height, not min-height: the empty slot on Free measured 19px
   against 21px for a filled one, which put its price block two pixels out
   of step with the other three. */
.pk-was{
  font-size:16px;line-height:21px;height:21px;
  color:var(--a-mute);text-decoration:line-through;text-decoration-thickness:1.5px;
}
.pk-price em{font-style:normal;font-size:11.5px;line-height:1.4;color:var(--a-mute);}

.pk-go{
  padding:14px;border-radius:12px;cursor:pointer;
  font-family:inherit;font-size:14px;font-weight:650;letter-spacing:-.01em;
  background:var(--a-chip-2);color:var(--a-ink);
  transition:transform .2s var(--ease),background-color .2s var(--ease);
}
.pk-go:hover{transform:translateY(-1px);}
.pk-go:active{transform:translateY(0) scale(.985);}
.pk-card.is-best .pk-go{background:var(--vz-acc);color:var(--vz-acc-ink);}
.pk-card.is-free .pk-go,.pk-card[data-plan="free"] .pk-go{
  background:transparent;box-shadow:inset 0 0 0 1px var(--a-line);color:var(--a-mute);cursor:default;
}
.pk-card[data-plan="free"] .pk-go:hover{transform:none;}
.pk-save{margin-top:9px;text-align:center;font-size:11px;color:var(--a-mute);}

/* ── credits, and what they turn into ──
   The same two parts the marketing page carries, in the same order: the
   pool as a plain sentence, then the box that says how many photographs
   that actually is. A credit figure means nothing to someone who has
   never bought one; a number of frames is the unit they already think
   in, so it gets the box and the pool gets a line. */
.pk-credits{
  font-size:15px;color:var(--a-mute);margin-bottom:7px;line-height:1.3;
}
/* No .is-best override on any of these: unlike the marketing page, where
   the featured card is a black surface, the best card here is the same
   panel with an accent wash. White-on-dark values would vanish the disc
   and the box the moment the app is in light mode. */
.pk-yield{padding:13px 15px;border-radius:13px;background:var(--a-chip);}
.pk-yield-n{font-size:14px;line-height:1.35;color:var(--a-ink);}
.pk-yield-n b{font-weight:650;font-variant-numeric:tabular-nums;}
.pk-yield-s{
  font-size:11.5px;line-height:1.5;color:var(--a-mute);margin:0;opacity:.85;
}
.pk-yield-s b{font-weight:650;color:var(--a-ink);font-variant-numeric:tabular-nums;}

/* the rule and the heading over the inherited list */
.pk-divider{height:1px;background:var(--a-line);margin:20px 0 15px;}
.pk-inherit{
  font-size:11px;font-weight:600;letter-spacing:.09em;text-transform:uppercase;
  color:var(--a-mute);padding-bottom:13px;
}

.pk-list li{
  position:relative;padding-left:24px;
  font-size:12.5px;line-height:1.45;color:var(--a-ink);
}
.pk-list svg{width:13px;height:13px;flex:none;margin-top:1px;color:var(--vz-acc);}
/* what this tier does not carry, dimmed but never hidden — the gap is the
   argument for the tier above */
.pk-list li.is-off{color:var(--a-mute);}
.pk-list li.is-off svg{color:var(--a-mute);opacity:.55;}
.pk-list b{font-weight:650;margin-left:5px;}
.pk-list li.is-off b{color:var(--a-mute);}

/* ── the finder ── */
[data-pk-reveal]{
  opacity:0;transform:translate3d(0,26px,0);
  transition:opacity .8s var(--e-out),transform .8s var(--e-out);
}
[data-pk-reveal].is-in{opacity:1;transform:none;}
.pk-find,.pk-faq{margin-bottom:120px;}
.pk-h2{
  font-size:clamp(25px,3.4vw,38px);font-weight:600;letter-spacing:-.032em;
  line-height:1.1;color:var(--a-ink);max-width:22ch;
}
.pk-sub{max-width:60ch;margin-top:12px;font-size:14.5px;line-height:1.62;color:var(--a-mute);}
.pk-find-h{margin-bottom:38px;}
/* ── the plan quiz ──
   One panel, one question. The old finder was a two-column console: chips
   and sliders on the left, a verdict updating on the right. It filled the
   width and gave the reader four things to do at once, which is a form.
   A single centred card asks for one answer and has nowhere else to look. */
.pk-quiz{
  max-width:760px;margin:0 auto;padding:34px 34px 30px;
  border-radius:22px;background:var(--a-panel);
  box-shadow:inset 0 0 0 1px var(--a-line);
}
@media (max-width:560px){.pk-quiz{padding:24px 20px 22px;}}

.pk-qbar{
  display:flex;align-items:center;justify-content:space-between;gap:18px;
  padding-bottom:22px;margin-bottom:24px;border-bottom:1px solid var(--a-line);
}
.pk-qdots{display:flex;gap:6px;}
/* Bars rather than dots: a bar has a length, so a row of them reads as
   distance covered instead of four identical lamps. */
.pk-qdots i{
  width:34px;height:3px;border-radius:100px;background:var(--a-chip-2);
  transition:background .3s var(--e-out),width .3s var(--e-out);
}
.pk-qdots i.is-done{background:color-mix(in srgb,var(--vz-acc) 55%,transparent);}
.pk-qdots i.is-on{width:52px;background:var(--vz-acc);}
.pk-qcount{font-size:11.5px;letter-spacing:.09em;text-transform:uppercase;color:var(--a-mute);}

.pk-qq{font-size:clamp(19px,2.4vw,24px);font-weight:600;letter-spacing:-.022em;color:var(--a-ink);}
.pk-qn{margin-top:6px;font-size:13.5px;color:var(--a-mute);}

.pk-kindcap{
  margin:20px 0 9px;font-size:10.5px;letter-spacing:.13em;
  text-transform:uppercase;color:var(--a-mute);
}
.pk-opts{
  margin-top:18px;display:grid;gap:9px;
  grid-template-columns:repeat(auto-fit,minmax(min(238px,100%),1fr));
}
.pk-kindcap + .pk-opts{margin-top:0;}

.pk-opt{
  display:flex;align-items:center;justify-content:space-between;gap:14px;
  padding:14px 16px;border-radius:14px;text-align:left;
  background:var(--a-chip);color:var(--a-ink);
  box-shadow:inset 0 0 0 1px transparent;
  transition:background .2s var(--e-out),box-shadow .2s var(--e-out),transform .12s var(--e-out);
  animation:pkOptIn .34s var(--e-out) both;animation-delay:var(--d,0ms);
}
@keyframes pkOptIn{from{opacity:0;transform:translateY(7px);}to{opacity:1;transform:none;}}
@media (prefers-reduced-motion:reduce){.pk-opt{animation:none;}}
.pk-opt:hover{box-shadow:inset 0 0 0 1px var(--a-mute);}
.pk-opt:active{transform:scale(.985);}
.pk-opt.is-on{
  background:color-mix(in srgb,var(--vz-acc) 12%,var(--a-chip));
  box-shadow:inset 0 0 0 1.5px var(--vz-acc);
}
.pk-opt-t{display:flex;flex-direction:column;gap:2px;min-width:0;}
.pk-opt-t b{font-size:14.5px;font-weight:600;line-height:1.25;}
.pk-opt-t em{font-style:normal;font-size:12px;color:var(--a-mute);}

/* The mark carries the difference between the two kinds of question, using
   the convention every form already taught the reader: a square box for
   "tick as many as you like", a round one for "pick exactly one". Without
   it both questions look like radios and the first one silently discourages
   a second answer. */
.pk-opt-m{
  flex:none;width:19px;height:19px;border-radius:50%;
  display:grid;place-items:center;
  box-shadow:inset 0 0 0 1.5px var(--a-line-2,var(--a-mute));
  transition:background .2s var(--e-out),box-shadow .2s var(--e-out);
}
.pk-opt-m svg{width:11px;height:11px;color:var(--vz-acc-ink);opacity:0;transition:opacity .18s var(--e-out);}
.pk-opt.is-on .pk-opt-m{background:var(--vz-acc);box-shadow:inset 0 0 0 1.5px var(--vz-acc);}
.pk-opt.is-on .pk-opt-m svg{opacity:1;}
.pk-opt[data-multi] .pk-opt-m{border-radius:6px;}
.pk-opt.is-on .pk-opt-m:empty::after{
  content:'';width:7px;height:7px;border-radius:50%;background:var(--vz-acc-ink);
}

.pk-qnav{
  display:flex;align-items:center;justify-content:space-between;gap:16px;
  margin-top:26px;padding-top:22px;border-top:1px solid var(--a-line);
}
.pk-qback{
  font-size:13.5px;color:var(--a-mute);padding:8px 2px;
  transition:color .2s var(--e-out);
}
.pk-qback:hover:not(:disabled){color:var(--a-ink);}
.pk-qback:disabled{opacity:.32;cursor:default;}
.pk-qnav .pk-go.is-solid:disabled{opacity:.4;cursor:default;}
.pk-qnav .pk-go.is-solid:disabled:hover svg{transform:none;}

/* ── the answer ── */
.pk-result{text-align:center;animation:pkOptIn .42s var(--e-out) both;}
@media (prefers-reduced-motion:reduce){.pk-result{animation:none;}}
.pk-result .pk-cap{
  font-size:10.5px;letter-spacing:.13em;text-transform:uppercase;color:var(--a-mute);
}
.pk-rname{
  margin-top:8px;font-size:clamp(34px,5.6vw,52px);font-weight:600;
  letter-spacing:-.035em;line-height:1;color:var(--a-ink);
}
.pk-rprice{margin-top:10px;display:flex;align-items:baseline;justify-content:center;gap:8px;}
.pk-rprice b{font-size:20px;font-weight:600;color:var(--a-ink);}
.pk-rprice em{font-style:normal;font-size:13px;color:var(--a-mute);}
.pk-result .pk-meter{margin:24px auto 0;max-width:420px;}
.pk-result .pk-meter-t{text-align:center;}
.pk-result .pk-why span{display:block;}
.pk-result .pk-why li{gap:10px;font-size:13.5px;line-height:1.5;}
.pk-result .pk-why{
  max-width:440px;margin:22px auto 0;text-align:left;
  padding:18px 20px;border-radius:14px;background:var(--a-chip);
}
.pk-rmix{margin-top:16px;font-size:13px;color:var(--a-mute);}
.pk-rmix b{color:var(--a-ink);font-weight:650;}
.pk-result .pk-go.is-solid{align-self:center;margin-top:22px;}
.pk-restart{
  display:block;margin:14px auto 0;font-size:13px;color:var(--a-mute);
  text-decoration:underline;text-underline-offset:3px;
  transition:color .2s var(--e-out);
}
.pk-restart:hover{color:var(--a-ink);}

.pk-meter{height:8px;border-radius:100px;background:var(--a-chip-2);overflow:hidden;}
.pk-meter i{
  display:block;height:100%;border-radius:inherit;
  background:linear-gradient(90deg,color-mix(in srgb,var(--vz-acc) 55%,transparent),var(--vz-acc));
  transition:width .45s var(--e-out);
}
.pk-meter i.is-over{background:linear-gradient(90deg,var(--vz-acc),var(--a-danger,#e0364a));}
.pk-meter-t{margin-top:10px;font-size:12px;color:var(--a-mute);font-variant-numeric:tabular-nums;}
.pk-meter-t b{color:var(--a-ink);font-weight:650;}
.pk-why{display:flex;flex-direction:column;gap:9px;margin:14px 0 22px;}
.pk-why li{display:flex;align-items:flex-start;gap:9px;font-size:13px;line-height:1.45;color:var(--a-ink);}
.pk-why svg{width:13px;height:13px;flex:none;margin-top:2px;color:var(--vz-acc);}
.pk-why span{display:flex;flex-direction:column;gap:1px;}
.pk-why b{font-weight:650;}
.pk-why em{font-style:normal;font-size:11.5px;color:var(--a-mute);}
.pk-go.is-solid{
  display:inline-flex;align-items:center;justify-content:center;gap:9px;
  align-self:flex-start;padding:13px 24px;border-radius:100px;
  background:var(--vz-acc);color:var(--vz-acc-ink);
}
.pk-go.is-solid svg{width:14px;height:14px;transition:transform .25s var(--e-out);}
.pk-go.is-solid:hover svg{transform:translateX(3px);}

/* ── teams ── */

/* ── questions ── */
.pk-faq{padding-top:0;}
/* Two columns above 900px. Six questions stacked ran the better part of a
   screen on their own, and a column of one-line headings with acres of
   space to their right is a list pretending to be a page.
   column-gap has a rule in it, so the two halves stay separated without a
   border on every item. */
/* Two independent stacks, not a column flow: see the note in pricing.js.
   The rule between them is drawn on the second column so it cannot end up
   floating below the shorter side. */
.pk-qs{
  margin-top:24px;
  display:grid;grid-template-columns:1fr 1fr;
  align-items:start;gap:0 56px;
}
.pk-qs .pk-qcol:last-child{
  padding-left:28px;margin-left:-28px;
  border-left:1px solid var(--a-line);
}
@media (max-width:900px){
  .pk-qs{grid-template-columns:1fr;gap:0;}
  .pk-qs .pk-qcol:last-child{padding-left:0;margin-left:0;border-left:0;}
}
.pk-q{
  border-bottom:1px solid var(--a-line);
}
.pk-q summary{
  display:flex;align-items:flex-start;justify-content:space-between;gap:20px;
  padding:18px 2px;cursor:pointer;list-style:none;
  font-size:15px;font-weight:600;line-height:1.35;letter-spacing:-.015em;color:var(--a-ink);
  transition:color .22s var(--ease);
}
.pk-q summary::-webkit-details-marker{display:none;}
.pk-q summary:hover{color:var(--vz-acc);}
/* a plus that becomes a minus, drawn from two rules rather than an icon */
.pk-q summary i{position:relative;width:13px;height:13px;flex:none;margin-top:4px;color:var(--a-mute);transition:color .22s var(--ease);}
.pk-q summary:hover i,.pk-q[open] summary i{color:var(--vz-acc);}
.pk-q summary i::before,.pk-q summary i::after{
  content:"";position:absolute;left:0;top:6px;width:13px;height:1.5px;
  background:currentColor;transition:transform .34s var(--e-out),opacity .34s var(--ease);
}
.pk-q summary i::after{transform:rotate(90deg);}
.pk-q[open] summary i::after{transform:rotate(0);opacity:0;}
/* min-height:0 is not optional: a grid item has a min-content floor, so
   0fr collapses to the content height and the drawer never shuts */
.pk-a{display:grid;grid-template-rows:0fr;transition:grid-template-rows .36s var(--e-out);}
.pk-q[open] .pk-a{grid-template-rows:1fr;}
.pk-a p{overflow:hidden;min-height:0;padding-right:34px;font-size:13.5px;line-height:1.65;color:var(--a-mute);}
.pk-q[open] .pk-a p{padding-bottom:20px;}

/* ── close ── */
.pk-end{padding-top:40px;border-top:1px solid var(--a-line);}
.pk-end-h{
  font-size:clamp(28px,4.6vw,54px);font-weight:600;letter-spacing:-.04em;
  line-height:1.04;color:var(--a-ink);margin-bottom:20px;
}
.pk-end .pk-lede{animation:none;margin-bottom:28px;}
.pk-end-go{
  display:inline-flex;align-items:center;gap:10px;
  padding:16px 32px;border-radius:100px;
  font-size:15px;font-weight:650;letter-spacing:-.012em;
  background:var(--a-ink);color:var(--a-panel);
  transition:transform .22s var(--e-out),box-shadow .22s var(--ease);
}
.pk-end-go svg{width:15px;height:15px;transition:transform .25s var(--e-out);}
.pk-end-go:hover{transform:translateY(-2px);box-shadow:0 18px 38px -18px rgba(0,0,0,.75);}
.pk-end-go:hover svg{transform:translateX(4px);}
.pk-fine{margin-top:20px;font-size:11.5px;line-height:1.5;color:var(--a-mute);}

@media (max-width:720px){
  .pk-hero{padding:36px 0 34px;}
  .pk-grid{margin-bottom:72px;}
  .pk-find,.pk-faq{margin-bottom:72px;}
  .pk-quiz{padding:24px 20px 22px;}
}
@media (prefers-reduced-motion: reduce){
  .pk-w,.pk-eyebrow,.pk-lede,.pk-cycle,.pk-have,.pk-card,.pk-promo{animation:none;}
  [data-pk-reveal]{opacity:1;transform:none;transition:none;}
  .pk-card::after{display:none;}
  .pk-meter i{transition:none;}
}

/* Everything the plans share, said once. It used to be twenty-four lines
   spread across four cards saying the same thing four times over. */
.pk-shared{
  max-width:1180px;margin-bottom:120px;padding:15px 20px;border-radius:100px;
  background:var(--a-sunk);box-shadow:inset 0 0 0 1px var(--a-line);
  font-size:12.5px;line-height:1.6;color:var(--a-mute);
}
.pk-shared b{color:var(--a-ink);font-weight:650;margin-right:5px;}
@media (max-width:720px){
  .pk-shared{border-radius:16px;margin-bottom:72px;}
}

/* ── the standing add-on ──
   A single bar under the ladder, marked by a rule down its left edge the
   way the reference does. Zero is a real position and the bar says so
   plainly: it lights up only once you have actually asked for something. */
.pk-addon{
  max-width:1180px;margin-bottom:120px;padding:22px 24px;border-radius:18px;
  background:var(--a-panel);
  box-shadow:inset 0 0 0 1px var(--a-line),inset 3px 0 0 var(--a-line);
  transition:box-shadow .3s var(--ease),background-color .3s var(--ease);
}
.pk-addon.is-on{
  background:color-mix(in srgb,var(--vz-acc) 5%,var(--a-panel));
  box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--vz-acc) 30%,transparent),
             inset 3px 0 0 var(--vz-acc);
}
.pk-addon-h{
  display:flex;align-items:baseline;justify-content:space-between;gap:18px;
  flex-wrap:wrap;margin-bottom:16px;
}
.pk-addon-k{
  display:flex;align-items:center;gap:7px;
  font-size:11.5px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;
  color:var(--vz-acc);
}
.pk-addon-k svg{width:11px;height:11px;}
.pk-addon-t{font-size:17px;font-weight:600;letter-spacing:-.02em;color:var(--a-ink);}
.pk-addon-t b{
  margin-left:8px;font-size:26px;font-weight:650;letter-spacing:-.035em;
  color:var(--a-ink);font-variant-numeric:tabular-nums;
}
.pk-addon.is-on .pk-addon-t b{color:var(--vz-acc);}
.pk-addon-t em{font-style:normal;font-size:13px;font-weight:500;color:var(--a-mute);margin-left:3px;}

.pk-addon-row{display:flex;align-items:center;gap:16px;flex-wrap:wrap;margin-bottom:16px;}
.pk-addon-range{
  flex:1;min-width:180px;height:38px;appearance:none;background:transparent;
  cursor:pointer;display:block;
}
.pk-addon-range::-webkit-slider-runnable-track{
  height:8px;border-radius:100px;
  background:linear-gradient(90deg,var(--vz-acc) 0 var(--p),var(--a-chip-2) var(--p) 100%);
}
.pk-addon-range::-webkit-slider-thumb{
  appearance:none;width:22px;height:22px;border-radius:50%;margin-top:-7px;
  background:var(--vz-acc);box-shadow:0 2px 10px rgba(0,0,0,.45);
  transition:transform .18s var(--e-out);
}
.pk-addon-range::-webkit-slider-thumb:hover{transform:scale(1.12);}
.pk-addon-range::-moz-range-track{
  height:8px;border-radius:100px;
  background:linear-gradient(90deg,var(--vz-acc) 0 var(--p),var(--a-chip-2) var(--p) 100%);
}
.pk-addon-range::-moz-range-thumb{width:22px;height:22px;border:0;border-radius:50%;background:var(--vz-acc);}
.pk-addon-n{
  flex:none;min-width:172px;padding:10px 16px;border-radius:11px;text-align:center;
  background:var(--a-sunk);box-shadow:inset 0 0 0 1px var(--a-line);
  font-size:12.5px;color:var(--a-mute);
}
.pk-addon-n b{color:var(--a-ink);font-weight:650;font-variant-numeric:tabular-nums;}

.pk-addon-go{
  display:block;width:100%;padding:14px;border-radius:12px;cursor:pointer;
  font-family:inherit;font-size:14px;font-weight:650;letter-spacing:-.01em;
  background:var(--a-chip-2);color:color-mix(in srgb,var(--a-mute) 62%,var(--a-ink));
  transition:background-color .25s var(--ease),color .25s var(--ease),transform .2s var(--ease);
}
.pk-addon.is-on .pk-addon-go{background:var(--vz-acc);color:var(--vz-acc-ink);}
.pk-addon.is-on .pk-addon-go:hover{transform:translateY(-1px);}
.pk-addon-fine{
  display:flex;align-items:center;justify-content:space-between;gap:16px;flex-wrap:wrap;
  margin-top:12px;font-size:11.5px;color:var(--a-mute);
}
.pk-addon-fine svg{width:12px;height:12px;color:var(--vz-acc);margin-right:6px;vertical-align:-2px;}
.pk-addon-fine span{color:var(--a-mute);}

@media (max-width:720px){
  .pk-addon{margin-bottom:72px;padding:20px;}
  .pk-addon-n{min-width:0;flex:1;}
}
@media (prefers-reduced-motion: reduce){
  .pk-addon,.pk-addon-go,.pk-addon-step{transition:none;}
}

/* ── the full comparison ──
   Rules, not boxes. The header sticks because a tick in row fourteen means
   nothing once the column it belongs to has scrolled away. */
.pk-compare{margin-bottom:120px;}
/* No overflow above the width the table needs. overflow-x:auto makes the
   wrapper a scroll container on BOTH axes, and a sticky header inside one
   sticks to that container rather than to the window — which, since the
   wrapper never scrolls vertically, meant the header never stuck at all.
   Below 820px the table genuinely does not fit and scrolling is worth
   losing the sticky for. */
.pt-wrap{border-radius:18px;box-shadow:inset 0 0 0 1px var(--a-line);}
@media (max-width:820px){.pt-wrap{overflow-x:auto;}}
/* With no overflow to clip them, the corner cells carry the radius */
.pt thead th:first-child{border-top-left-radius:18px;}
.pt thead th:last-child{border-top-right-radius:18px;}
.pt tbody tr:last-child th{border-bottom-left-radius:18px;}
.pt tbody tr:last-child td:last-child{border-bottom-right-radius:18px;}
.pt{width:100%;border-collapse:collapse;min-width:720px;background:var(--a-panel);}

.pt thead th{
  position:sticky;top:0;z-index:2;
  padding:20px 18px;text-align:center;vertical-align:top;
  background:var(--a-sunk);border-bottom:1px solid var(--a-line);
}
.pt-corner{
  text-align:left !important;
  font-size:11px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;
  color:var(--a-mute);
}
.pt thead th.is-best{background:color-mix(in srgb,var(--vz-acc) 9%,var(--a-sunk));}
.pt thead .pk-tag{display:inline-block;margin-bottom:8px;}
.pt-name{display:block;font-size:17px;font-weight:600;letter-spacing:-.02em;color:var(--a-ink);}
.pt-price{
  display:block;margin-top:4px;font-size:13.5px;font-weight:600;color:var(--a-ink);
  font-variant-numeric:tabular-nums;
}
/* mute at 11.5px on the table header ground measured 4.36:1 in the light
   theme — under 4.5 */
.pt-price em{
  font-style:normal;font-size:11.5px;font-weight:400;
  color:color-mix(in srgb,var(--a-mute) 70%,var(--a-ink));
}
.pt-go{
  margin-top:11px;padding:8px 16px;border-radius:100px;cursor:pointer;
  font-family:inherit;font-size:12.5px;font-weight:650;
  background:var(--a-chip-2);color:var(--a-ink);
  transition:background-color .2s var(--ease),transform .18s var(--ease);
}
.pt-go:hover{transform:translateY(-1px);}
.pt thead th.is-best .pt-go{background:var(--vz-acc);color:var(--vz-acc-ink);}

/* a band that names the group, so fifteen rows read as three sets */
.pt-group th{
  padding:16px 18px 9px;text-align:left;
  font-size:10px;font-weight:700;letter-spacing:.15em;text-transform:uppercase;
  color:var(--a-mute);background:var(--a-sunk);
}
.pt tbody tr:not(.pt-group){border-top:1px solid var(--a-line);}
.pt tbody tr:not(.pt-group):hover{background:var(--a-chip);}
.pt tbody th[scope="row"]{
  padding:14px 18px;text-align:left;font-size:13.5px;font-weight:500;color:var(--a-ink);
}
.pt tbody td{
  padding:14px 18px;text-align:center;font-size:13.5px;color:var(--a-mute);
  font-variant-numeric:tabular-nums;
}
.pt tbody td b{color:var(--a-ink);font-weight:650;}
.pt-y,.pt-n{display:inline-grid;place-items:center;width:18px;height:18px;}
.pt-y{color:var(--vz-acc);}
.pt-n{color:var(--a-mute);opacity:.5;}
.pt-y svg,.pt-n svg{width:14px;height:14px;}

@media (max-width:720px){
  .pk-compare{margin-bottom:72px;}
  .pt thead th{padding:16px 12px;}
  .pt tbody th[scope="row"],.pt tbody td{padding:12px;font-size:12.5px;}
}

/* a conversion line for something the plan does not carry — stated, not
   dressed up as a number */

/* Marks along the range. Three and a half orders of magnitude is a lot of
   travel for a thumb, so the sizes people actually ask for are one click. */
.pk-addon-steps{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:16px;}
.pk-addon-step{
  padding:6px 13px;border-radius:100px;cursor:pointer;
  font-family:inherit;font-size:11.5px;font-weight:600;
  font-variant-numeric:tabular-nums;
  color:color-mix(in srgb,var(--a-mute) 62%,var(--a-ink));
  background:transparent;box-shadow:inset 0 0 0 1px var(--a-line);
  transition:color .2s var(--ease),box-shadow .2s var(--ease),background-color .2s var(--ease);
}
.pk-addon-step:hover{color:var(--a-ink);box-shadow:inset 0 0 0 1px var(--a-mute);}
.pk-addon-step.is-on{background:var(--vz-acc);color:var(--vz-acc-ink);box-shadow:none;}

/* ══ SHOTS — one photo in, nine angles out ══════
   Three steps, one decision at a time. The stepper is the only thing that
   survives all three, so it is what says where you are. */
.pg{display:block;max-width:560px;margin:0 auto;}
.pg:focus{outline:none;}

.pg-nav{position:relative;display:flex;align-items:center;justify-content:center;margin-bottom:30px;}
.pg-back{
  position:absolute;left:0;display:grid;place-items:center;
  width:30px;height:30px;border:0;border-radius:50%;cursor:pointer;
  background:transparent;color:var(--a-mute);
  transition:background-color .2s var(--e-out),color .2s var(--e-out);
}
.pg-back svg{width:17px;height:17px;}
.pg-back:hover{background:var(--a-chip);color:var(--a-ink);}

.pg-steps{display:flex;align-items:center;gap:10px;list-style:none;margin:0;padding:0;}
.pg-step{
  display:flex;align-items:center;gap:8px;
  font-size:13px;font-weight:500;color:var(--a-mute);
  transition:color .25s var(--e-out);
}
/* the rule between two steps, drawn by the one that follows */
.pg-step + .pg-step::before{
  content:'';width:40px;height:1px;background:var(--a-line);margin-right:2px;
}
.pg-step-n{
  display:grid;place-items:center;width:22px;height:22px;border-radius:50%;
  font-size:11.5px;font-weight:600;font-variant-numeric:tabular-nums;
  color:var(--a-mute);background:var(--a-chip);
  transition:background-color .25s var(--e-out),color .25s var(--e-out);
}
.pg-step.is-on{color:var(--a-ink);}
.pg-step.is-on .pg-step-n{background:var(--vz-acc);color:var(--vz-acc-ink);}
.pg-step.is-done .pg-step-n{
  background:color-mix(in srgb,var(--vz-acc) 30%,transparent);color:var(--a-ink);
}
@media (max-width:560px){
  .pg-step + .pg-step::before{width:14px;}
  .pg-step{font-size:12px;}
}

/* ── step one ── */
.pg-intro{
  display:flex;flex-direction:column;align-items:center;text-align:center;
  max-width:520px;margin:0 auto;padding:34px 30px 28px;border-radius:22px;
  background:var(--a-panel);box-shadow:inset 0 0 0 1px var(--a-line);
  transition:box-shadow .2s var(--e-out),background-color .2s var(--e-out);
}
.pg-intro.is-over{
  background:color-mix(in srgb,var(--vz-acc) 8%,var(--a-panel));
  box-shadow:inset 0 0 0 2px var(--vz-acc);
}
/* three frames fanned out: the tool showing its own output rather than
   describing it */
.pg-intro-demo{display:flex;gap:8px;margin-bottom:22px;}
.pg-intro-demo img{
  width:84px;height:auto;border-radius:10px;display:block;
  box-shadow:0 8px 24px rgba(0,0,0,.35);
}
.pg-intro-demo img:first-child{transform:rotate(-4deg);}
.pg-intro-demo img:last-child{transform:rotate(4deg);}
.pg-intro-h{font-size:30px;font-weight:600;letter-spacing:.06em;color:var(--a-ink);}
.pg-intro-p{max-width:38ch;margin-top:10px;font-size:13.5px;line-height:1.62;color:var(--a-mute);}
.pg-upload{
  display:flex;align-items:center;justify-content:center;gap:10px;
  width:100%;margin-top:22px;padding:15px 24px;border:0;border-radius:14px;
  font-family:inherit;font-size:15px;font-weight:600;cursor:pointer;
  background:var(--a-btn);color:var(--a-btn-ink);
  transition:transform .12s var(--e-out),opacity .2s var(--e-out);
}
.pg-upload svg{width:17px;height:17px;}
.pg-upload:hover{opacity:.9;}
.pg-upload:active{transform:scale(.985);}
.pg-fine{margin-top:14px;font-size:11.5px;line-height:1.5;color:var(--a-mute);}

/* ── photo in hand, nothing spent ──
   No card here. The picture is the subject of this step, so it sits on
   the page at the size it deserves and the controls line up under it,
   rather than the photo shrinking to a thumbnail so a panel can fit. */
.pg-stage{display:flex;flex-direction:column;align-items:center;}
.pg-stage-frame{
  margin:0;border-radius:18px;overflow:hidden;line-height:0;
  background:var(--a-chip);box-shadow:0 24px 60px rgba(0,0,0,.45);
}
.pg-stage-img{
  display:block;width:auto;height:auto;
  max-width:min(440px,100%);max-height:52vh;object-fit:contain;
}
.pg-stage-meta{
  display:flex;align-items:baseline;justify-content:center;gap:9px;
  margin-top:13px;text-align:center;
}
.pg-stage-meta b{font-size:13.5px;font-weight:600;color:var(--a-ink);}
.pg-stage-meta em{
  font-style:normal;font-size:11.5px;color:var(--a-mute);
  font-variant-numeric:tabular-nums;
}

/* quality, size, spend — one line, the money on the right */
.pg-bar{
  display:flex;align-items:center;justify-content:center;
  flex-wrap:wrap;gap:14px;margin-top:24px;
}
.pg-bar-opts{display:flex;align-items:center;flex-wrap:wrap;gap:8px;}
/* the chips were built to stack, so undo the stacking margins here */
.pg-bar .pg-res{margin-top:0;}
.pg-go{
  display:inline-flex;align-items:center;justify-content:center;gap:9px;
  padding:14px 30px;border:0;border-radius:14px;cursor:pointer;
  font-family:inherit;font-size:15px;font-weight:600;
  background:var(--a-btn);color:var(--a-btn-ink);
  transition:transform .12s var(--e-out),opacity .2s var(--e-out);
}
.pg-go:hover{opacity:.9;}
.pg-go:active{transform:scale(.985);}
.pg-go b{font-variant-numeric:tabular-nums;}
.pg-go .pg-star{color:currentColor;}

@media (max-width:620px){
  .pg-bar{flex-direction:column;gap:12px;}
  .pg-go{width:100%;}
}
.pg-upload .pg-star{color:currentColor;}
.pg-upload b{font-variant-numeric:tabular-nums;}
.pg-swap{
  margin-top:12px;padding:6px 4px;border:0;background:transparent;cursor:pointer;
  font-family:inherit;font-size:12.5px;color:var(--a-mute);
  text-decoration:underline;text-underline-offset:3px;
  transition:color .2s var(--e-out);
}
.pg-swap:hover{color:var(--a-ink);}

.pg-engines{display:flex;gap:5px;}
.pg-engines-c{margin-top:16px;justify-content:center;}
.pg-engine{
  display:flex;flex-direction:column;gap:1px;padding:6px 12px;
  border:0;border-radius:10px;cursor:pointer;text-align:left;
  font-family:inherit;background:var(--a-chip);color:var(--a-ink);
  box-shadow:inset 0 0 0 1px transparent;
  transition:box-shadow .2s var(--e-out),background-color .2s var(--e-out);
}
.pg-engine b{font-size:12px;font-weight:600;}
.pg-engine em{font-style:normal;font-size:10px;color:var(--a-mute);}
.pg-engine:hover:not(:disabled){box-shadow:inset 0 0 0 1px var(--a-mute);}
/* a tier this plan cannot run: shown, dimmed, wearing a lock and the
   name of the plan that unlocks it */
.pg-engine.is-locked{opacity:.45;}
.pg-engine.is-locked:hover:not(:disabled){opacity:.7;box-shadow:inset 0 0 0 1px var(--a-line);}
.pg-engine.is-locked .pg-engine-c{display:flex;align-items:center;gap:4px;}
.pg-lock{width:11px;height:11px;}
.pg-engine.is-on{
  background:color-mix(in srgb,var(--vz-acc) 14%,var(--a-chip));
  box-shadow:inset 0 0 0 1.5px var(--vz-acc);
}

/* ── the contact sheet ──
   One block, not nine cards. Nine framed tiles read as nine separate
   things; butted together with the corners rounded only on the outside
   they read as one sheet, which is what they are. */
.pg-grid{
  display:grid;grid-template-columns:repeat(3,1fr);gap:2px;
  border-radius:16px;overflow:hidden;background:var(--a-line);
}
.pg-grid-up{grid-template-columns:repeat(auto-fit,minmax(min(170px,100%),1fr));}

.pg-cell{
  position:relative;display:flex;align-items:center;justify-content:center;
  width:100%;aspect-ratio:1/1.42;padding:0;border:0;margin:0;
  overflow:hidden;cursor:pointer;background:var(--a-chip);
  transition:transform .18s var(--e-out);
}
.pg-cell img{width:100%;height:100%;object-fit:cover;display:block;}
div.pg-cell{cursor:default;flex-direction:column;gap:9px;}
.pg-cell.is-blank{background:var(--a-panel);}

/* the label costs nothing until it is wanted */
.pg-lab{
  position:absolute;left:0;right:0;bottom:0;padding:22px 10px 8px;
  font-size:11px;font-weight:600;color:#fff;text-align:left;
  background:linear-gradient(to top,rgba(0,0,0,.72),transparent);
  opacity:0;transition:opacity .2s var(--e-out);
}
.pg-cell:hover .pg-lab,.pg-cell:focus-visible .pg-lab{opacity:1;}

.pg-tick{
  position:absolute;top:9px;right:9px;width:21px;height:21px;border-radius:50%;
  background:var(--vz-acc);opacity:0;transform:scale(.7);
  transition:opacity .18s var(--e-out),transform .18s var(--e-out);
}
.pg-tick::after{
  content:'';position:absolute;left:7px;top:5px;width:5px;height:9px;
  border:solid var(--vz-acc-ink);border-width:0 2px 2px 0;transform:rotate(45deg);
}
.pg-cell.is-picked .pg-tick{opacity:1;transform:scale(1);}
/* Inset rather than a border: an outline on a gapless grid would be half
   covered by the neighbour it shares an edge with. */
.pg-cell.is-picked::after{
  content:'';position:absolute;inset:0;pointer-events:none;
  box-shadow:inset 0 0 0 3px var(--vz-acc);
}

.pg-wait{
  width:32px;height:32px;border-radius:50%;
  background:color-mix(in srgb,var(--a-mute) 35%,transparent);
}
[data-pg-spin]{animation:pgPulse 1.5s ease-in-out infinite;}
@keyframes pgPulse{0%,100%{opacity:.35;}50%{opacity:.9;}}
@media (prefers-reduced-motion:reduce){[data-pg-spin]{animation:none;}}

.pg-fail{
  padding:0 14px;text-align:center;font-size:11.5px;line-height:1.45;
  color:var(--a-danger,#e0364a);
}
.pg-retry{
  padding:5px 12px;border:0;border-radius:100px;cursor:pointer;
  font-family:inherit;font-size:11.5px;font-weight:600;
  background:var(--a-btn);color:var(--a-btn-ink);
}

/* ── what to do next, and the tools to do it ── */
.pg-hint{
  margin:22px 0 14px;text-align:center;
  font-size:13px;color:var(--a-mute);font-variant-numeric:tabular-nums;
}
.pg-tools{display:flex;align-items:stretch;gap:9px;}
.pg-tool{
  display:flex;align-items:center;justify-content:center;gap:8px;
  flex:none;padding:0 16px;min-height:52px;min-width:52px;
  border:0;border-radius:14px;cursor:pointer;
  font-family:inherit;font-size:14px;font-weight:600;
  background:var(--a-chip);color:var(--a-ink);
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:box-shadow .2s var(--e-out),background-color .2s var(--e-out),transform .12s var(--e-out);
}
.pg-tool svg{width:18px;height:18px;flex:none;}
.pg-tool:hover:not(:disabled){box-shadow:inset 0 0 0 1px var(--a-mute);}
.pg-tool:active:not(:disabled){transform:scale(.985);}
.pg-tool:disabled{opacity:.4;cursor:default;}
/* the one that costs money is the wide one */
.pg-tool-main{flex:1;}

.pg-star{width:13px;height:13px;color:var(--vz-acc);}
.pg-tool-main b{font-variant-numeric:tabular-nums;}

@media (max-width:560px){
  .pg-tools{flex-wrap:wrap;}
  .pg-tool-main{min-width:100%;order:-1;}
}

/* ── Shots keeps its own header size ──
   .hub-title is 34–52px because it heads five pages whose whole content is
   a headline and a form. This page's content is a nine-frame contact
   sheet, and a title that size took a third of the screen before the
   sheet started. Scoped to this page so the other four are untouched. */
[data-tool="gallery"] .ut-head{margin-bottom:22px;}
[data-tool="gallery"] .hub-title{
  font-size:clamp(24px,2.6vw,30px);
  letter-spacing:-.028em;
}
[data-tool="gallery"] .hub-sub{font-size:13.5px;max-width:52ch;}

/* ── 1K or 2K ── */
.pg-res{display:flex;align-items:center;gap:6px;margin-top:12px;}
.pg-resb{
  padding:5px 14px;border:0;border-radius:100px;cursor:pointer;
  font-family:inherit;font-size:12px;font-weight:600;
  font-variant-numeric:tabular-nums;
  background:var(--a-chip);color:var(--a-ink);
  box-shadow:inset 0 0 0 1px transparent;
  transition:box-shadow .2s var(--e-out),background-color .2s var(--e-out);
}
.pg-resb:hover:not(:disabled){box-shadow:inset 0 0 0 1px var(--a-mute);}
.pg-resb.is-on{
  background:color-mix(in srgb,var(--vz-acc) 14%,var(--a-chip));
  box-shadow:inset 0 0 0 1.5px var(--vz-acc);
}
.pg-resb:disabled{opacity:.4;cursor:default;}
.pg-res-n{font-size:11px;color:var(--a-mute);}

/* ── what the wizard gives back ──
   The summary panel used to be the last thing a run produced, because a
   run produced nothing. Now it holds the frame that came back. */
.app-out{
  margin:0;display:flex;flex-direction:column;align-items:center;gap:10px;
  padding:18px;border-radius:16px;
  background:var(--a-chip);box-shadow:inset 0 0 0 1px var(--a-line);
}
.app-out img{
  display:block;max-width:100%;max-height:min(62vh,620px);
  width:auto;height:auto;border-radius:11px;
}
.app-out figcaption{font-size:11.5px;color:var(--a-mute);font-variant-numeric:tabular-nums;}
.app-out.is-wait,.app-out.is-fail{min-height:200px;justify-content:center;text-align:center;}
.app-out.is-wait p,.app-out.is-fail p{font-size:13px;line-height:1.55;color:var(--a-mute);max-width:38ch;}
.app-out.is-fail p{color:var(--a-danger,#e0364a);}
/* the old dot lived here */

.app-out-acts{display:flex;gap:9px;justify-content:center;margin-top:14px;flex-wrap:wrap;}
.app-mini{
  display:inline-flex;align-items:center;justify-content:center;
  padding:9px 18px;border:0;border-radius:100px;cursor:pointer;
  font-family:inherit;font-size:13px;font-weight:600;text-decoration:none;
  background:var(--a-chip);color:var(--a-ink);
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:box-shadow .2s var(--e-out),background-color .2s var(--e-out);
}
.app-mini:hover{box-shadow:inset 0 0 0 1px var(--a-mute);}

/* The summary is a grid of selection cards, and a result dropped into it
   becomes two more cells — which is how the actions ended up as tall
   pills either side of the picture. A result takes the whole width. */
.app-summary-grid > .app-out,
.app-summary-grid > .app-out-acts,
.app-summary-grid > .app-out-set,
.app-summary-grid > .app-out-note{grid-column:1 / -1;}
.app-out-acts .app-mini{flex:none;}

/* ── waiting, shaped like the picture that is coming ──
   Drawn at the aspect the reader chose, so the space is reserved and the
   frame does not jump when the image lands. A light sweeps across it
   rather than a dot pulsing in the middle: the eye reads a sweep as
   progress and a pulse as a heartbeat. */
.app-out-frame{
  position:relative;overflow:hidden;
  width:min(100%,300px);border-radius:12px;
  background:var(--a-panel);
  box-shadow:inset 0 0 0 1px var(--a-line);
}
.app-out-sweep{
  position:absolute;inset:0;
  background:linear-gradient(105deg,
    transparent 30%,
    color-mix(in srgb,var(--a-ink) 9%,transparent) 48%,
    color-mix(in srgb,var(--a-ink) 14%,transparent) 52%,
    transparent 70%);
  transform:translateX(-100%);
  animation:appSweep 1.7s cubic-bezier(.4,0,.25,1) infinite;
}
@keyframes appSweep{to{transform:translateX(100%);}}

/* Corner ticks, so an empty rectangle reads as a viewfinder rather than a
   box that failed to load. */
.app-out-frame::before,
.app-out-frame::after{
  content:'';position:absolute;width:16px;height:16px;
  border:1.5px solid color-mix(in srgb,var(--a-mute) 45%,transparent);
}
.app-out-frame::before{top:12px;left:12px;border-right:0;border-bottom:0;border-radius:3px 0 0 0;}
.app-out-frame::after{bottom:12px;right:12px;border-left:0;border-top:0;border-radius:0 0 3px 0;}

@media (prefers-reduced-motion:reduce){
  .app-out-sweep{animation:none;opacity:.5;transform:none;}
}

/* ── the ring and the line, inside the frame ──
   Under the frame they read as a caption beneath an empty box. Inside it,
   the box is plainly the thing being worked on. */
.app-out-mid{
  position:absolute;inset:0;z-index:1;
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:14px;
  padding:0 26px;text-align:center;
}
.app-out-mid p{font-size:12.5px;line-height:1.5;color:var(--a-mute);max-width:26ch;}

/* One arc of a circle, turning. The track behind it keeps the shape read
   as a ring rather than a comet. */
.app-out-ring{
  width:30px;height:30px;border-radius:50%;flex:none;
  border:2.5px solid color-mix(in srgb,var(--a-mute) 28%,transparent);
  border-top-color:var(--vz-acc);
  animation:appSpin .8s linear infinite;
}
@keyframes appSpin{to{transform:rotate(360deg);}}
@media (prefers-reduced-motion:reduce){
  .app-out-ring{animation-duration:2.4s;}
}

/* ── a result per photo ──
   One upload, one frame back. The set is a grid so five photos come back
   as five, not as one picture that blended them. */
.app-out-set{
  display:grid;gap:12px;
  grid-template-columns:repeat(auto-fill,minmax(min(190px,100%),1fr));
}
.app-out-cell{margin:0;display:flex;flex-direction:column;gap:7px;}
.app-out-cell a{display:block;border-radius:12px;overflow:hidden;}
.app-out-cell img{display:block;width:100%;height:auto;border-radius:12px;}
.app-out-cell figcaption{
  font-size:11px;color:var(--a-mute);font-variant-numeric:tabular-nums;padding:0 2px;
}
.app-out-cell.is-fail{
  min-height:180px;align-items:center;justify-content:center;text-align:center;
  padding:16px;border-radius:12px;background:var(--a-chip);
  box-shadow:inset 0 0 0 1px var(--a-line);
}
.app-out-cell.is-fail p{font-size:12px;line-height:1.5;color:var(--a-danger,#e0364a);}
.app-out-note{
  margin-top:14px;text-align:center;
  font-size:12.5px;color:var(--a-mute);font-variant-numeric:tabular-nums;
}
/* the waiting frame is a cell now, so it fills its column */
.app-out-cell .app-out-frame{width:100%;}

/* ── the optional line ──
   Sits under the summary, above the price: the last thing read before the
   button, which is where an afterthought belongs. */
.app-ask{
  display:block;max-width:560px;margin:18px auto 0;
}
.app-ask-h{
  display:flex;align-items:center;gap:8px;margin-bottom:8px;
  font-size:12.5px;font-weight:600;color:var(--a-ink);
}
.app-ask-h em{
  font-style:normal;font-size:10.5px;font-weight:500;letter-spacing:.06em;
  text-transform:uppercase;color:var(--a-mute);
  padding:2px 7px;border-radius:100px;background:var(--a-chip);
}
.app-ask-in{
  display:block;width:100%;resize:vertical;min-height:56px;
  padding:11px 13px;border:0;border-radius:12px;
  font-family:inherit;font-size:13.5px;line-height:1.5;
  color:var(--a-ink);background:var(--a-chip);
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:box-shadow .2s var(--e-out);
}
.app-ask-in::placeholder{color:var(--a-mute);}
.app-ask-in:focus{outline:none;box-shadow:inset 0 0 0 1.5px var(--vz-acc);}

/* ── the dry-run bar ──
   A test mode you forget you left on is a bug generator, so this is not
   subtle and it does not scroll away. */
[data-dry-bar]{
  position:fixed;left:0;right:0;bottom:0;z-index:9000;
  display:flex;align-items:center;justify-content:center;gap:14px;flex-wrap:wrap;
  padding:9px 16px;
  font-size:12.5px;color:#160f00;
  background:#f5c518;box-shadow:0 -6px 20px rgba(0,0,0,.28);
}
[data-dry-bar] b{font-weight:700;}
[data-dry-bar] button{
  padding:5px 13px;border:0;border-radius:100px;cursor:pointer;
  font-family:inherit;font-size:12px;font-weight:600;
  background:#160f00;color:#f5c518;
}

/* the price rides under the model name, so a tier reads name / engine / cost */
.pg-engine{align-items:flex-start;}
.pg-engine-c{
  display:flex;align-items:center;gap:3px;margin-top:3px;
  font-size:11px;font-weight:600;font-variant-numeric:tabular-nums;
  color:var(--a-mute);
}
.pg-engine.is-on .pg-engine-c{color:var(--a-ink);}
.pg-engine-c .pg-star{width:10px;height:10px;color:var(--vz-acc);}


/* ── a toggle says what it toggles ──
   Label above, value below: the same shape the quality tiers use, so the
   bar reads as settings rather than as three unrelated words. */
.pg-tool-pick{
  flex-direction:column;align-items:flex-start;justify-content:center;
  gap:1px;padding:0 14px;
}
.pg-tool-pick em{
  font-style:normal;font-size:9.5px;font-weight:600;letter-spacing:.09em;
  text-transform:uppercase;color:var(--a-mute);line-height:1.1;
}
.pg-tool-pick b{font-size:13.5px;font-weight:600;line-height:1.2;font-variant-numeric:tabular-nums;}
.pg-tool-c{
  display:flex;align-items:center;gap:3px;
  font-size:10px;font-weight:600;color:var(--a-mute);
  font-variant-numeric:tabular-nums;line-height:1.1;
}
.pg-tool-c .pg-star{width:9px;height:9px;color:var(--vz-acc);}
@media (max-width:560px){.pg-tool-pick{flex:1;}}

/* ══ upscale ══════════════════════════════════
   One job, so one screen: what you dropped, how much bigger, and go. */
[data-tool="upscale"] .ut-head,
[data-tool="enhance"] .ut-head{margin-bottom:22px;}
[data-tool="upscale"] .hub-title,
[data-tool="enhance"] .hub-title{font-size:clamp(24px,2.6vw,30px);letter-spacing:-.028em;}
[data-tool="upscale"] .hub-sub,
[data-tool="enhance"] .hub-sub{font-size:13.5px;max-width:52ch;}

.up{display:block;max-width:900px;margin:0 auto;}

.up-drop{
  display:flex;flex-direction:column;align-items:center;text-align:center;gap:10px;
  padding:56px 28px;border-radius:20px;
  background:var(--a-panel);box-shadow:inset 0 0 0 1px var(--a-line);
  transition:box-shadow .2s var(--e-out),background-color .2s var(--e-out);
}
.up-drop.is-over{
  background:color-mix(in srgb,var(--vz-acc) 8%,var(--a-panel));
  box-shadow:inset 0 0 0 2px var(--vz-acc);
}
.up-drop-ic{width:30px;height:30px;color:var(--a-mute);}
.up-drop-ic svg{width:100%;height:100%;}
.up-drop h2{font-size:19px;font-weight:600;color:var(--a-ink);}
.up-drop p{max-width:46ch;font-size:13.5px;line-height:1.6;color:var(--a-mute);}

.up-btn{
  margin-top:8px;padding:12px 22px;border:0;border-radius:12px;cursor:pointer;
  font-family:inherit;font-size:14px;font-weight:600;
  background:var(--a-chip);color:var(--a-ink);
  box-shadow:inset 0 0 0 1px var(--a-line);
}
.up-btn.is-solid{background:var(--a-btn);color:var(--a-btn-ink);box-shadow:none;}

/* auto-FIT, not auto-fill: with two photos the row was three empty
   columns wide and everything sat jammed against the left. fit collapses
   the empty tracks so the set stays centred whatever its size. */
/* Narrow enough that a full set of nine lands in two rows instead of
   three — the whole tray has to be visible at once or the count at the
   bottom is describing something off screen. These are thumbnails of what
   you dropped, not the output; the result opens full size on click. */
.up-grid{
  display:grid;gap:12px;justify-content:center;
  grid-template-columns:repeat(auto-fit,minmax(140px,168px));
}
.up-shot{margin:0;display:flex;flex-direction:column;gap:7px;}
.up-shot-hit{
  position:relative;display:flex;align-items:center;justify-content:center;
  width:100%;aspect-ratio:1/1.3;padding:0;border:0;overflow:hidden;
  border-radius:12px;background:var(--a-chip);cursor:pointer;
  box-shadow:inset 0 0 0 1px var(--a-line);
}
div.up-shot-hit{cursor:default;}
.up-shot-hit img{width:100%;height:100%;object-fit:cover;display:block;}
.up-shot-hit.is-fail span{padding:0 14px;text-align:center;font-size:11.5px;line-height:1.45;color:var(--a-danger,#e0364a);}
.up-shot figcaption{display:flex;flex-direction:column;gap:1px;padding:0 2px;}
.up-shot figcaption b{
  font-size:11.5px;font-weight:600;color:var(--a-ink);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.up-shot figcaption em{font-style:normal;font-size:10.5px;color:var(--a-mute);font-variant-numeric:tabular-nums;}

.up-x{
  position:absolute;top:7px;right:7px;width:22px;height:22px;
  display:grid;place-items:center;border:0;border-radius:50%;cursor:pointer;
  font-size:11px;background:rgba(8,7,6,.72);color:#fff;
  opacity:0;transition:opacity .18s var(--e-out);
}
.up-shot-hit:hover .up-x{opacity:1;}

.up-ring{
  width:26px;height:26px;border-radius:50%;
  border:2.5px solid color-mix(in srgb,var(--a-mute) 28%,transparent);
  border-top-color:var(--vz-acc);
  animation:appSpin .8s linear infinite;
}
@media (prefers-reduced-motion:reduce){.up-ring{animation-duration:2.4s;}}

.up-add{
  display:grid;place-items:center;aspect-ratio:1/1.3;
  border:1.5px dashed var(--a-line);border-radius:12px;cursor:pointer;
  font-size:22px;background:transparent;color:var(--a-mute);
  transition:border-color .2s var(--e-out),color .2s var(--e-out);
}
.up-add:hover{border-color:var(--a-mute);color:var(--a-ink);}

.up-hint{
  margin:20px 0 14px;text-align:center;
  font-size:13px;color:var(--a-mute);font-variant-numeric:tabular-nums;
}
.up-tools{display:flex;gap:9px;justify-content:center;flex-wrap:wrap;}
.up-tool{
  display:flex;flex-direction:column;align-items:flex-start;justify-content:center;gap:1px;
  min-height:50px;padding:0 16px;border:0;border-radius:13px;cursor:pointer;
  font-family:inherit;font-size:13.5px;font-weight:600;
  background:var(--a-chip);color:var(--a-ink);
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:box-shadow .2s var(--e-out);
}
.up-tool:hover:not(:disabled){box-shadow:inset 0 0 0 1px var(--a-mute);}
.up-tool:disabled{opacity:.4;cursor:default;}
.up-tool em{
  font-style:normal;font-size:9.5px;font-weight:600;letter-spacing:.09em;
  text-transform:uppercase;color:var(--a-mute);line-height:1.1;
}
.up-tool.is-solid{
  flex-direction:row;align-items:center;gap:7px;
  background:var(--a-btn);color:var(--a-btn-ink);box-shadow:none;
}
.up-tool-main{min-width:190px;justify-content:center;}
.up-star{width:12px;height:12px;color:currentColor;}
.up-tool b{font-variant-numeric:tabular-nums;}

/* ── the caption carries three facts, so it needs three lines ── */
.up-shot figcaption{gap:3px;}
.up-name{
  font-size:11.5px;font-weight:600;color:var(--a-ink);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.up-dim{font-size:11px;color:var(--a-mute);font-variant-numeric:tabular-nums;}
.up-dim b{color:var(--a-ink);font-weight:600;}
.up-cost{
  display:flex;align-items:center;gap:3px;
  font-size:11px;font-weight:600;color:var(--a-mute);font-variant-numeric:tabular-nums;
}
.up-cost .up-star{width:10px;height:10px;color:var(--vz-acc);}
.up-over{color:var(--a-danger,#e0364a);}
.up-shot.is-over .up-shot-hit{box-shadow:inset 0 0 0 1.5px var(--a-danger,#e0364a);}

/* the add tile should not weigh as much as a photograph */
.up-add{aspect-ratio:1/1.3;font-size:20px;opacity:.7;}
.up-add:hover{opacity:1;}

/* ── the tool should fit the screen it opens on ──
   Remove Background put a 52px headline, a 74vh stage and a four-card
   demo on one page, which came to 1,565px against a 1,274px window: you
   arrived at a tool and had to scroll to see it work. The headline is the
   cheapest thing to shrink — it is the same six words at any size — and
   the stage gives back the rest.

   Scoped per tool rather than to .ut-*, which Resize also uses and which
   has its own arithmetic. */
[data-tool="removebg"] .ut-head{margin-bottom:22px;}
[data-tool="removebg"] .hub-title{
  font-size:clamp(24px,2.6vw,30px);
  letter-spacing:-.028em;
}
[data-tool="removebg"] .hub-sub{font-size:13.5px;max-width:56ch;}
[data-tool="removebg"] .ut-stage{height:clamp(380px,calc(100vh - 268px),760px);}
[data-tool="removebg"] .ut-demo{padding-top:26px;}
[data-tool="removebg"] .ut-demo-sub{padding:6px 0 16px;}

/* smaller tiles need smaller type under them */
.up-name{font-size:11px;}
.up-dim,.up-cost{font-size:10.5px;}
.up-shot-hit{aspect-ratio:1/1.25;}
.up-add{aspect-ratio:1/1.25;}

/* ── Resize, same arithmetic as Remove Background ──
   167px of headline, a 74vh stage and a 599px demo clip came to 1,560px
   in a 1,274px window. The clip is the biggest single piece and the one
   that matters least on arrival: it shows what the tool does, which the
   stage right above it is about to do for real. */
[data-tool="resize"] .ut-head{margin-bottom:22px;}
[data-tool="resize"] .hub-title{font-size:clamp(24px,2.6vw,30px);letter-spacing:-.028em;}
[data-tool="resize"] .hub-sub{font-size:13.5px;max-width:56ch;}
[data-tool="resize"] .ut-stage{height:min(40vh,495px);}
[data-tool="resize"] .ut-demo{padding-top:24px;}
[data-tool="resize"] .ut-demo-sub{padding:6px 0 14px;}
[data-tool="resize"] .ut-demo-v{max-width:560px;}

/* ── Motion Control on one screen ──
   231px of header above a tool whose two inputs are the whole point, and
   a 478px sample strip under it: 1,462px in a 1,274px window. The
   headline is two lines at 50px for no reason other than that there was
   room — there is not. */
[data-tool="motion"] .mc-head,
.mc-head{margin-bottom:26px;}
.mc-h1{font-size:clamp(26px,3.2vw,34px);}
.mc-head .mc-sub{font-size:13.5px;}
.mc-kicker{margin-bottom:9px;}

/* Five 9:16 clips across the full column came out 409px tall each — a
   sample strip taller than the tool it illustrates. Narrowing the strip
   keeps all five and takes back 200px of page. */

/* Resize: the side panel is taller than the stage, so the grid no longer
   shrinks with it — the last thirty pixels have to come from the demo. */
[data-tool="resize"] .ut-demo{padding-top:18px;}
[data-tool="resize"] .ut-demo-v{max-width:500px;}

/* The two input slots are the tool. 443px each was generous rather than
   necessary, and the 56px gap under the settings row was the largest gap
   on a page that had run out of room. */
.mc-slot{min-height:0;}
.mc-flow{margin-bottom:24px;max-width:960px;margin-left:auto;margin-right:auto;}
.mc-set{margin-bottom:30px;}

/* ── Shots and Upscale sit in the middle ──
   Both open with one card and nothing else, and a card pinned under a
   left-aligned headline left two thirds of the screen empty below it. A
   tool whose whole content is one panel should have that panel where the
   eye already is.

   Centred with flex rather than a fixed offset, so a full tray — nine
   frames and a toolbar — still grows downward instead of being cut. */
[data-tool="gallery"] .ut-main,
[data-tool="upscale"] .ut-main{
  display:flex;align-items:center;
  min-height:calc(100vh - var(--anav-h,61px));
  padding-top:22px;padding-bottom:100px;
}
[data-tool="gallery"] .ut-main > .container,
[data-tool="upscale"] .ut-main > .container{width:100%;}
[data-tool="gallery"] .ut-head,
[data-tool="upscale"] .ut-head,
[data-tool="resize"] .ut-head{
  text-align:center;margin-left:auto;margin-right:auto;
}
[data-tool="gallery"] .hub-sub,
[data-tool="upscale"] .hub-sub,
[data-tool="resize"] .hub-sub{margin-left:auto;margin-right:auto;}

/* ── the empty state, laid out sideways on a wide screen ──
   Centred vertically, the opening card became a small island: 520px of
   content in the middle of a 2,000px window with nothing either side.
   Widening it alone would just be a bigger island, so above 880px the
   card turns on its side — the sample frames hold the left, the words and
   the button the right, and the block reads as one composition instead of
   a stack floating in the dark.

   Grid with named areas rather than flex-direction:row: these cards have
   five or six children, and a row would simply line all of them up.
   Below 880px it stays the column it already was; a phone has no width
   to spend on this. */
@media (min-width:880px){
  [data-tool="gallery"] .pg,
  [data-tool="upscale"] .up{max-width:880px;}

  .pg-intro{
    display:grid;align-items:center;justify-items:start;text-align:left;
    grid-template-columns:auto minmax(0,1fr);
    grid-template-areas:
      "demo title"
      "demo blurb"
      "demo cta"
      "demo fine";
    column-gap:46px;row-gap:0;
    max-width:880px;padding:40px 46px;
  }
  .pg-intro-demo{grid-area:demo;margin-bottom:0;}
  .pg-intro-demo img{width:106px;}
  .pg-intro-h{grid-area:title;font-size:34px;}
  .pg-intro-p{grid-area:blurb;max-width:36ch;margin-top:8px;}
  .pg-intro .pg-upload{grid-area:cta;margin-top:20px;}
  .pg-intro .pg-fine{grid-area:fine;margin-top:12px;}

  .up-drop{
    display:grid;align-items:center;justify-items:start;text-align:left;
    grid-template-columns:auto minmax(0,1fr) auto;
    grid-template-areas:
      "ic title btn"
      "ic blurb btn";
    column-gap:24px;row-gap:2px;
    max-width:880px;padding:42px 46px;
  }
  .up-drop-ic{grid-area:ic;width:40px;height:40px;}
  .up-drop h2{grid-area:title;font-size:21px;}
  .up-drop p{grid-area:blurb;max-width:44ch;}
  .up-drop .up-btn{grid-area:btn;margin-top:0;align-self:center;white-space:nowrap;}
}

/* ── a size up ──
   Turning the cards sideways gave them width the type never claimed; at
   34px and 13.5px the right-hand column read like a caption beside the
   pictures rather than the other half of the composition. */
@media (min-width:880px){
  .pg-intro-demo img{width:120px;}
  .pg-intro-h{font-size:40px;letter-spacing:.05em;}
  .pg-intro-p{font-size:15px;line-height:1.6;max-width:34ch;}
  .pg-intro .pg-upload{font-size:16px;padding:16px 26px;}
  .pg-intro .pg-fine{font-size:12px;}

  .up-drop-ic{width:52px;height:52px;}
  .up-drop h2{font-size:24px;}
  .up-drop p{font-size:14.5px;line-height:1.6;}
  .up-drop .up-btn{font-size:15px;padding:14px 26px;}
}

/* ── the title sits on a marker stroke ──
   The reference is a highlighter: the bar covers the lower half of the
   words and the letters rise out of it. Copying it literally failed twice
   before this. A solid block behind the whole title is a label, not a
   highlight. And the obvious colour — the accent — is pure white in this
   theme, so light type on it lands at 1.1:1.

   So the bar is a mid-tone struck from the ink itself at 22%: dark enough
   that the page's own light type still reads across it, light enough to
   be plainly a stroke against a near-black ground. Because it is mixed
   from --a-ink rather than named, it inverts with the theme — a pale bar
   under dark words in light mode without a second rule.

   Sized in em so it tracks the type, and positioned near the baseline so
   ascenders clear it the way they do on the reference. */
[data-tool="gallery"] .hub-title,
[data-tool="upscale"] .hub-title,
[data-tool="enhance"] .hub-title,
[data-tool="removebg"] .hub-title,
[data-tool="resize"] .hub-title{
  display:inline;
  padding:0 .16em;
  background-image:linear-gradient(
    color-mix(in srgb,var(--a-ink) 29%,transparent),
    color-mix(in srgb,var(--a-ink) 29%,transparent));
  background-repeat:no-repeat;
  background-size:100% .46em;
  background-position:0 .74em;
  border-radius:2px;
  /* a wrapped title gets the stroke on every line, not one long box */
  -webkit-box-decoration-break:clone;
  box-decoration-break:clone;
}
[data-tool="gallery"] .ut-head,
[data-tool="upscale"] .ut-head,
[data-tool="enhance"] .ut-head,
[data-tool="removebg"] .ut-head,
[data-tool="resize"] .ut-head{line-height:1.45;}
[data-tool="gallery"] .hub-sub,
[data-tool="upscale"] .hub-sub,
[data-tool="enhance"] .hub-sub,
[data-tool="removebg"] .hub-sub,
[data-tool="resize"] .hub-sub{margin-top:14px;}


/* ═══════════════════════════════════════════════════════════════════
   STUDIO SIDEBAR

   The sixteen tools, down the left edge, grouped by what they hand back.
   Built in js/sidebar.js; everything here is the look.

   It speaks the top bar's language, because it sits directly under it.
   The bar refuses a slab behind a label — "the row is a line of words;
   the only thing that should change is how present a word is" — and
   marks the current page with the accent rather than with grey. This
   column does the same: hover moves a name from muted to full ink and
   nothing else, and the page you are on takes a short accent rule beside
   the word, the upright cousin of the bar's rule underneath it.

   Same easing, same .18s, same accent token, so a glance from the bar to
   the column does not cross a border between two designs.

   Everything is gated on .has-sb, set by that script only once the column
   is really in the document, so a page where it failed to run looks
   exactly the way it did before.
   ═══════════════════════════════════════════════════════════════════ */
.sb,.sb-toggle{display:none;}

@media (min-width:1080px){
  /* Black, not the panel grey. The column is the edge of the window and
     wants to read as the edge — a lighter slab beside a darker page put
     a seam down the screen the eye kept returning to. */
  .sb{
    position:fixed;left:0;top:61px;bottom:0;z-index:55;width:252px;
    display:flex;flex-direction:column;
    background:#000;
    border-right:1px solid var(--a-line);
  }
  [data-app="light"] .sb{background:#fff;}

  .sb-scroll{
    flex:1;min-height:0;overflow-y:auto;
    padding:12px 12px 10px;
  }
  .sb-scroll::-webkit-scrollbar{width:8px;}
  .sb-scroll::-webkit-scrollbar-thumb{
    background:var(--a-chip-2);border-radius:100px;
    border:2px solid transparent;background-clip:content-box;
  }

  /* Space does the grouping; the label only has to name it, which is why
     it can be this small without getting lost. */
  .sb-sec + .sb-sec{margin-top:14px;}
  .sb-h{
    padding:0 12px 8px;
    font-size:11px;font-weight:600;letter-spacing:.1em;
    text-transform:uppercase;color:var(--a-mute);
  }

  /* ── a row is a word, not a box ──
     No pill, on hover or otherwise — the same decision the bar makes, for
     the same reason. Sixteen slabs in a column is a stack of boxes, and
     the shape is not carrying any meaning the ink does not already carry.
     The 1px nudge gives back the sense of contact that a background would
     have given, at none of the visual cost. */
  .sb-item{
    position:relative;
    display:flex;align-items:center;gap:11px;
    padding:8px 12px;border-radius:9px;
    font-size:15px;font-weight:500;letter-spacing:-.01em;
    color:var(--a-mute);
    transition:color .18s var(--ease),padding-left .18s var(--ease);
  }
  .sb-item:hover{color:var(--a-ink);padding-left:14px;}
  .sb-item.is-pressed{color:var(--a-ink);transition:none;}
  .sb-item.is-pressed .sb-ic{opacity:1;transition:none;}
  .sb-item.is-on{color:var(--a-ink);font-weight:600;}

  /* The mark yields to the word: dimmed at rest, full once the row is
     hovered or current, on the bar's own timing. */
  .sb-ic{
    flex:none;width:18px;height:18px;
    display:grid;place-items:center;color:inherit;opacity:.7;
    transition:opacity .18s var(--ease);
  }
  .sb-ic svg{width:18px;height:18px;display:block;}
  .sb-item:hover .sb-ic{opacity:.85;}
  .sb-item.is-on .sb-ic{opacity:1;}

  /* ── the marker ──
     The bar puts a short accent rule under the current word; a column
     puts the same rule beside it. Inset into the row rather than run out
     to the column's edge, because in the bar it is inset into the link
     rather than run out to the bar's edge.

     It draws itself on arrival — scaling up from nothing, overshooting a
     little and settling — which is the column's version of the bead the
     bar drops. One gesture, once, and then it is simply a mark. */
  /* the bead, on its way in */
  .sb-item.is-on::before{
    content:"";position:absolute;left:1px;top:50%;
    width:5px;height:5px;margin-top:-2.5px;
    border-radius:50%;background:var(--vz-acc);
    opacity:0;pointer-events:none;transform-origin:center;
    animation:sb-drop-fall .92s cubic-bezier(.55,0,.35,1) both;
  }
  /* what it leaves behind */
  .sb-item.is-on::after{
    content:"";position:absolute;left:2px;top:50%;
    width:3px;height:15px;margin-top:-7.5px;
    border-radius:3px;background:var(--vz-acc);
    transform-origin:center;
    animation:sb-drop-rule .92s cubic-bezier(.3,.9,.3,1) both;
  }
  [data-app="dark"] .sb-item.is-on::after{
    box-shadow:0 0 7px color-mix(in srgb,var(--vz-acc) 45%,transparent);
  }

  /* Falling: down the margin, then drawn out along the bar it becomes. */
  @keyframes sb-drop-fall{
    0%  {opacity:0;transform:translateY(-20px) scale(.6);}
    14% {opacity:1;transform:translateY(-17px) scale(1);}
    50% {opacity:1;transform:translateY(-6px) scaleX(.72) scaleY(1.4);}
    72% {opacity:1;transform:translateY(0) scaleX(.3) scaleY(4.6);}
    100%{opacity:0;transform:translateY(0) scaleX(.16) scaleY(8);}
  }

  /* Crossing: in from the right of the row, along it, and down into the
     same mark. The page chooses which of the two it wears. */
  .sb-item.is-on.sb-from-right::before,
  .mo-rtl .sb-item.is-on::before{
    animation-name:sb-drop-cross;
  }
  @keyframes sb-drop-cross{
    0%  {opacity:0;transform:translateX(150px) scale(.6);}
    14% {opacity:1;transform:translateX(126px) scale(1);}
    50% {opacity:1;transform:translateX(52px) scaleX(1.5) scaleY(.7);}
    72% {opacity:1;transform:translateX(5px) scaleX(.5) scaleY(3.4);}
    100%{opacity:0;transform:translateX(0) scaleX(.16) scaleY(8);}
  }

  /* The mark waits for the bead to arrive before drawing itself. */
  @keyframes sb-drop-rule{
    0%,64%{transform:scaleY(0);opacity:0;}
    100%  {transform:scaleY(1);opacity:1;}
  }

  /* ── arrival ──
     The list draws itself in from the edge it lives on, a beat apart, so
     the column reads as one movement rather than sixteen things appearing
     at once. Fast and short: it is navigation, not an entrance. */
  .sb-intro .sb-h,
  .sb-intro .sb-item{
    animation:sb-in .4s var(--e-out) both;
    animation-delay:calc(var(--i,0) * 16ms);
  }
  @keyframes sb-in{
    from{opacity:0;transform:translateX(-7px);}
    to  {opacity:1;transform:none;}
  }
  /* ── putting it away ──
     Lives in the top bar, because a control inside the thing it hides
     cannot bring it back. */
  .sb-toggle{
    display:grid;place-items:center;flex:none;
    width:30px;height:30px;border-radius:8px;
    color:var(--a-mute);cursor:pointer;
    transition:color .18s var(--ease),background-color .18s var(--ease);
  }

  .sb-toggle-rail{
    flex:none;margin:11px 0 2px 10px;
    transition:margin-left .3s var(--e-out);
  }
  .sb-toggle:hover{color:var(--a-ink);background:var(--a-chip);}
  .sb-toggle:active{transform:scale(.94);}
  .sb-toggle svg{width:17px;height:17px;display:block;}
  .sb-toggle .sb-toggle-bar{
    transition:opacity .22s var(--ease),transform .28s var(--e-out);
    transform-origin:7px 9px;
  }
  .sb-off .sb-toggle .sb-toggle-bar{opacity:.3;transform:translateX(-2px);}

  /* ── the page moves over ──
     main and the wizards' step bar are the whole of what sits in the
     page's flow. The header spans the window on purpose, and the toast
     and the modal are fixed overlays a page padding would shove
     off-centre. */
  .has-sb .app-body > main,
  .has-sb .app-body > .app-stepper-w{padding-left:252px;}
  .has-sb [data-dry-bar]{left:252px;}

  /* The column leaves the way it arrived rather than being cut. Gated on
     .sb-anim, which the toggle sets and a page load never does — without
     it a stored "hidden" would play a slide-out at every arrival. */
  .sb-off .sb{width:62px;}
  .sb-off .sb-toggle-rail{margin-left:14px;}

  /* Out of sight, still in the accessibility tree: the name is what a
     screen reader reads and what the tooltip repeats, so it is hidden
     rather than removed. */
  .sb-off .sb-t{
    position:absolute;width:1px;height:1px;
    margin:-1px;padding:0;overflow:hidden;
    clip-path:inset(50%);white-space:nowrap;
  }
  .sb-off .sb-h{
    height:0;padding:0;overflow:hidden;
    /* the space above each group still separates them */
  }
  .sb-off .sb-item{justify-content:center;padding-left:0;padding-right:0;}
  .sb-off .sb-item:hover{padding-left:0;}
  .sb-off .sb-scroll{padding-left:9px;padding-right:9px;}

  /* the marker keeps the left edge, where it reads as a margin mark
     rather than as something attached to a word that is not there */
  .sb-off .sb-item.is-on::after{left:-4px;}
  .sb-off .sb-item.is-on::before{left:-5px;}

  .sb-off.has-sb .app-body > main,
  .sb-off.has-sb .app-body > .app-stepper-w{padding-left:62px;}
  .sb-off.has-sb [data-dry-bar]{left:62px;}

  .sb-anim .sb{transition:width .3s var(--e-out);}
  .sb-anim.has-sb .app-body > main,
  .sb-anim.has-sb .app-body > .app-stepper-w{
    transition:padding-left .32s var(--e-out);
  }
  .sb-anim.has-sb [data-dry-bar]{transition:left .32s var(--e-out);}
}

@media (prefers-reduced-motion:reduce){
  .sb-item,.sb-ic,.sb-toggle,.sb-toggle-bar,.sb-h,
  .sb-item.is-on::before,
  .sb-item.is-on::after,
  .sb-anim .sb,
  .sb-anim.has-sb .app-body > main,
  .sb-anim.has-sb .app-body > .app-stepper-w,
  .sb-anim.has-sb [data-dry-bar]{animation:none;transition:none;}
  .sb-item:hover{padding-left:12px;}
}

/* ═══════════════════════════════════════════════════════════════════
   MOVING BETWEEN TOOLS

   Every tool is its own document, so choosing one from the column was a
   full page load: the screen blanked, and the sidebar tore itself down
   and drew itself back in — stagger and all — on every single click. An
   entrance that is charming once is a flicker when it happens on every
   navigation.

   Two halves to fixing it.

   The browser can carry one document into the next itself, so it is
   asked to. Naming the header and the column takes them OUT of the
   cross-fade: matching names on both sides are treated as the same
   object, so the chrome holds still while only the page beneath it
   changes. That is the whole difference between a site that reloads and
   an app that moves.
   ═══════════════════════════════════════════════════════════════════ */
/* ── why the browser does not do this ──
   A cross-document view transition looked like the right answer and was
   not. To transition between two documents the browser replaces the
   page with a snapshot of it, and a snapshot is a picture: for the whole
   length of the transition nothing on screen can be clicked, the column
   included. Choosing a tool and then having to wait a third of a second
   before the next one would take a click is worse than the flicker it
   was fixing.

   So only the page fades, and only its own content. The column is never
   part of it — it stays a live element that takes a click the moment the
   new document parses.

   Opacity only: a transform here would make <main> the containing block
   for anything fixed inside it, and the composer bar is fixed. */

/* ═══════════════════════════════════════════════════════════════════
   THE IMAGE MENU, AS AN ENGINE PICKER

   Every tool this menu used to list now lives in the left column, so it
   was saying the same sixteen names twice. What the bar can carry that
   the column cannot is the engines: twenty-six of them, too many to sit
   in a column that also holds the tools, and the sort of thing you pick
   once and then work with rather than navigate between.

   Built in js/anav.js from js/engines.js.
   ═══════════════════════════════════════════════════════════════════ */
.anav-menu-eng{min-width:404px;max-width:428px;padding:6px;}
.anav-eng .anav-menu-t{min-width:0;}
.anav-eng em{
  display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}

/* ── the five worth reaching for first ──
   Framed rather than merely listed. A heading alone would put them in
   the same reading rhythm as the twenty-one below, and the point of a
   short list at the top is that it is not the long one. */
/* locked in the top-bar menu: dimmed, with the lock in the gutter the
   row already reserves on the right */
.anav-eng.is-locked{opacity:.5;}
.anav-eng.is-locked:hover,.anav-eng.is-locked:focus-visible{opacity:.74;}
.anav-eng-lock{
  flex:0 0 auto;display:grid;place-items:center;
  width:16px;height:16px;margin-left:auto;color:var(--a-mute);
}
.anav-eng-lock svg{width:13px;height:13px;}

.anav-eng-lead{
  padding:4px;margin:0 0 8px;border-radius:12px;
  background:var(--a-chip-2);
  box-shadow:inset 0 0 0 1px var(--a-line);
}
.anav-eng-lead .anav-menu-h{margin:6px 0 4px;color:var(--a-ink);opacity:.8;}
.anav-eng-lead .anav-menu-ic{
  background:var(--vz-acc);color:var(--vz-acc-ink);
}


.anav-eng{align-items:center;gap:11px;padding:7px 9px;}
.anav-menu-eng > .anav-eng{margin:0 4px;}
.anav-menu-eng > .anav-menu-h{
  margin:15px 0 3px;padding:0 14px;
  font-weight:600;color:var(--a-mute);
}
.anav-menu-eng > .anav-menu-h:first-of-type{margin-top:6px;}
.anav-eng b{font-size:13.5px;}
.anav-eng em{font-size:11.5px;line-height:1.4;}

/* the current engine, marked the way the current page is */
.anav-eng.is-on .anav-menu-ic{background:var(--vz-acc);color:var(--vz-acc-ink);}

/* ── a vendor's own mark, shown as supplied ──
   Sized to the tile and nothing else: no filter, no recolouring, no
   stretch. Most brand terms allow the mark to identify that vendor's
   product — which is all these pickers do — and forbid restyling it, so
   the tile stays neutral and the file is left alone. */
.anav-eng-logo,
.cmp-mrow-logo{
  width:16px;height:16px;display:block;object-fit:contain;
}

/* ── what is left, at the foot of the column ──
   The bar prints the number; this gives it a length. Pinned below the
   list rather than inside it, so it stays put while the tools scroll and
   is the last thing on screen rather than something you scroll to. */
@media (min-width:1080px){
  .sb-foot{
    flex:none;margin:0 12px 12px;padding:9px 11px 10px;
    border-radius:10px;
    background:var(--a-chip);
    box-shadow:inset 0 0 0 1px var(--a-line);
  }
  .sb-foot-n{
    display:flex;align-items:baseline;gap:6px;
    font-size:11.5px;color:var(--a-mute);
  }
  .sb-foot-n svg{width:11px;height:11px;align-self:center;flex:none;color:var(--a-mute);}
  .sb-foot-n b{
    font-size:16px;font-weight:650;letter-spacing:-.02em;
    color:var(--a-ink);font-variant-numeric:tabular-nums;
  }
  .sb-foot-n em{font-style:normal;}

  .sb-foot-bar{
    height:3px;margin-top:8px;border-radius:3px;overflow:hidden;
    background:var(--a-chip-2);
  }
  .sb-foot-bar i{
    display:block;height:100%;border-radius:3px;
    background:var(--a-ink);
    transition:width .4s var(--e-out);
  }

  /* Only once it matters. A standing invitation to spend is furniture;
     the same words when the meter is nearly empty are information. */
  .sb-foot.is-low .sb-foot-bar i{background:var(--vz-acc);}
  .sb-foot.is-low .sb-foot-n svg{color:var(--vz-acc);}
  /* On the figure's own line, at its end — a full-width button under the
     meter cost forty pixels the list needed, to say two words. */
  .sb-foot-go{
    margin-left:auto;padding:3px 8px;border-radius:100px;
    flex:none;
    font-size:11px;font-weight:600;
    background:var(--a-btn);color:var(--a-btn-ink);
  }

  /* Narrowed, it keeps the figure and loses the words — the tooltip on
     the block still says what the number is. */
  .sb-off .sb-foot{
    margin:0 9px 12px;padding:9px 4px;text-align:center;
  }
  .sb-off .sb-foot-n{flex-direction:column;gap:1px;align-items:center;}
  .sb-off .sb-foot-n em,
  .sb-off .sb-foot-go{display:none;}
  .sb-off .sb-foot-n{gap:0;}
  .sb-off .sb-foot-n b{font-size:14px;}
  .sb-off .sb-foot-bar{margin-top:7px;}
}

/* ── the two controls under the meter ──
   Small and quiet: neither is used mid-task, so they sit at the very
   bottom where a hand goes looking rather than where the eye lands. */
@media (min-width:1080px){
}


/* ── a video engine the catalogue lists but fal does not serve yet ──
   Dimmed rather than removed: the list is partly a statement of where the
   studio is going, and hiding the unwired half would make the roster look
   smaller than it is. Clicking one says so instead of failing. */
.vg-card.is-soon,.vg-feat-card.is-soon{opacity:.42;}
.vg-card.is-soon:hover,.vg-feat-card.is-soon:hover{opacity:.6;}

/* the finished clip, sharing the stage with the start-frame preview */
.vg-stage-video{width:100%;height:100%;object-fit:contain;display:block;border-radius:inherit;}

/* ── the mark beside the name ──
   Filled with currentColor, so the one drawing serves the light
   marketing pages and the dark studio without a second file. Sized off
   the wordmark rather than in pixels, so the two stay in proportion
   wherever the lockup is scaled. */
/* In the studio bar the mark is the entire logo — there is no wordmark
   left to take its size from, so it is set outright. 22px keeps the
   sparkle above one device pixel on a 1x screen, which is where it
   started to mush at the old size. */
.nav-logo-mark{width:25px;height:25px;flex:none;display:block;color:var(--a-ink);}
.anav-logo{padding-right:2px;}




/* ── the tick beside each feature ──
   A mark per row, present or absent, in the same order on every card —
   that is what makes the four columns readable across as well as down.
   The cross is drawn quietly: what matters is that the thing is missing,
   not that the absence is decorated. */
.pk-list li{
  display:flex;align-items:flex-start;gap:9px;
  font-size:12.5px;line-height:1.45;color:var(--a-ink);
  padding-left:0;
}
.pk-mark{flex:0 0 15px;display:flex;margin-top:1px;}
.pk-mark svg{width:15px;height:15px;color:var(--vz-acc);}
.pk-list b{font-weight:650;margin-left:2px;}

.pk-list li.is-off{color:var(--a-mute);}
.pk-list li.is-off .pk-mark svg{color:var(--a-mute);opacity:.55;width:14px;height:14px;}
.pk-list li.is-off b{color:var(--a-mute);}


/* ── the offer, in its own box ──
   Name, pool, what the pool buys, price. Nothing else: the moment the
   feature list was inside it, the box stopped being an offer and became
   a page. */
.pk-box{
  position:relative;overflow:hidden;
  display:flex;flex-direction:column;
  padding:20px 20px 18px;
  min-height:250px;
}
/* A box carrying a badge starts lower, or the name reads through the
   pill. Only the boxes that have one pay the space — the price is
   pinned to the bottom either way, so all four still line up. */
.pk-card:has(.pk-tag) .pk-box{padding-top:44px;}
.pk-box .pk-name{margin-bottom:14px;}
/* the price sits at the foot of the box however tall the rest runs, so
   the four numbers land on one line across the row */
.pk-box .pk-price{margin-top:auto;padding-top:16px;}

.pk-credits{font-size:14.5px;color:var(--a-ink);margin-bottom:6px;}
.pk-credits b{font-size:15px;font-weight:650;color:var(--a-ink);font-variant-numeric:tabular-nums;}
.pk-credits em{font-style:normal;font-size:12.5px;color:var(--a-mute);}

/* what the pool buys: quiet, under the pool it belongs to */
.pk-yield{background:none;padding:0;}
.pk-yield-s{font-size:11.5px;line-height:1.55;color:var(--a-mute);margin:0;}
.pk-yield-s b{font-weight:600;color:var(--a-mute);font-variant-numeric:tabular-nums;}

/* ── the button, outside the box ── */
/* Inside the box, directly under the price it belongs to. */
.pk-box .pk-go{margin-top:14px;width:100%;}

/* ── the ticks, on the page rather than in a panel ──
   No border and no background: ten bordered rows under four bordered
   boxes reads as a table nobody asked for. */
/* The sections are divided by a rule, not by a box each. */
.pk-list{
  display:flex;flex-direction:column;gap:10px;
  margin:0;padding:18px 20px;list-style:none;
  border-top:1px solid var(--a-line);
}

/* ── the numbers ──
   Label left, value right, the way a spec sheet reads. These are the rows
   a tick could not answer: "Queue" is not yes or no, it is Standard or
   Priority. */
.pk-stats{
  display:flex;flex-direction:column;gap:0;
  margin:0;padding:6px 20px 12px;
  border-top:1px solid var(--a-line);
}
.pk-stat{
  display:flex;align-items:baseline;justify-content:space-between;gap:12px;
  padding:9px 0;border-bottom:1px solid var(--a-line);
}
/* the frame is the last line — a rule under the final row would sit on
   top of it and read as a double border */
.pk-stat:last-child{border-bottom:0;}
.pk-stat dt{font-size:12.5px;color:var(--a-mute);}
.pk-stat dd{
  margin:0;font-size:12.5px;font-weight:650;color:var(--a-ink);
  text-align:right;font-variant-numeric:tabular-nums;
}
.pk-stat dd.is-off{font-weight:400;color:var(--a-mute);opacity:.6;}

/* ── sizing the plan that can be sized ──
   Four rungs, marked above the track so the jump between them is visible
   before it is dragged. Only Ultra declares steps; the markup is absent
   everywhere else rather than hidden. */
.pk-size{margin:14px 0 0;}
.pk-size-marks{
  display:flex;justify-content:space-between;margin-bottom:5px;
  font-size:10.5px;font-variant-numeric:tabular-nums;color:var(--a-mute);
}
.pk-size-mark.is-on{color:var(--a-ink);font-weight:650;}
.pk-size-range{
  -webkit-appearance:none;appearance:none;
  width:100%;height:3px;border-radius:100px;margin:0;
  background:color-mix(in srgb,var(--a-ink) 22%,transparent);
  cursor:pointer;
}
.pk-size-range::-webkit-slider-thumb{
  -webkit-appearance:none;appearance:none;
  width:15px;height:15px;border-radius:50%;border:0;
  background:var(--a-ink);cursor:grab;
  box-shadow:0 2px 8px rgba(0,0,0,.4);
}
.pk-size-range::-moz-range-thumb{
  width:15px;height:15px;border-radius:50%;border:0;
  background:var(--a-ink);cursor:grab;
  box-shadow:0 2px 8px rgba(0,0,0,.4);
}
.pk-size-range:focus-visible{outline:2px solid var(--vz-acc);outline-offset:4px;}

/* ── the cut-out, while it runs ──
   A veil over the picture that a bright line wipes away, left to right:
   the photo is being cleaned, which is what the tool is doing.

   It is its own element rather than a pseudo-element on the frame. The
   frame's ::before is already the sunk backdrop behind the photo, so
   borrowing it for the sweep replaced the backdrop for the length of the
   run. It also sits on the stage rather than inside the upload frame,
   because after the first cut the frame is hidden and the result canvas
   has taken its place — a sweep parented to the frame would be invisible
   on every run after the first, which is exactly when the button reads
   "Run again".

   The veil and the line are stops in one gradient twice the stage's
   width, moved by background-position. Two elements on two animations
   drift apart as soon as the timing is touched; stops in one gradient
   cannot. Position rather than transform because a transform's
   percentages resolve against the moving element itself — a 2px line
   told to travel 340% goes 7px, not across the stage.

   Black rather than the accent: --vz-acc is #fff in dark mode and
   near-black in light, so either way it vanishes against half the photos
   people upload. Dimming reads on all of them. */
.ut-scan{
  position:absolute;inset:0;z-index:6;
  pointer-events:none;
  background-image:linear-gradient(90deg,
    transparent 0%,
    transparent 48.4%,
    rgba(255,255,255,.35) 49.4%,
    #fff 50%,
    rgba(255,255,255,.5) 50.6%,
    rgba(0,0,0,.30) 51.4%,
    rgba(0,0,0,.44) 56%,
    rgba(0,0,0,.44) 100%);
  background-size:200% 100%;
  background-repeat:no-repeat;
  /* 100% parks the veil over the whole stage, 0% leaves it clear */
  animation:ut-scan 1.65s cubic-bezier(.42,0,.3,1) infinite;
}
.ut-scan[hidden]{display:none;}

/* the glow rides the line, so it is cut from the same gradient */
.ut-scan::after{
  content:"";position:absolute;inset:0;
  background-image:linear-gradient(90deg,
    transparent 46.5%,
    rgba(255,255,255,.18) 50%,
    transparent 53.5%);
  background-size:200% 100%;
  background-repeat:no-repeat;
  filter:blur(6px);
  animation:inherit;
}

@keyframes ut-scan{
  0%{background-position:100% 0;opacity:0;}
  9%{opacity:1;}
  86%{opacity:1;}
  100%{background-position:0 0;opacity:0;}
}

@media (prefers-reduced-motion:reduce){
  .ut-scan{animation:none;background-position:50% 0;opacity:.9;}
  .ut-scan::after{display:none;}
}


/* ═══ EDIT — Crop & Expand, Draw, Annotate ═══ */

/* ── shared panel parts ── */
/* The native control brings its own arrow and its own metrics, neither of
   which match anything else on this panel. appearance:none takes both
   away; the chevron and the engine glyph are painted back as background
   images, so there is no wrapper element to keep in step. */
.ed-select{
  appearance:none;-webkit-appearance:none;
  width:100%;margin-bottom:9px;padding:10px 30px 10px 32px;border-radius:10px;
  font:inherit;font-size:12.5px;font-weight:500;color:var(--a-ink);
  background-color:rgba(255,255,255,.07);
  background-repeat:no-repeat;
  background-position:left 10px center, right 11px center;
  background-size:14px 14px, 10px 10px;
  box-shadow:inset 0 0 0 1px var(--a-line);
  border:0;cursor:pointer;
  transition:background-color .18s var(--e-out);
}
.ed-select:hover{background-color:rgba(255,255,255,.13);}
.ed-select:focus-visible{outline:2px solid var(--a-ink);outline-offset:1px;}
/* the option list is drawn by the OS, so it needs a solid ground of its own */
.ed-select option{background:#17171a;color:#fff;}
.ed-area{
  display:block;width:100%;margin-bottom:8px;padding:9px 10px;
  border-radius:10px;border:0;resize:vertical;
  font:inherit;font-size:12.5px;line-height:1.45;color:var(--a-ink);
  background:rgba(255,255,255,.06);
  box-shadow:inset 0 0 0 1px var(--a-line);
}
.ed-area::placeholder{color:var(--a-mute);}
.ed-lab{font-size:11.5px;color:var(--a-mute);padding:2px 0 6px;}

/* ── the ratio grid ──
   Five to a row, landscape on top and portrait below, so the two families
   read as two rows rather than as one list that happens to turn over. */
.ed-ratios{
  display:grid;grid-template-columns:repeat(5,1fr);gap:6px;padding-bottom:10px;
}
.ed-ratio{
  padding:9px 0;border-radius:9px;cursor:pointer;
  font-size:11.5px;font-weight:600;font-variant-numeric:tabular-nums;
  color:var(--a-ink);background:rgba(255,255,255,.06);
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:background-color .18s var(--e-out),box-shadow .18s var(--e-out);
}
.ed-ratio:hover{background:rgba(255,255,255,.12);}
.ed-ratio.is-on{
  background:var(--a-btn);color:var(--a-btn-ink);
  box-shadow:inset 0 0 0 1.5px var(--a-ink);
}

/* ── the colour picker ── */
.ed-pick{display:grid;grid-template-columns:1fr 22px 30px;gap:8px;padding-bottom:12px;}
.ed-pick-sq{
  position:relative;aspect-ratio:1/.92;border-radius:10px;cursor:crosshair;
  touch-action:none;
  /* white to the hue across, then black up from the bottom: the standard
     saturation/brightness square, built from two gradients rather than a
     bitmap so it costs nothing and stays sharp at any size */
  background:
    linear-gradient(to top, #000, transparent),
    linear-gradient(to right, #fff, hsl(var(--h,0) 100% 50%));
  box-shadow:inset 0 0 0 1px var(--a-line);
}
.ed-pick-dot{
  position:absolute;width:14px;height:14px;border-radius:50%;
  transform:translate(-50%,-50%);pointer-events:none;
  background:var(--c,#fff);
  box-shadow:0 0 0 2px #fff, 0 0 0 3.5px rgba(0,0,0,.45);
}
.ed-pick-hue{
  position:relative;border-radius:8px;cursor:ns-resize;touch-action:none;
  background:linear-gradient(to bottom,
    #f00 0%,#f0f 17%,#00f 33%,#0ff 50%,#0f0 67%,#ff0 83%,#f00 100%);
  box-shadow:inset 0 0 0 1px var(--a-line);
}
.ed-pick-hdot{
  position:absolute;left:-2px;right:-2px;height:6px;border-radius:3px;
  transform:translateY(-50%);pointer-events:none;
  background:#fff;box-shadow:0 0 0 1px rgba(0,0,0,.45);
}
.ed-pick-side{display:flex;flex-direction:column;gap:6px;}
.ed-pick-btn{
  display:grid;place-items:center;width:30px;height:30px;border-radius:8px;
  cursor:pointer;color:var(--a-ink);background:rgba(255,255,255,.08);
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:background-color .18s var(--e-out);
}
.ed-pick-btn svg{width:15px;height:15px;}
.ed-pick-btn:hover{background:rgba(255,255,255,.16);}
.ed-pick-btn.is-on{background:var(--a-btn);color:var(--a-btn-ink);box-shadow:none;}

.ed-swatches{display:grid;grid-template-columns:repeat(7,1fr);gap:6px;padding-bottom:10px;}
.ed-swatch{
  aspect-ratio:1;border-radius:50%;cursor:pointer;background:var(--c,#fff);
  box-shadow:inset 0 0 0 1px rgba(0,0,0,.25);
  transition:transform .16s var(--e-out),box-shadow .16s var(--e-out);
}
.ed-swatch:hover{transform:scale(1.14);}
.ed-swatch.is-on{box-shadow:0 0 0 2px var(--a-panel),0 0 0 3.5px var(--a-ink);}

/* ── the mode switch ──
   Two ways of marking, one tool. They sit side by side rather than in a
   list because they are alternatives, not steps. */
.ed-modes{display:grid;grid-template-columns:1fr 1fr;gap:6px;padding-bottom:10px;}
.ed-mode{
  display:flex;align-items:center;justify-content:center;gap:6px;
  padding:9px 8px;border-radius:9px;cursor:pointer;
  font-size:12.5px;font-weight:500;color:var(--a-ink);
  background:rgba(255,255,255,.06);
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:background-color .18s var(--e-out),color .18s var(--e-out);
}
.ed-mode svg{width:15px;height:15px;flex:none;}
.ed-mode:hover{background:rgba(255,255,255,.13);}
.ed-mode.is-on{background:var(--a-btn);color:var(--a-btn-ink);box-shadow:none;font-weight:600;}

/* ── the Generate button ──
   Full width and light, because it is the one thing on this panel that
   spends money — everything above it is set-up. */
.ed-go{
  display:flex;align-items:center;justify-content:center;gap:8px;
  width:100%;margin-top:2px;padding:12px 14px;border-radius:11px;
  font-size:13.5px;font-weight:600;cursor:pointer;
  color:var(--a-btn-ink);background:var(--a-btn);
  transition:opacity .18s var(--e-out),transform .18s var(--e-out);
}
.ed-go svg{width:15px;height:15px;flex:none;}
.ed-go em{font-style:normal;font-weight:500;opacity:.62;}
.ed-go:hover{transform:translateY(-1px);}
.ed-go[disabled]{opacity:.32;cursor:default;transform:none;}
.ed-mini-wide{width:100%;margin-top:7px;text-align:center;}

/* ── the region overlay ──
   Inset by the wrapper's own padding so it lands exactly on the canvas,
   which is what the percentage geometry in the markup is measured against. */
.ed-regions{position:absolute;inset:18px;pointer-events:none;z-index:5;}
.ed-regions[hidden]{display:none;}

/* the painted regions, under the boxes and their labels */
.ed-maskview{
  position:absolute;inset:18px;width:auto;height:auto;
  border-radius:10px;pointer-events:none;z-index:4;
}
.ed-maskview[hidden]{display:none;}

/* A hairline and a wash, not a heavy frame. The mark is there to say
   which part of the photograph is being talked about; a thick border
   competes with the picture it is pointing at. */
.ed-region{
  position:absolute;pointer-events:auto;cursor:pointer;
  border-radius:5px;
  box-shadow:inset 0 0 0 1.5px #2b7fff, 0 0 0 1px rgba(0,0,0,.35);
  background:rgba(43,127,255,.10);
  transition:background-color .18s var(--e-out),box-shadow .18s var(--e-out);
}
.ed-region:hover{background:rgba(43,127,255,.17);}
.ed-region.is-sel{
  box-shadow:inset 0 0 0 1.5px #2b7fff, 0 0 0 1px rgba(0,0,0,.35),
             0 0 0 4px rgba(43,127,255,.22);
}
.ed-region.is-draft{pointer-events:none;background:rgba(43,127,255,.14);}
/* a painted region draws its own shape on the canvas below, so the box
   is only there to hold the number and the prompt */
.ed-region.is-brush{background:none;box-shadow:none;}
.ed-region.is-brush:hover{background:none;}

.ed-region-n{
  position:absolute;top:-11px;left:-11px;
  width:21px;height:21px;border-radius:50%;
  display:grid;place-items:center;
  font-size:11px;font-weight:700;font-variant-numeric:tabular-nums;
  color:#fff;background:#2b7fff;
  box-shadow:0 0 0 2px var(--a-panel),0 2px 6px rgba(0,0,0,.4);
}
.ed-region-x{
  position:absolute;top:-11px;right:-11px;
  width:21px;height:21px;border-radius:50%;cursor:pointer;
  display:grid;place-items:center;font-size:10px;
  color:#fff;background:#22222a;
  box-shadow:0 0 0 2px var(--a-panel),0 2px 6px rgba(0,0,0,.4);
  opacity:0;transition:opacity .16s var(--e-out),background-color .16s var(--e-out);
}
.ed-region:hover .ed-region-x,
.ed-region.is-sel .ed-region-x{opacity:1;}
.ed-region-x:hover{background:#c8342b;}

/* The prompt bar hangs under its mark. Fixed dark, not a theme token: it
   floats over a photograph, so it has to read against the picture rather
   than against the page. */
.ed-region-ask{
  position:absolute;top:calc(100% + 10px);left:0;min-width:252px;max-width:340px;
  display:flex;align-items:flex-end;gap:7px;padding:8px;
  border-radius:13px;background:rgba(22,22,25,.95);
  backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.12),0 20px 44px -20px rgba(0,0,0,.85);
}
.ed-region-ask textarea{
  flex:1;border:0;resize:none;padding:5px 6px;border-radius:7px;
  font:inherit;font-size:12.5px;line-height:1.45;color:#fff;background:transparent;
}
.ed-region-ask textarea::placeholder{color:rgba(255,255,255,.42);}
.ed-region-ask textarea:focus{outline:none;}
.ed-region-ok{
  flex:none;width:28px;height:28px;border-radius:50%;cursor:pointer;
  display:grid;place-items:center;font-size:12px;
  color:#fff;background:#2b7fff;
  transition:background-color .16s var(--e-out);
}
.ed-region-ok:hover{background:#1a6ae8;}
.ed-region-lbl{
  position:absolute;top:calc(100% + 6px);left:0;max-width:210px;
  padding:3px 8px;border-radius:7px;
  font-size:11px;line-height:1.4;color:#fff;background:rgba(22,22,25,.92);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.1);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}

/* the pointer says what the canvas will do with a press */
.ed-canvas-w canvas{cursor:default;}
[data-ed-mode="draw"] .ed-canvas-w canvas{cursor:crosshair;}
[data-ed-mode="annotate"] .ed-canvas-w canvas{cursor:crosshair;}
[data-ed-mode="annotate"][data-ed-mark="brush"] .ed-canvas-w canvas{cursor:none;}
[data-ed-mode="retouch"] .ed-canvas-w canvas{cursor:none;}

/* the annotate brush marks a region rather than cutting one out, so its
   ring is the same blue as everything else that means "this bit here" */
.ed-brushdot[data-mode="region"]{
  border-color:rgba(43,127,255,.95);
  box-shadow:0 0 0 1.5px rgba(255,255,255,.7) inset;
}

/* The two glyphs on the engine select. Drawn in a mid grey rather than a
   theme token because a background-image cannot read one — and a grey at
   this weight holds up against both the light and the dark panel. */
.ed-select{
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23888f99' stroke-width='2.1' stroke-linecap='round'%3E%3Cpath d='M6 18V11M12 18V6M18 18v-4'/%3E%3C/svg%3E"),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23888f99' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
}

/* ── the grips on a mark ──
   The body moves it, the corner resizes it. Both say so through the
   cursor, because a box that can be dragged and does not look like it
   is a box nobody tries to drag. */
.ed-region{cursor:move;}
.ed-region.is-draft{cursor:crosshair;}
.ed-region-size{
  position:absolute;right:-6px;bottom:-6px;
  width:13px;height:13px;border-radius:50%;
  background:#fff;cursor:nwse-resize;pointer-events:auto;
  box-shadow:0 0 0 2px #2b7fff, 0 2px 6px rgba(0,0,0,.4);
  opacity:0;transition:opacity .16s var(--e-out);
}
.ed-region:hover .ed-region-size,
.ed-region.is-sel .ed-region-size{opacity:1;}

/* the bin, beside the tick in the prompt bar */
.ed-region-bin{
  flex:none;width:28px;height:28px;border-radius:50%;cursor:pointer;
  display:grid;place-items:center;
  color:rgba(255,255,255,.6);background:rgba(255,255,255,.08);
  transition:background-color .16s var(--e-out),color .16s var(--e-out);
}
.ed-region-bin svg{width:14px;height:14px;}
.ed-region-bin:hover{background:#c8342b;color:#fff;}

/* ── AI Edit ── */
.ed-area-tall{min-height:104px;}
.ed-reframe{display:flex;align-items:center;gap:6px;padding-bottom:10px;}
/* a label wrapping a hidden file input, so it behaves as the button it
   looks like without a click handler standing in the middle */
.ed-mode-file{flex:1;cursor:pointer;}
/* The engine's own sentence, under the picker. It is what tells the two
   Nano Bananas apart — the names alone do not. */
.ed-note{
  font-size:11.5px;line-height:1.45;color:var(--a-mute);
  padding:0 2px 10px;
}

/* ── Enhance: which fault ──
   A row of jobs, not a strength slider. The note under it changes with
   the selection, because the name alone does not tell you whether this
   is the one for your photograph. */
.up-fixes{
  display:grid;grid-template-columns:repeat(5,1fr);gap:6px;
  margin-bottom:8px;
}
.up-fix{
  display:flex;align-items:center;justify-content:center;gap:6px;
  padding:10px 8px;border-radius:10px;cursor:pointer;
  font-size:12.5px;font-weight:500;color:var(--a-ink);
  background:var(--a-chip);
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:background-color .18s var(--e-out),color .18s var(--e-out);
}
.up-fix svg{width:15px;height:15px;flex:none;}
.up-fix:hover{background:var(--a-chip-2);}
.up-fix.is-on{background:var(--a-btn);color:var(--a-btn-ink);box-shadow:none;font-weight:600;}
.up-fix:disabled{opacity:.4;cursor:default;}
.up-fix-note{
  font-size:12px;line-height:1.5;color:var(--a-mute);
  padding:0 2px 16px;
}
@media (max-width:720px){
  .up-fixes{grid-template-columns:repeat(3,1fr);}
}

/* ── Enhance: the empty room ──
   A card with the work pictured at the top, rather than a dashed
   rectangle asking for a file. Monochrome throughout: the split is drawn
   with grey and contrast, not with a colour, so it sits inside the rest
   of the studio instead of shouting over it. */
.up-card{
  width:100%;max-width:560px;margin:8px auto 0;
  border-radius:20px;overflow:hidden;
  background:var(--a-panel);
  box-shadow:inset 0 0 0 1px var(--a-line), 0 30px 60px -44px rgba(0,0,0,.7);
  transition:box-shadow .22s var(--e-out);
}
.up-card.is-over{box-shadow:inset 0 0 0 2px var(--a-ink), 0 30px 60px -40px rgba(0,0,0,.75);}

/* The same photograph twice: flattened on the left, clean on the right,
   with a hairline where they meet. One file, and the difference is the
   whole point of the page. */
/* Taller than sixteen by ten. The picture is the point of this card,
   and the copy under it is only three short lines. */
.up-hero{position:relative;aspect-ratio:16/11;overflow:hidden;background:var(--a-chip);}
.up-hero img{
  position:absolute;inset:0;width:100%;height:100%;
  object-fit:cover;object-position:50% 22%;display:block;
}
.up-hero-a{filter:grayscale(1) contrast(.72) brightness(.82) blur(1.4px);}
.up-hero-b{
  filter:grayscale(1) contrast(1.12) brightness(1.04);
  clip-path:inset(0 0 0 50%);
}
.up-hero-line{
  position:absolute;top:0;bottom:0;left:50%;width:1.5px;
  background:rgba(255,255,255,.9);
  box-shadow:0 0 12px rgba(0,0,0,.55);
}
/* a soft floor under the picture so the title is not fighting it */
.up-hero::after{
  content:"";position:absolute;inset:auto 0 0 0;height:38%;
  background:linear-gradient(180deg,transparent,var(--a-panel));
  pointer-events:none;
}

.up-card-in{padding:6px 32px 30px;text-align:center;}
.up-card-t{
  display:flex;align-items:center;justify-content:center;gap:10px;
  font-size:29px;font-weight:600;letter-spacing:-.02em;color:var(--a-ink);
  padding-bottom:8px;
}
.up-card-ic{
  display:grid;place-items:center;width:34px;height:34px;border-radius:10px;
  background:var(--a-btn);color:var(--a-btn-ink);
}
.up-card-ic svg{width:19px;height:19px;}
.up-card-p{
  font-size:13.5px;line-height:1.6;color:var(--a-mute);
  max-width:42ch;margin:0 auto;padding-bottom:18px;
}
.up-card-btns{display:flex;gap:8px;justify-content:center;flex-wrap:wrap;}
.up-card-btns .up-btn{
  display:inline-flex;align-items:center;justify-content:center;gap:7px;
  min-width:132px;padding:11px 18px;border-radius:11px;
  font-size:13px;font-weight:600;cursor:pointer;
  color:var(--a-ink);background:var(--a-chip);
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:background-color .18s var(--e-out),transform .18s var(--e-out);
}
.up-card-btns .up-btn svg{width:15px;height:15px;flex:none;}
.up-card-btns .up-btn:hover{background:var(--a-chip-2);transform:translateY(-1px);}
.up-card-btns .up-btn.is-solid{
  background:var(--a-btn);color:var(--a-btn-ink);box-shadow:none;
}
.up-card-note{padding-top:12px;font-size:11.5px;color:var(--a-mute);opacity:.85;}

/* ── picking something already in the library ── */
.up-sheet{
  position:fixed;inset:0;z-index:120;
  display:grid;place-items:center;padding:24px;
  background:rgba(8,8,10,.72);
  backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);
}
.up-sheet-in{
  width:min(560px,100%);max-height:78vh;display:flex;flex-direction:column;
  border-radius:18px;overflow:hidden;
  background:var(--a-panel);
  box-shadow:inset 0 0 0 1px var(--a-line), 0 40px 80px -30px rgba(0,0,0,.8);
}
.up-sheet-top{
  display:flex;align-items:center;justify-content:space-between;
  padding:15px 18px;border-bottom:1px solid var(--a-line);
}
.up-sheet-top h3{font-size:14px;font-weight:600;color:var(--a-ink);}
.up-sheet-x{
  width:28px;height:28px;border-radius:50%;cursor:pointer;
  display:grid;place-items:center;font-size:11px;
  color:var(--a-mute);background:var(--a-chip);
  transition:background-color .16s var(--e-out),color .16s var(--e-out);
}
.up-sheet-x:hover{background:var(--a-chip-2);color:var(--a-ink);}
.up-sheet-grid{
  display:grid;gap:8px;padding:16px;overflow-y:auto;
  grid-template-columns:repeat(auto-fill,minmax(94px,1fr));
}
.up-sheet-pick{
  aspect-ratio:1/1.25;border-radius:10px;overflow:hidden;cursor:pointer;
  background:var(--a-chip);box-shadow:inset 0 0 0 1px var(--a-line);
  transition:box-shadow .16s var(--e-out),transform .16s var(--e-out);
}
.up-sheet-pick img{width:100%;height:100%;object-fit:cover;display:block;}
.up-sheet-pick:hover{transform:translateY(-2px);box-shadow:0 0 0 2px var(--a-ink);}

/* ═══ THE FINISHING ROOM ═══
   Upscale and Enhance share it. Strip on the left, the picture large in
   the middle, the settings on the right — the arrangement every editor
   uses, because the thing being worked on should be the biggest thing on
   the screen. The grid of thumbnails these two had before showed nine
   photographs at postage-stamp size and none of them properly. */
.up.is-room{max-width:1420px;}
.up-room{
  display:grid;
  grid-template-columns:96px minmax(0,1fr) 332px;
  gap:14px;
  height:clamp(430px,calc(100vh - 268px),820px);
}

/* ── the strip ── */
.up-strip{
  display:flex;flex-direction:column;gap:8px;
  padding:8px;overflow-y:auto;overflow-x:hidden;
  border-radius:14px;background:var(--a-panel);
  box-shadow:inset 0 0 0 1px var(--a-line);
  scrollbar-width:thin;
}
.up-strip-add{
  flex:none;display:grid;place-items:center;
  width:100%;aspect-ratio:1/1.15;border-radius:10px;cursor:pointer;
  font-size:19px;color:var(--a-mute);background:var(--a-chip);
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:background-color .16s var(--e-out),color .16s var(--e-out);
}
.up-strip-add:hover{background:var(--a-chip-2);color:var(--a-ink);}
.up-strip-item{
  position:relative;flex:none;
  width:100%;aspect-ratio:1/1.15;border-radius:10px;overflow:hidden;
  cursor:pointer;background:var(--a-chip);
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:box-shadow .16s var(--e-out);
}
.up-strip-item img{width:100%;height:100%;object-fit:cover;display:block;}
.up-strip-item.is-on{box-shadow:0 0 0 2px var(--a-ink);}
.up-strip-item .up-x{top:4px;right:4px;width:17px;height:17px;font-size:8px;}
/* a frame that has already come back says so, quietly */
.up-strip-item.is-done::after{
  content:"";position:absolute;left:5px;bottom:5px;
  width:7px;height:7px;border-radius:50%;
  background:var(--a-ink);box-shadow:0 0 0 2px var(--a-panel);
}

/* ── the stage ── */
.up-stage{
  position:relative;display:grid;place-items:center;padding:16px;
  /* An explicit track that can shrink. Without it the row is auto-sized,
     the grid area has no definite height, and the picture’s max-height of
     100% resolves against nothing — so a portrait frame took the full
     width, ran past the bottom of the stage, and the overflow rule cut
     the top and bottom off it. */
  grid-template-columns:minmax(0,1fr);
  grid-template-rows:minmax(0,1fr);
  border-radius:16px;overflow:hidden;
  background:var(--a-chip);
  box-shadow:inset 0 0 0 1px var(--a-line);
}
.up-stage img{
  max-width:100%;max-height:100%;
  object-fit:contain;display:block;border-radius:8px;
}
/* Sits on the picture, the way a play button does. Fixed dark rather
   than a theme token: it floats over a photograph, so it has to read
   against the photograph and not against the page. */
.up-stage-go{
  position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  display:inline-flex;align-items:center;gap:8px;
  padding:11px 20px;border-radius:12px;cursor:pointer;
  font-size:13.5px;font-weight:600;color:#fff;
  background:rgba(20,20,22,.82);
  backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.16),0 18px 40px -18px rgba(0,0,0,.8);
  transition:background-color .18s var(--e-out),transform .18s var(--e-out);
}
.up-stage-go:hover{background:rgba(20,20,22,.94);transform:translate(-50%,-52%);}
.up-stage-go svg{width:15px;height:15px;}
.up-stage-cap{
  position:absolute;left:14px;bottom:12px;
  padding:4px 9px;border-radius:7px;
  font-size:11px;font-variant-numeric:tabular-nums;color:#fff;
  background:rgba(20,20,22,.8);
}
.up-stage-bad{
  max-width:280px;text-align:center;font-size:12.5px;line-height:1.5;
  color:var(--a-danger,#e0364a);
}

/* ── the panel ── */
.up-panel{
  display:flex;flex-direction:column;min-height:0;
  border-radius:16px;overflow:hidden;
  background:var(--a-panel);
  box-shadow:inset 0 0 0 1px var(--a-line);
}
.up-panel-top{
  display:flex;align-items:center;justify-content:space-between;gap:8px;
  padding:13px 15px;border-bottom:1px solid var(--a-line);
}
.up-panel-top h2{
  display:flex;align-items:center;gap:8px;
  font-size:14px;font-weight:600;color:var(--a-ink);
}
.up-panel-top h2 svg{width:16px;height:16px;opacity:.75;}
.up-reset{
  display:inline-flex;align-items:center;gap:5px;
  font-size:12px;color:var(--a-mute);cursor:pointer;background:none;
  transition:color .16s var(--e-out);
}
.up-reset:hover{color:var(--a-ink);}
.up-reset svg{width:13px;height:13px;}
.up-panel-body{
  flex:1;min-height:0;overflow-y:auto;padding:15px 15px 16px;
  scrollbar-width:none;
}
/* On only while there is something below: a permanent fade would dim the
   last control on a panel that already fits, and keep dimming it after
   you had scrolled to the end of one that did not. */
.up-panel-body.has-more{
  -webkit-mask-image:linear-gradient(180deg,#000 calc(100% - 30px),transparent);
  mask-image:linear-gradient(180deg,#000 calc(100% - 30px),transparent);
}
.up-panel-body::-webkit-scrollbar{display:none;}
.up-panel-foot{
  padding:13px 15px;border-top:1px solid var(--a-line);
  background:var(--a-panel);
}

.up-sec{font-size:11.5px;color:var(--a-mute);padding:0 2px 7px;}
.up-sec:not(:first-child){padding-top:13px;}

/* one option: icon, name, and the sentence that picks it */
.up-opt{
  display:flex;align-items:center;gap:11px;width:100%;text-align:left;
  padding:9px 11px;margin-bottom:5px;border-radius:11px;cursor:pointer;
  background:var(--a-chip);box-shadow:inset 0 0 0 1px var(--a-line);
  transition:background-color .16s var(--e-out),box-shadow .16s var(--e-out);
}
.up-opt:hover{background:var(--a-chip-2);}
.up-opt.is-on{box-shadow:inset 0 0 0 1.5px var(--a-ink);}
.up-opt-ic{
  flex:none;display:grid;place-items:center;
  width:32px;height:32px;border-radius:8px;
  color:var(--a-ink);background:var(--a-panel);
  box-shadow:inset 0 0 0 1px var(--a-line);
}
.up-opt.is-on .up-opt-ic{background:var(--a-btn);color:var(--a-btn-ink);box-shadow:none;}
.up-opt-ic svg{width:16px;height:16px;}
.up-opt-t{display:flex;flex-direction:column;gap:1px;min-width:0;}
.up-opt-t b{font-size:12.5px;font-weight:600;color:var(--a-ink);}
.up-opt-t span{
  font-size:11px;line-height:1.4;color:var(--a-mute);
  overflow:hidden;text-overflow:ellipsis;
}

/* the scale row */
.up-seg{display:grid;grid-template-columns:repeat(5,1fr);gap:5px;}
.up-seg button{
  padding:9px 0;border-radius:9px;cursor:pointer;
  font-size:12px;font-weight:600;font-variant-numeric:tabular-nums;
  color:var(--a-ink);background:var(--a-chip);
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:background-color .16s var(--e-out);
}
.up-seg button:hover:not(:disabled){background:var(--a-chip-2);}
.up-seg button.is-on{background:var(--a-btn);color:var(--a-btn-ink);box-shadow:none;}
.up-seg button:disabled{opacity:.32;cursor:default;}

.up-panel-go{
  display:flex;align-items:center;justify-content:center;gap:8px;
  width:100%;padding:12px 14px;border-radius:11px;cursor:pointer;
  font-size:13.5px;font-weight:600;
  color:var(--a-btn-ink);background:var(--a-btn);
  transition:opacity .18s var(--e-out),transform .18s var(--e-out);
}
.up-panel-go:hover:not(:disabled){transform:translateY(-1px);}
.up-panel-go:disabled{opacity:.35;cursor:default;transform:none;}
.up-panel-go b{font-variant-numeric:tabular-nums;opacity:.7;font-weight:600;}
.up-panel-note{padding-top:9px;font-size:11px;line-height:1.45;color:var(--a-mute);text-align:center;}

@media (max-width:1080px){
  .up-room{grid-template-columns:78px minmax(0,1fr) 290px;}
}
@media (max-width:860px){
  .up-room{grid-template-columns:1fr;height:auto;}
  .up-strip{flex-direction:row;overflow-x:auto;overflow-y:hidden;}
  .up-strip-add,.up-strip-item{width:74px;flex:none;}
  .up-stage{min-height:44vh;}
}

/* the wait mark turns while a frame is out at the engine */
.up-star.is-spin{animation:up-spin .9s linear infinite;transform-origin:50% 50%;}
@keyframes up-spin{to{transform:rotate(360deg);}}

/* Enhance opens on the same centred card as Upscale, so it is centred
   the same way — and both stop being centred once the room is up, where
   a narrow heading floating over a full-width layout reads as a mistake. */
[data-tool="enhance"] .ut-head{text-align:center;margin-left:auto;margin-right:auto;}
[data-tool="enhance"] .hub-sub{margin-left:auto;margin-right:auto;}
[data-tool="upscale"].has-room .ut-head,
[data-tool="enhance"].has-room .ut-head{
  max-width:none;text-align:left;margin-left:0;margin-right:0;margin-bottom:20px;
}
[data-tool="upscale"].has-room .hub-sub,
[data-tool="enhance"].has-room .hub-sub{margin-left:0;margin-right:0;}

/* ── the opening card, centred in the space it has ──
   Both finishing pages open on it. Hung off the top of a tall empty page
   it looked like the layout had failed to load; in the middle it reads as
   the one thing being asked for. */
.up.is-empty{
  display:grid;place-items:center;
  min-height:clamp(340px,calc(100vh - 330px),600px);
}
.up.is-empty .up-card{margin:0;}
/* the heading above it is centred to match, on both pages */
[data-tool="upscale"] .ut-head,
[data-tool="enhance"] .ut-head{margin-bottom:26px;}

/* ── Enhance: the settings ──
   Only drawn for the fixes whose engine actually reads them. Nothing here
   is sent until Enhance is pressed, so a value can be moved back and
   forth for nothing. */
.up-dial{padding-bottom:14px;}
.up-dial-row{display:flex;align-items:center;justify-content:space-between;gap:10px;}
.up-dial-t{display:block;font-size:12px;font-weight:500;color:var(--a-ink);padding-bottom:6px;}
.up-dial-row .up-dial-t{padding-bottom:0;}
.up-dial-v{
  font-size:11.5px;font-weight:600;font-variant-numeric:tabular-nums;
  color:var(--a-ink);background:var(--a-chip);
  padding:2px 7px;border-radius:6px;
  box-shadow:inset 0 0 0 1px var(--a-line);
}
.up-dial-h{font-size:11px;line-height:1.45;color:var(--a-mute);padding-top:5px;}
.up-dial-r{
  width:100%;margin-top:8px;accent-color:var(--a-ink);
  cursor:ew-resize;
}
.up-dial-text{
  display:block;width:100%;padding:9px 10px;border:0;resize:vertical;
  border-radius:9px;font:inherit;font-size:12.5px;line-height:1.45;
  color:var(--a-ink);background:var(--a-chip);
  box-shadow:inset 0 0 0 1px var(--a-line);
}
.up-dial-text::placeholder{color:var(--a-mute);}
.up-dial-text:focus{outline:none;box-shadow:inset 0 0 0 1.5px var(--a-ink);}

/* the switch */
.up-switch{
  appearance:none;-webkit-appearance:none;
  position:relative;flex:none;width:38px;height:22px;border-radius:11px;
  cursor:pointer;background:var(--a-chip);
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:background-color .2s var(--e-out);
}
.up-switch::after{
  content:"";position:absolute;top:3px;left:3px;
  width:16px;height:16px;border-radius:50%;
  background:var(--a-mute);
  transition:transform .2s var(--e-out),background-color .2s var(--e-out);
}
.up-switch:checked{background:var(--a-btn);box-shadow:none;}
.up-switch:checked::after{transform:translateX(16px);background:var(--a-btn-ink);}
.up-switch:disabled{opacity:.4;cursor:default;}

/* ── Enhance: the three skin looks ──
   A face on each, because which kind of skin somebody wants is a thing
   they recognise on sight and struggle to put into words. */
.up-looks{display:grid;grid-template-columns:1fr 1fr;gap:7px;padding-bottom:10px;}
.up-look{
  position:relative;aspect-ratio:1/1;border-radius:11px;overflow:hidden;
  cursor:pointer;background:var(--a-chip);
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:box-shadow .16s var(--e-out),transform .16s var(--e-out);
}
/* Beauty close-ups, cropped square just below the hairline. */
.up-look img{width:100%;height:100%;object-fit:cover;object-position:50% 22%;display:block;}
/* the name sits on the picture, so it needs its own ground */
.up-look span{
  position:absolute;left:0;right:0;bottom:0;
  padding:14px 8px 6px;
  font-size:11.5px;font-weight:600;color:#fff;text-align:left;
  background:linear-gradient(180deg,transparent,rgba(0,0,0,.78));
}
.up-look:hover{transform:translateY(-2px);}
.up-look.is-on{box-shadow:0 0 0 2px var(--a-ink);}
/* a tick, so the choice reads at a glance and not only by the outline */
.up-look.is-on::after{
  content:"\2713";position:absolute;top:6px;right:6px;
  width:19px;height:19px;border-radius:50%;
  display:grid;place-items:center;font-size:10px;font-weight:700;
  color:var(--a-btn-ink);background:var(--a-btn);
}
.up-look:disabled{opacity:.45;cursor:default;}

/* Upscale: the price rides on the option it belongs to, so the choice
   and its cost are read in one movement rather than two. */
.up-opt-cr{
  margin-left:auto;flex:none;display:inline-flex;align-items:center;gap:4px;
  font-size:12.5px;font-weight:600;font-variant-numeric:tabular-nums;
  color:var(--a-mute);
}
.up-opt.is-on .up-opt-cr{color:var(--a-ink);}
.up-opt-cr .up-star{width:11px;height:11px;}

/* ══ Upscale, on its own layout ══
   A column, centred, read downward: the photographs you brought, the
   one you are looking at, how much bigger, and go. It shared the
   three-column room with Enhance, which is right for a panel of dials
   and wrong here — this page holds one decision and the sidebar was
   putting it where the eye arrives last. Enhance keeps the room. */
.uz-col{
  width:100%;max-width:600px;margin:0 auto;
  display:flex;flex-direction:column;align-items:center;gap:18px;
}

/* ── what you brought ── */
.uz-strip{
  display:flex;align-items:center;gap:8px;
  max-width:100%;padding:2px;overflow-x:auto;scrollbar-width:none;
}
.uz-strip::-webkit-scrollbar{display:none;}
.uz-add,.uz-thumb{
  position:relative;flex:none;width:52px;height:52px;
  border-radius:13px;overflow:hidden;cursor:pointer;
  background:var(--a-chip);box-shadow:inset 0 0 0 1px var(--a-line);
  transition:box-shadow .18s var(--e-out),transform .18s var(--e-out);
}
.uz-add{display:grid;place-items:center;color:var(--a-mute);}
.uz-add svg{width:15px;height:15px;}
.uz-add:hover{color:var(--a-ink);box-shadow:inset 0 0 0 1px var(--a-ink);}
.uz-thumb img{width:100%;height:100%;object-fit:cover;display:block;}
.uz-thumb:hover{transform:translateY(-1px);}
.uz-thumb.is-on{box-shadow:0 0 0 2px var(--a-ink);}
/* a hairline on the ones that have been through, so the strip reports
   progress without reaching for a second colour */
.uz-thumb.is-done::after{
  content:"";position:absolute;left:0;right:0;bottom:0;height:3px;
  background:var(--a-ink);
}
.uz-x{
  position:absolute;top:3px;right:3px;width:16px;height:16px;
  border-radius:50%;display:grid;place-items:center;font-size:8px;
  color:#fff;background:rgba(0,0,0,.62);
  opacity:0;transition:opacity .16s var(--e-out);
}
.uz-thumb:hover .uz-x{opacity:1;}

/* ── the picture ── */
.uz-stage{width:100%;display:flex;flex-direction:column;align-items:center;gap:11px;}
.uz-frame{
  position:relative;margin:0;max-width:100%;line-height:0;
  border-radius:16px;overflow:hidden;background:var(--a-chip);
  box-shadow:inset 0 0 0 1px var(--a-line), 0 26px 50px -34px rgba(0,0,0,.85);
}
.uz-frame img{
  display:block;width:auto;height:auto;
  max-width:100%;max-height:clamp(240px,42vh,440px);object-fit:contain;
}
.uz-work{
  position:absolute;inset:0;display:grid;place-items:center;
  background:rgba(0,0,0,.42);
}
.uz-work svg{width:20px;height:20px;color:#fff;}
.uz-done{
  position:absolute;left:10px;top:10px;padding:4px 9px;border-radius:999px;
  font-size:10.5px;font-weight:600;letter-spacing:.02em;
  color:var(--a-btn-ink);background:var(--a-btn);
}
/* the two numbers that matter, where a caption goes */
.uz-cap{
  margin:0;display:flex;align-items:center;gap:8px;
  font-size:11.5px;color:var(--a-mute);font-variant-numeric:tabular-nums;
}
.uz-cap span{opacity:.55;}
.uz-bad{margin:0;padding:44px 20px;font-size:12px;color:var(--a-mute);text-align:center;}

/* ── the one decision, on one line ──
   Two cards and a full-width slab was a lot of furniture for a toggle
   and a verb, and it pulled the eye away from the photograph, which is
   the only thing on this page worth looking at. The controls are the
   same height now and sit on one line.

   The fill is the theme token with a soft dome of light over it: a
   radial highlight from above and a gentle vertical fade, both in
   plain white and black so they read the same way over a white button
   in the dark theme and a black one in the light. */
.uz-bar{width:100%;display:flex;flex-direction:column;gap:9px;}
.uz-row{display:flex;align-items:stretch;gap:9px;}

.uz-seg{
  flex:none;display:grid;grid-template-columns:1fr 1fr;gap:3px;
  padding:3px;border-radius:13px;
  background:var(--a-chip);
  box-shadow:inset 0 0 0 1px var(--a-line), inset 0 1px 2px rgba(0,0,0,.13);
}
.uz-size{
  min-width:56px;padding:0 15px;border-radius:10px;cursor:pointer;
  display:grid;place-items:center;
  font-size:12.5px;font-weight:600;color:var(--a-mute);
  font-variant-numeric:tabular-nums;
  transition:color .16s var(--e-out),background-color .16s var(--e-out),
             box-shadow .16s var(--e-out);
}
.uz-size:hover:not(:disabled):not(.is-on){color:var(--a-ink);}
.uz-size.is-on{
  color:var(--a-btn-ink);background-color:var(--a-btn);
  background-image:
    radial-gradient(120% 120% at 50% -30%, rgba(255,255,255,.20), transparent 62%),
    linear-gradient(180deg, rgba(255,255,255,.07), rgba(0,0,0,.10));
  box-shadow:inset 0 1px 0 rgba(255,255,255,.20), 0 2px 6px -3px rgba(0,0,0,.55);
}
.uz-size:disabled{opacity:.3;cursor:default;}

.uz-go{
  position:relative;flex:1;min-height:44px;
  display:flex;align-items:center;justify-content:center;gap:8px;
  padding:0 46px 0 18px;border-radius:13px;cursor:pointer;
  font-size:13px;font-weight:600;letter-spacing:-.005em;
  color:var(--a-btn-ink);background-color:var(--a-btn);
  background-image:
    radial-gradient(130% 150% at 50% -40%, rgba(255,255,255,.22), transparent 60%),
    linear-gradient(180deg, rgba(255,255,255,.09), rgba(0,0,0,.17));
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.26),
    inset 0 -1px 0 rgba(0,0,0,.16),
    0 8px 20px -11px rgba(0,0,0,.65);
  transition:background-image .2s var(--e-out),box-shadow .2s var(--e-out),
             transform .12s var(--e-out);
}
.uz-go:hover:not(:disabled){
  background-image:
    radial-gradient(130% 150% at 50% -40%, rgba(255,255,255,.32), transparent 62%),
    linear-gradient(180deg, rgba(255,255,255,.14), rgba(0,0,0,.06));
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.32),
    inset 0 -1px 0 rgba(0,0,0,.14),
    0 11px 26px -11px rgba(0,0,0,.7);
}
.uz-go:active:not(:disabled){
  transform:translateY(1px);
  box-shadow:inset 0 2px 4px rgba(0,0,0,.2);
}
.uz-go:disabled{opacity:.38;cursor:default;box-shadow:none;}
.uz-go .up-star{width:12px;height:12px;}
.uz-go-cr{
  position:absolute;right:15px;font-size:12px;font-weight:600;
  opacity:.62;font-variant-numeric:tabular-nums;
}
/* ── the small print ── */
.uz-foot{display:flex;align-items:center;justify-content:center;gap:18px;padding-top:1px;}
.uz-ghost{
  font-size:11.5px;font-weight:500;color:var(--a-mute);cursor:pointer;
  transition:color .16s var(--e-out);
}
.uz-ghost:hover{color:var(--a-ink);}
.uz-ghost:disabled{opacity:.4;cursor:default;}
.uz-ghost.is-str{color:var(--a-ink);}

@media (max-width:560px){
  .uz-col{gap:14px;}
  .uz-frame img{max-height:36vh;}
}

.uz-ghost.is-dim{color:var(--a-mute);opacity:.7;cursor:default;}

/* ── Enhance: the settings, folded ──
   A row that behaves like the section heading it replaces: same size,
   same colour, same place. The count sits beside it so folding it away
   does not hide the fact that there is something there, and the chevron
   turns rather than swapping for a second icon. */
.up-fold{
  display:flex;align-items:center;gap:7px;width:100%;
  margin-top:13px;padding:0 2px 7px;cursor:pointer;
  font-size:11.5px;color:var(--a-mute);background:none;
  transition:color .16s var(--e-out);
}
.up-fold:hover{color:var(--a-ink);}
.up-fold em{
  font-style:normal;font-size:10px;font-weight:600;
  padding:1px 6px;border-radius:999px;
  color:var(--a-mute);background:var(--a-chip);
  box-shadow:inset 0 0 0 1px var(--a-line);
}
.up-fold svg{
  width:13px;height:13px;margin-left:auto;
  transition:transform .2s var(--e-out);
}
.up-fold.is-open svg{transform:rotate(180deg);}
.up-fold.is-open{color:var(--a-ink);}
/* the dials arrive rather than appearing */
.up-fold-in{animation:upFold .22s var(--e-out) both;}
@keyframes upFold{
  from{opacity:0;transform:translateY(-4px);}
  to{opacity:1;transform:none;}
}

/* ══ Enhance opens on a fault dissolving ══
   Upscale shows one photograph split by a hairline, because comparing
   two states is exactly its subject. Enhance’s subject is a fault
   leaving, so there is no line and no halves: the flat, grainy, soft
   copy simply thins out across the frame into the photograph it should
   have been. Both masks are the same diagonal read in opposite
   directions, so the two layers hand over without an edge anywhere.

   The grain is drawn rather than photographed — two offset dot grids at
   three and four pixels, overlaid — so it costs nothing and sits only
   over the half that is meant to look broken. */
.up-hero.is-fade .up-hero-a{
  filter:grayscale(1) contrast(.62) brightness(.86) blur(2.4px);
}
.up-hero.is-fade .up-hero-b{
  filter:grayscale(1) contrast(1.16) brightness(1.02);
  clip-path:none;
  -webkit-mask-image:linear-gradient(100deg,transparent 26%,#000 64%);
  mask-image:linear-gradient(100deg,transparent 26%,#000 64%);
}
.up-hero.is-fade::before{
  content:"";position:absolute;inset:0;z-index:2;pointer-events:none;
  background-image:
    radial-gradient(rgba(255,255,255,.55) .6px, transparent .7px),
    radial-gradient(rgba(0,0,0,.6) .6px, transparent .7px);
  background-size:3px 3px, 4px 4px;
  background-position:0 0, 1px 2px;
  mix-blend-mode:overlay;
  -webkit-mask-image:linear-gradient(100deg,#000 24%,transparent 60%);
  mask-image:linear-gradient(100deg,#000 24%,transparent 60%);
}
/* the floor under the title stays on top of both */
.up-hero::after{z-index:3;}

/* ── the two utility pages, tightened for the dark shell ──
   Resize and Remove BG were drawn for the marketing pages and inherit
   three details that read differently on a near-black ground. */

/* A white button at 40% over #0a0a0a is a solid grey slab, and a solid
   slab reads as broken rather than as waiting for something. Given the
   panel’s own chip surface and a hairline it recedes, which is what a
   control that is not ready yet should do. */
[data-app] .ut-run:disabled{
  opacity:1;
  color:var(--a-mute);
  background:var(--a-chip);
  box-shadow:inset 0 0 0 1px var(--a-line);
}

/* The stage is a well and the panel beside it is a card, which is the
   right pairing — but the well had no edge, so on a dark page it read as
   an absence rather than a surface. One hairline, the same one the card
   wears, and it becomes a place to drop something into. */
[data-app] .ut-stage{
  box-shadow:inset 0 0 0 1px var(--a-line);
}

/* A filled mid-grey circle is the one shape on these pages that belongs
   to no other page. Every icon that means "a thing you can act on" here
   is a rounded square on the chip surface — the option rows, the card
   heads, the segment. This one joins them. */
[data-app] .ut-empty-ic{
  width:52px;height:52px;border-radius:15px;
  color:var(--a-ink);background:var(--a-chip);
  box-shadow:inset 0 0 0 1px var(--a-line);
}
[data-app] .ut-empty-ic svg{width:22px;height:22px;}

/* ── an empty stage is a promise, not a canvas ──
   Remove BG sizes its stage at 100vh − 268px so a dropped photograph gets
   the whole window. Before anything is dropped that is 632px of nothing,
   and it pushed the four worked examples — the part that actually shows
   what the tool does to hair and glass — a full screen below the fold. It
   only needs to be that tall once it is holding something.

   Keyed off the empty panel the page already toggles, so there is no new
   state to keep in step. */
[data-app] [data-tool="removebg"] .ut-stage:has(.ut-empty:not([hidden])){
  height:clamp(340px,calc(100vh - 500px),430px);
}

/* ══ Resize opens on a card, like the other two ══
   Upscale and Enhance both open on one card with a picture over it, and
   Resize opened on a bare grey well — three finishing tools, three front
   doors. It uses the same card now, and the demo clip goes where they
   put a photograph: not a wash behind the words, not a band nobody
   scrolled to, just the thing itself, playing, at the size it was made
   for. The tool is drawn behind it and shown the moment there is a file.

   Keyed off the empty panel the page already toggles, so there is no
   second source of truth about whether a photograph exists. */
/* A shade taller than the clip itself, and letterboxed rather than
   cropped: the size labels live close to the left and right edges, so
   filling the box would eat the one thing the clip is there to show. The
   bands top and bottom are set to the colour the clip’s own sheet renders
   at once the filter below has had it — #fafafa through grayscale,
   brightness .92 and contrast 1.03 comes out #e9e9e9 — so they are not
   bands, they are the sheet. */
.up-hero.is-clip{aspect-ratio:5/3;background:#e9e9e9;}
.up-hero.is-clip video{
  position:absolute;inset:0;width:100%;height:100%;
  object-fit:contain;display:block;
}
[data-app] .up-hero.is-clip video{
  /* the clip is a white sheet; a shade off full brightness sits it in
     the card instead of glaring out of the top of it */
  filter:grayscale(1) brightness(.92) contrast(1.03);
}

[data-tool="resize"] .container:has(.ut-empty[hidden]) [data-ut-open]{display:none;}
[data-tool="resize"] .container:has(.ut-empty:not([hidden])) .ut-grid{display:none;}

[data-tool="resize"] .up-card{max-width:560px;margin:0 auto;}
[data-tool="resize"] .up-card-note{
  padding-top:14px;font-size:11.5px;color:var(--a-mute);text-align:center;
}

/* ══ the three finishing pages open at the same height ══
   Upscale has been vertically centring its opening card since it was
   written: .ut-main is a flex box the height of the window. Enhance and
   Resize were never added to that rule, so they hung off the top instead
   — same card, same heading, same everything, sitting 32px higher.
   Moving between the two pages made the whole page jump.

   Only while the card is up. Once there is a photograph, Enhance opens
   its three-column room and Resize its grid, and both of those want the
   top of the page rather than the middle of it. */
[data-tool="enhance"]:not(.has-room) .ut-main,
[data-tool="resize"] .ut-main:has(.ut-empty:not([hidden])){
  display:flex;align-items:center;
  min-height:calc(100vh - var(--anav-h,61px));
  padding-top:22px;padding-bottom:100px;
}
[data-tool="enhance"]:not(.has-room) .ut-main > .container,
[data-tool="resize"] .ut-main:has(.ut-empty:not([hidden])) > .container{width:100%;}

/* ══ Templates: the frame that comes back ══
   It lands over the one being copied, in the same box, so the
   comparison is a glance rather than a scroll. */
.tpl-modal-out{
  position:absolute;inset:0;width:100%;height:100%;
  object-fit:cover;display:block;z-index:2;
  animation:tplIn .3s var(--e-out) both;
}
@keyframes tplIn{from{opacity:0;}to{opacity:1;}}
.tpl-modal-busy{
  position:absolute;inset:0;z-index:3;
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;
  background:rgba(0,0,0,.55);color:#fff;
  font-size:12px;font-weight:600;
}
.tpl-modal-busy svg{width:22px;height:22px;animation:upSpin .9s linear infinite;}
@keyframes upSpin{to{transform:rotate(360deg);}}

.tpl-done{display:flex;gap:8px;padding-top:10px;}
.tpl-done-btn{
  flex:1;padding:10px 12px;border-radius:11px;cursor:pointer;
  font-size:12.5px;font-weight:600;
  color:var(--a-ink);background:var(--a-chip);
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:background-color .16s var(--e-out);
}
.tpl-done-btn:hover{background:var(--a-chip-2);}
.tpl-done-btn.is-solid{
  color:var(--a-btn-ink);background:var(--a-btn);box-shadow:none;
}
.tpl-done-btn.is-solid:hover{opacity:.9;}

/* ══ Templates: the modal, corrected ══ */

/* The frame was being cropped to fill a column narrower than it is.
   These are portraits and the whole composition is the point — what the
   light does at the top of the frame is half of what is being copied —
   so it is shown whole, on a ground of its own, in a wider column. */
[data-app] .tpl-modal-box{max-width:1120px;}
[data-app] .tpl-modal-grid{grid-template-columns:minmax(0,1.12fr) minmax(0,1fr);}
[data-app] .tpl-modal-ref{background:var(--a-sunk,#0e0e0e);}
[data-app] .tpl-modal-ref img{object-fit:contain;min-height:420px;}

/* A white circle with a white glyph in it. The button borrows the
   marketing ink token, which the app theme flips to near-white, so the
   cross went invisible the moment the studio shell wrapped it. */
[data-app] .tpl-modal-x{
  background:var(--a-btn);color:var(--a-btn-ink);
  box-shadow:0 8px 20px -10px rgba(0,0,0,.7);
}
[data-app] .tpl-modal-x:hover{background:var(--a-btn);opacity:.9;}

/* ── the prompt, withheld ──
   Blurred rather than removed. A gap where the prompt should be says
   nothing; four lines of unreadable text say there is something here,
   it is long, and it is written — which is the argument for paying.

   The blur is a curtain, not a lock: the words are still in the page for
   anyone who opens the inspector. The prompts ship in
   js/templates-data.js to every visitor either way, so this is honest
   about what it is. Real gating means serving them per session. */
.tpl-prompt.is-locked{position:relative;min-height:132px;}
.tpl-prompt.is-locked p{
  filter:blur(4.5px);
  user-select:none;-webkit-user-select:none;pointer-events:none;
  opacity:.72;
}
.tpl-prompt.is-locked .tpl-prompt-copy{display:none;}

.tpl-locked{
  position:absolute;inset:0;z-index:2;
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:4px;padding:14px 18px;text-align:center;border-radius:12px;
  background:linear-gradient(180deg,rgba(20,19,18,.55),rgba(20,19,18,.86));
}
.tpl-locked > svg{width:17px;height:17px;color:rgba(255,255,255,.7);margin-bottom:2px;}
.tpl-locked b{font-size:13px;font-weight:600;color:#fff;}
.tpl-locked span{
  font-size:11.5px;line-height:1.5;color:rgba(255,255,255,.62);
  max-width:34ch;
}
.tpl-locked-go{
  margin-top:9px;padding:8px 15px;border-radius:100px;
  font-size:12px;font-weight:600;white-space:nowrap;
  color:#151515;background:#fff;
  transition:opacity .16s var(--e-out),transform .16s var(--e-out);
}
.tpl-locked-go:hover{opacity:.9;transform:translateY(-1px);}

/* ── Templates: through the run ──
   On the frame rather than under it, because the frame is the thing
   that changes. Quiet until the pointer is over the picture, so a still
   modal is not wearing two buttons it does not need yet. */
.tpl-arrow{
  position:absolute;top:50%;transform:translateY(-50%);z-index:3;
  width:38px;height:38px;border-radius:50%;cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  color:#151515;background:rgba(255,255,255,.92);
  box-shadow:0 10px 26px -12px rgba(0,0,0,.8);
  opacity:0;
  transition:opacity .2s var(--e-out),transform .2s var(--e-out),background-color .2s var(--e-out);
}
.tpl-arrow.is-prev{left:14px;}
.tpl-arrow.is-next{right:14px;}
.tpl-arrow svg{width:16px;height:16px;}
.tpl-modal-ref:hover .tpl-arrow,
.tpl-arrow:focus-visible{opacity:1;}
.tpl-arrow:hover{background:#fff;transform:translateY(-50%) scale(1.06);}
/* a pointer never arrives on a touch screen, so there they simply stay */
@media (hover:none){.tpl-arrow{opacity:1;}}

.tpl-modal-pos{
  font-size:11.5px;color:var(--ink-mute);
  font-variant-numeric:tabular-nums;margin-left:auto;
}

/* ── Templates: the prompt, editable ──
   On Plus and above the panel is the prompt rather than a picture of
   it. It stays monospace and stays the same size, so nothing jumps when
   the cursor lands — only the caret and a ring say it is live. */
.tpl-prompt.is-editable p{cursor:text;outline:none;}
.tpl-prompt.is-editable{
  transition:box-shadow .18s var(--e-out);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.10);
}
.tpl-prompt.is-editable:focus-within{box-shadow:inset 0 0 0 1.5px rgba(255,255,255,.34);}

.tpl-prompt-foot{
  display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  padding:8px 2px 0;font-size:11.5px;color:var(--a-mute);
}
.tpl-prompt-reset{
  margin-left:auto;font-size:11.5px;font-weight:600;cursor:pointer;
  color:var(--a-ink);text-decoration:underline;text-underline-offset:3px;
  transition:opacity .16s var(--e-out);
}
.tpl-prompt-reset:hover{opacity:.7;}

/* ══ Templates: casting ══
   A face is recognised, not read, so the row is faces — name underneath,
   small, for when two of them look alike. Only ever drawn on the 53
   templates whose prompt asks for somebody. */
.tpl-cast-note{font-size:11.5px;line-height:1.5;color:var(--a-mute);padding-bottom:11px;}
.tpl-cast-top{display:flex;align-items:center;gap:8px;padding-bottom:10px;}
.tpl-cast-tabs{
  display:flex;gap:3px;padding:3px;border-radius:11px;
  background:var(--a-chip);box-shadow:inset 0 0 0 1px var(--a-line), inset 0 1px 2px rgba(0,0,0,.13);
}
.tpl-cast-tabs button{
  padding:6px 13px;border-radius:8px;cursor:pointer;
  font-size:11.5px;font-weight:600;color:var(--a-mute);
  transition:color .16s var(--e-out),background-color .16s var(--e-out);
}
.tpl-cast-tabs button:hover{color:var(--a-ink);}
.tpl-cast-tabs button.is-on{
  color:var(--a-btn-ink);background-color:var(--a-btn);
  background-image:radial-gradient(120% 120% at 50% -30%, rgba(255,255,255,.20), transparent 62%);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.2);
}
.tpl-cast-own{
  margin-left:auto;display:inline-flex;align-items:center;gap:6px;
  padding:8px 12px;border-radius:10px;cursor:pointer;
  font-size:11.5px;font-weight:600;color:var(--a-ink);
  background:var(--a-chip);box-shadow:inset 0 0 0 1px var(--a-line);
  transition:box-shadow .16s var(--e-out);
}
.tpl-cast-own:hover{box-shadow:inset 0 0 0 1px var(--a-ink);}
.tpl-cast-own svg{width:13px;height:13px;}

/* One row, scrolled sideways: twenty-three faces down the page would be
   the whole panel, and casting is one decision, not a catalogue. */
.tpl-cast-row{
  display:grid;grid-template-columns:repeat(auto-fill,minmax(46px,1fr));
  gap:7px 6px;padding:2px;
}
.tpl-cast-pick{
  position:relative;cursor:pointer;min-width:0;
  display:flex;flex-direction:column;align-items:center;gap:4px;
}
.tpl-cast-pick img{
  width:100%;aspect-ratio:1/1;height:auto;
  border-radius:11px;object-fit:cover;display:block;
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:box-shadow .16s var(--e-out),transform .16s var(--e-out);
}
.tpl-cast-pick span{
  font-size:9.5px;color:var(--a-mute);max-width:100%;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.tpl-cast-pick:hover img{transform:translateY(-2px);}
.tpl-cast-pick.is-on img{box-shadow:0 0 0 2px var(--a-ink);}
.tpl-cast-pick.is-on span{color:var(--a-ink);font-weight:600;}
/* locked faces stay visible — the roster is what Starter is bought for,
   so it is shown rather than hidden behind a number */
.tpl-cast-pick.is-locked img{filter:grayscale(1) brightness(.45);}
.tpl-cast-pick.is-locked em{
  position:absolute;top:4px;right:4px;
  width:16px;height:16px;border-radius:50%;
  display:grid;place-items:center;font-style:normal;font-size:9px;font-weight:700;
  color:var(--a-btn-ink);background:var(--a-btn);
}
.tpl-cast-pick.is-own img{box-shadow:0 0 0 2px var(--a-ink);}

/* ── Templates: the button stays where you can reach it ──
   The panel grew a roster and the one control that matters slid off the
   bottom of a modal that scrolls. Sticking the foot to the bottom of the
   scroller costs nothing and holds at any window height, which trimming
   padding until it happened to fit would not. */
[data-app] .tpl-modal-foot{
  position:sticky;bottom:0;z-index:5;margin-top:auto;padding-top:16px;
  background:linear-gradient(180deg,transparent,var(--a-panel) 30%);
}
[data-app] .tpl-modal-foot .tpl-hint{padding-bottom:2px;}

/* a shade tighter, so the roster costs less of the panel than it did */
[data-app] .tpl-cast-row{gap:6px 5px;}
[data-app] .tpl-cast-note{padding-bottom:9px;}

/* ══ Templates: the modal, given the room it needs ══
   Three decisions were stacked in a 430px column and the third one — the
   roster — pushed the button off the bottom. Widening the box lets the
   faces be faces instead of stamps, and the trims below buy back the
   height that costs, so nothing scrolls at a normal window. */
[data-app] .tpl-modal-box{max-width:1340px;}
[data-app] .tpl-modal-grid{grid-template-columns:minmax(0,.92fr) minmax(0,1fr);}
[data-app] .tpl-modal-side{padding:26px 26px 22px;}

/* ── the trims ── */
/* the drop zone was sized for a page, not for a step in a panel */
[data-app] .tpl-drop{min-height:0;}
[data-app] .tpl-drop-empty{padding:18px 16px;}
[data-app] .tpl-drop-empty svg{width:20px;height:20px;}
[data-app] .tpl-prompt p{max-height:92px;}
[data-app] .tpl-extra textarea{min-height:44px;}
[data-app] .tpl-step{padding-bottom:16px;}

/* ── and the faces ──
   Sixty-four instead of forty-six. At a glance you are choosing between
   people rather than between thumbnails, which is the whole job. */
[data-app] .tpl-cast-row{grid-template-columns:repeat(auto-fill,minmax(62px,1fr));gap:8px 7px;}
[data-app] .tpl-cast-pick span{font-size:10px;}


/* ── the last forty pixels ──
   With the roster beside them the product and the prompt are the tall
   column, so the trim goes there. Nothing here changes what anything
   does; it is the air between them. */
[data-app] .tpl-drop-empty{padding:14px 16px;}
[data-app] .tpl-prompt p{max-height:78px;}
[data-app] .tpl-extra textarea{min-height:38px;}
[data-app] .tpl-step{padding-bottom:13px;}
[data-app] .tpl-lib-row img{width:38px;height:38px;}
[data-app] .tpl-modal-title{font-size:21px;}



/* the tile that asks for a face, drawn like the ones that have one */
.tpl-cast-add{
  width:100%;aspect-ratio:1/1;border-radius:11px;
  display:grid;place-items:center;color:var(--a-mute);
  background:var(--a-chip);
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:color .16s var(--e-out),box-shadow .16s var(--e-out),transform .16s var(--e-out);
}
.tpl-cast-add svg{width:16px;height:16px;}
.tpl-cast-pick.is-add:hover .tpl-cast-add{
  color:var(--a-ink);box-shadow:inset 0 0 0 1px var(--a-ink);transform:translateY(-2px);
}

/* ══ Templates: the roster, behind a door ══
   Forty-three headshots laid open under a form is the form buried. Three
   doors instead, sized to their own words rather than stretched across
   the panel, and a sheet that opens over them. */
.tpl-cast-doors{display:flex;flex-wrap:wrap;gap:7px;}
.tpl-door{
  position:relative;display:inline-flex;align-items:center;gap:7px;
  padding:9px 14px;border-radius:11px;cursor:pointer;
  font-size:12px;font-weight:600;color:var(--a-ink);
  background-color:var(--a-chip);
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:box-shadow .18s var(--e-out),background-color .18s var(--e-out),
             transform .14s var(--e-out),color .18s var(--e-out);
}
.tpl-door:hover{box-shadow:inset 0 0 0 1px var(--a-ink);transform:translateY(-1px);}
.tpl-door:active{transform:translateY(0);}
.tpl-door.is-on{
  color:var(--a-btn-ink);background-color:var(--a-btn);
  background-image:radial-gradient(120% 140% at 50% -40%, rgba(255,255,255,.24), transparent 62%);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.22), 0 6px 16px -8px rgba(0,0,0,.7);
}
.tpl-door em{
  font-style:normal;font-size:10px;font-weight:600;opacity:.5;
  font-variant-numeric:tabular-nums;
}
.tpl-door svg{width:13px;height:13px;}

/* ── the sheet ──
   Upward. The model is the last step on the panel, so downward is off
   the bottom of a modal that is already at its full height — it opened
   into nothing and looked like nothing had happened.

   It grows out of the doors rather than fading in over them: origin at
   the bottom, a little scale and a little lift, on a curve with some
   overshoot so it arrives rather than appears. */
.tpl-cast-sheet{
  position:absolute;left:0;right:0;bottom:calc(100% + 9px);z-index:6;
  padding:11px;border-radius:15px;
  background:color-mix(in srgb,var(--a-panel) 92%,transparent);
  backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);
  box-shadow:
    inset 0 0 0 1px var(--a-line),
    inset 0 1px 0 rgba(255,255,255,.06),
    0 30px 60px -22px rgba(0,0,0,.9);
  transform-origin:50% 100%;
  animation:tplSheet .34s cubic-bezier(.2,1.24,.36,1) both;
}
@keyframes tplSheet{
  from{opacity:0;transform:translateY(10px) scale(.96);}
  to{opacity:1;transform:none;}
}
/* the little beak, so it belongs to the door under it */
.tpl-cast-sheet::after{
  content:"";position:absolute;left:34px;bottom:-5px;
  width:10px;height:10px;transform:rotate(45deg);
  background:var(--a-panel);
  box-shadow:1px 1px 0 var(--a-line);
}
.tpl-cast-sheet-top{
  display:flex;align-items:center;justify-content:space-between;
  padding:1px 3px 10px;
}
.tpl-cast-sheet-top b{
  font-size:11px;font-weight:600;letter-spacing:.07em;text-transform:uppercase;
  color:var(--a-mute);
}
.tpl-cast-sheet-top button{
  width:22px;height:22px;border-radius:50%;cursor:pointer;font-size:10px;
  display:grid;place-items:center;color:var(--a-mute);
  transition:color .16s var(--e-out),background-color .16s var(--e-out),transform .16s var(--e-out);
}
.tpl-cast-sheet-top button:hover{color:var(--a-ink);background:var(--a-chip);transform:rotate(90deg);}
.tpl-cast-sheet .tpl-cast-row{
  grid-template-columns:repeat(6,minmax(0,1fr));gap:9px 7px;
  max-height:min(62vh,470px);overflow-y:auto;scrollbar-width:none;
}
.tpl-cast-sheet .tpl-cast-row::-webkit-scrollbar{display:none;}

/* ── the faces arrive in order ──
   Fourteen milliseconds apart, capped at half a second so the tail of a
   long roster is not still landing after you have chosen. */
.tpl-cast-sheet .tpl-cast-pick{
  animation:tplFace .3s var(--e-out) both;
  animation-delay:min(calc(var(--i,0) * 14ms), 500ms);
}
@keyframes tplFace{
  from{opacity:0;transform:translateY(7px) scale(.94);}
  to{opacity:1;transform:none;}
}
.tpl-cast-pick img{transition:box-shadow .16s var(--e-out),transform .16s var(--e-out);}
.tpl-cast-pick:hover img{transform:translateY(-3px) scale(1.03);}
.tpl-cast-pick.is-on img{box-shadow:0 0 0 2px var(--a-ink);}
/* a tick on the cast one, so the choice reads without comparing rings */
.tpl-cast-pick.is-on::after{
  content:"\2713";position:absolute;top:4px;right:4px;
  width:17px;height:17px;border-radius:50%;
  display:grid;place-items:center;font-size:9px;font-weight:700;
  color:var(--a-btn-ink);background:var(--a-btn);
  animation:tplTick .22s var(--e-out) both;
}
@keyframes tplTick{from{opacity:0;transform:scale(.6);}to{opacity:1;transform:none;}}

/* the step is the sheet’s frame of reference */
[data-tpl-cast-step] .tpl-step-body{position:relative;}

@media (prefers-reduced-motion:reduce){
  .tpl-cast-sheet,.tpl-cast-sheet .tpl-cast-pick,.tpl-cast-chosen,
  .tpl-cast-pick.is-on::after{animation:none;}
}

/* ── while you are choosing, that is all the step is ──
   The sheet used to float over the doors, which meant the panel was
   showing the question and the answer at the same time and neither had
   room. Opening it now stands the doors down and puts the roster in
   their place, in the flow — one thing on screen, doing one job. */
/* The doors stay: the one you came through is how you get back, and a
   lit button that cannot be pressed again is a button lying about its
   state. What steps aside is everything else — the sentence explaining
   the step and the card naming who is already cast, neither of which you
   are reading while a roster is open over them. */
.tpl-step-body.is-picking .tpl-cast-note,
.tpl-step-body.is-picking .tpl-cast-chosen{
  opacity:0;pointer-events:none;
  transition:opacity .18s var(--e-out);
}

/* ══ Templates: the doors, with faces on them ══
   Three chips reading "Women 21" told you the count and nothing about
   the cast. Three overlapping faces on the front of each one say what
   kind of roster is behind it, which is the part anybody is actually
   choosing between — and it costs three thumbnails already on the page.

   The upload door keeps the same slot so all three sit on one baseline;
   its circle is dashed, because there is nothing in it yet. */
.tpl-door{padding:8px 13px 8px 8px;gap:9px;}
.tpl-door.is-own{padding-left:9px;}

.tpl-door-faces{display:inline-flex;align-items:center;flex:none;}
.tpl-door-faces img{
  width:26px;height:26px;border-radius:50%;object-fit:cover;display:block;
  box-shadow:0 0 0 2px var(--a-panel);
  transition:transform .22s var(--e-out),box-shadow .18s var(--e-out);
}
.tpl-door-faces img + img{margin-left:-9px;}
/* they fan apart a little when the door is under the pointer */
.tpl-door:hover .tpl-door-faces img{transform:translateX(calc(var(--k,0) * 2px));}
.tpl-door.is-on .tpl-door-faces img{box-shadow:0 0 0 2px var(--a-btn);}

.tpl-door-faces.is-add{
  width:26px;height:26px;border-radius:50%;
  display:grid;place-items:center;color:var(--a-mute);
  box-shadow:inset 0 0 0 1.5px var(--a-line);
  transition:color .18s var(--e-out),box-shadow .18s var(--e-out);
}
.tpl-door-faces.is-add svg{width:12px;height:12px;}
.tpl-door.is-own:hover .tpl-door-faces.is-add{
  color:var(--a-ink);box-shadow:inset 0 0 0 1.5px var(--a-ink);
}

.tpl-door-t{font-size:12.5px;font-weight:600;letter-spacing:-.005em;}
.tpl-door em{
  padding:2px 6px;border-radius:100px;
  font-size:10px;line-height:1.4;
  background:var(--a-line);opacity:1;color:var(--a-mute);
}
.tpl-door.is-on em{background:rgba(0,0,0,.16);color:var(--a-btn-ink);opacity:.8;}

/* ══ Templates: the two steps, given their width and their height ══
   The doors were sized to their own words, which left 150px of the row
   doing nothing. Sized to the row instead they read as three cards — the
   faces on them carry the extra width, which is why this would have
   looked stretched before and does not now. */
.tpl-cast-doors{gap:8px;}
.tpl-cast-doors > *{flex:1;min-width:0;justify-content:flex-start;}

/* Three doors sized to the row are three doors that can be squeezed
   narrower than their contents, and a flex item does not clip: the count
   pushed off to the right by margin-left:auto simply left the button and
   sat on the panel behind it.

   Shortening the label instead was worse — "Women" became "W." — so the
   door keeps a floor: min-width is its own content. It still grows to
   share a wide row, and when three will not fit they wrap onto a second
   line rather than one of them losing its word. */
.tpl-door-faces,.tpl-door em{flex:none;}
.tpl-door-t{white-space:nowrap;}
.tpl-cast-doors{flex-wrap:wrap;}
.tpl-cast-doors > *{min-width:max-content;}
[data-app] .tpl-door{padding:11px 14px 11px 10px;}
[data-app] .tpl-door em{margin-left:auto;}
[data-app] .tpl-door-faces img{width:29px;height:29px;}
[data-app] .tpl-door-faces img + img{margin-left:-10px;}
[data-app] .tpl-door-faces.is-add{width:29px;height:29px;}

/* and the drop zone was a strip rather than a target. It is the first
   thing asked for on the panel and it should look like somewhere a
   photograph goes. */
[data-app] .tpl-drop-empty{padding:26px 16px;gap:9px;}
[data-app] .tpl-drop-empty svg{width:24px;height:24px;}
[data-app] .tpl-drop-empty > span{font-size:12.5px;}

/* ══ Templates: the door that holds the choice ══
   It stops advertising the roster and starts showing the answer: the
   face at full size instead of three overlapped, the name in place of
   the label, and the cross where the count was. The row still reads
   left to right as one sentence — Nora, or Men, or your own — instead of
   a row of questions with the answer parked underneath it. */
.tpl-door.is-cast{
  color:var(--a-btn-ink);background-color:var(--a-btn);
  background-image:radial-gradient(120% 140% at 50% -40%, rgba(255,255,255,.24), transparent 62%);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.22), 0 8px 20px -10px rgba(0,0,0,.75);
  animation:tplCast .3s cubic-bezier(.2,1.2,.36,1) both;
}
@keyframes tplCast{
  from{transform:scale(.97);}
  to{transform:none;}
}
.tpl-door-faces.is-one img{
  width:33px;height:33px;margin-left:0;
  box-shadow:0 0 0 2px rgba(255,255,255,.35);
}
.tpl-door.is-cast .tpl-door-t{font-weight:600;}
.tpl-door-x{
  margin-left:auto;width:22px;height:22px;border-radius:50%;
  display:grid;place-items:center;font-size:10px;cursor:pointer;
  color:var(--a-btn-ink);opacity:.6;
  transition:opacity .16s var(--e-out),background-color .16s var(--e-out),transform .16s var(--e-out);
}
.tpl-door-x:hover{opacity:1;background:rgba(0,0,0,.18);transform:rotate(90deg);}

@media (prefers-reduced-motion:reduce){.tpl-door.is-cast{animation:none;}}

/* ═══════════════════════════════════════════════════════════════════
   PHONE LAYER  ·  ≤820px only
   ═══════════════════════════════════════════════════════════════════
   Appended last and wrapped in a max-width query, so a desktop
   viewport never reaches it.
   =================================================================== */

@media (max-width:820px){

  /* ── the nav bar was unusable, not just tight ───────────────────
     .anav-in is one flex row: logo, links, actions. The links are the
     only part with flex-shrink, and the actions come to 274px of a
     375px screen — so the links were squeezed to a 30px-wide scroller
     with All tools, Campaign, Image, Video, Edit and Templates all
     laid out inside it, past the clip. Every destination in the app
     was present and none of them reachable.

     Six destinations and four controls do not share one phone-width
     line, so the links take their own. --anav-h is declared here
     because two panes size themselves off it and would otherwise
     keep using the 61px fallback and overshoot the viewport. */
  :root{--anav-h:98px;}

  .anav-in{
    flex-wrap:wrap;
    height:auto;
    padding:0 12px;
    column-gap:8px;row-gap:0;
  }
  .anav-logo{order:1;height:52px;}
  .anav-right{order:2;margin-left:auto;height:52px;padding-left:0;}
  .anav-links{
    order:3;
    flex:1 0 100%;
    width:calc(100% + 24px);
    margin:0 -12px;
    padding:0 12px;
    height:46px;
    align-self:auto;
    border-top:1px solid var(--a-line);
  }
  /* the row is its own line now, so it can hold a real target height */
  .anav-link{height:38px;padding:0 12px;}
  .anav-icon{width:38px;height:38px;}

  .vid-main{height:calc(100vh - var(--anav-h,98px));}

  /* ── type ───────────────────────────────────────────────────────
     An 8px badge and 9.5px tags read as specks on a handset. */
  .anav-badge{font-size:10px;}
  .pk-off,
  .pk-tag,
  .tpl-chip,
  .xp-sec-n{font-size:11.5px;}
  .hub-card-step,
  .tpl-cat-n,
  .tpl-card-n,
  .gw-empty-note,
  .up-card-note,
  .pk-yield-s,
  .tpl-modal-ref-note{font-size:12px;}
  .hub-eyebrow{font-size:12.5px;}
}

@media (max-width:820px){

  /* The three controls in the top row sat at 34px. They have their own
     line now, so there is room to make them a real target. */
  .anav-upgrade,
  .anav-assets{height:40px;}
  .anav .app-avatar{width:40px;height:40px;}

  /* Plan page: the cycle toggle, the add-on steppers and a run of
     10.5px labels. Same treatment — bigger targets, readable labels. */
  .pk-cyc{min-height:40px;}
  .pk-addon-step{width:40px;height:40px;}
  .pk-eyebrow,
  .pk-kindcap,
  .pk-size-mark{font-size:11.5px;}
}

@media (max-width:820px){

  /* ── settings ran off the side of the phone ─────────────────────
     .set-shell already collapses to one column here, but a bare 1fr
     track takes its minimum from its content, and the content is
     .set-nav — a row of workspace tabs. The track resolved to 618px
     inside a 327px shell, so the profile card, the credits bar and
     the promo banner all ran past the right edge with no way to
     scroll to them. minmax(0,1fr) lets the track be narrower than
     what is in it; the tab row scrolls on its own, as intended. */
  .set-shell{grid-template-columns:minmax(0,1fr);}
  .set-shell > *{min-width:0;}
  .set-nav{min-width:0;}

  /* The empty state's fan of stills is wider than the column it sits
     in, and pushed the card 18px past the right edge. */
  .gw-empty{max-width:100%;overflow:hidden;}

  /* ── targets ────────────────────────────────────────────────────
     A row of controls between 17px and 36px tall. Rather than resize
     them — several are switches, steppers and step chips whose size
     is the design — each gets an invisible 44px band inside it. The
     band only grows vertically, so it cannot reach into the control
     next to it, and .set-sw is left alone because its ::after is
     already the switch knob. */
  .app-step,.gw-act,.gc-step,.as-newfolder,.set-edit,.vg-toggle,
  .cs-tpl-all,.as-act,.vg-look-change,.as-side-row,.set-out,
  .pt-go,.pk-qback,.vg-icon,.vge-drop-x,.vg-frame-x{position:relative;}
  .app-step::after,.gw-act::after,.gc-step::after,.as-newfolder::after,
  .set-edit::after,.vg-toggle::after,.cs-tpl-all::after,.as-act::after,
  .vg-look-change::after,.as-side-row::after,.set-out::after,
  .pt-go::after,.pk-qback::after,.vg-icon::after,.vge-drop-x::after,
  .vg-frame-x::after{
    content:"";position:absolute;left:0;right:0;
    top:50%;height:44px;transform:translateY(-50%);
  }

  /* ── the last of the specks ─────────────────────────────────────
     9.5–10.5px labels, all of them carrying real information. */
  .cs-card-tag,.mc-slot-tag,.as-side-h,.set-promo-tag,
  .ua-eyebrow,.mc-kicker,.ua-found-h,.as-side-n,
  .mc-slot-foot,.cs-pick,.vg-spark,.ut-side-h{font-size:11.5px;}
  .anav-badge{font-size:11px;}
  .pt th{font-size:11.5px;}
}

@media (max-width:820px){

  /* The empty state is still 18px wider than the phone. Its parent is
     the one that is too wide, so pin the card to the viewport rather
     than to whatever is around it. */
  .gw-empty{width:auto;max-width:calc(100vw - 24px);margin-inline:auto;}

  /* ── the last of the 8.5–10.5px labels ──────────────────────────
     Every one of these carries information — a model vendor, a
     resolution cap, a ratio, a section heading. The ✓ and ✕ glyphs
     are left alone: those are icons drawn with a character, and
     enlarging them would burst the circles they sit in. */
  .mc-legal,.as-tag,.ua-lbl,.vg-ratio-l,.vg-res-max,.vg-scale-c,
  .vg-ruler-of,.ua-legal,.vg-legal,.vg-samples-note,.vg-stage-ratio,
  .vg-panel-h,.vg-card-by,.vg-sr,.vg-card-spec,.vg-tag,
  .mc-slot-tag,.mc-kicker{font-size:11.5px;}
  .mc-form em,.mc-form i,.mc-form span,
  .ua-summary dt,.ua-summary b{font-size:11.5px;}

  /* ── the last of the short controls ─────────────────────────────
     Same invisible 44px band as the others. */
  .ua-read,.ua-next,.vg-seg2,.vg-pill-s,.ed-btn,
  .ua-shot-x,.vg-frame-x,.auth-legal a,.auth-back{position:relative;}
  .ua-read::after,.ua-next::after,.vg-seg2::after,.vg-pill-s::after,
  .ed-btn::after,.ua-shot-x::after,.vg-frame-x::after{
    content:"";position:absolute;left:0;right:0;
    top:50%;height:44px;transform:translateY(-50%);
  }
}

@media (max-width:820px){

  /* ── the tail: labels with no class of their own ────────────────
     Bare <em>, <span>, <b> and <dt> inside the tool panels, sitting
     at 9–10.5px. Targeted through the component that holds them,
     since they have no hook of their own. */
  .mc-arrow em,.mc-row-txt em,.mc-tile em,.mc-tile-txt em,
  .mc-note-f span,.mc-note-f i,
  .vg-row-txt em,.vg-group-h b,.vg-group-h em,
  .ua-field span,.ua-shot-empty em,.ua-own-empty em,
  .ua-prompt-h span,.ua-brief-list dt,
  .ut-preset em,.ut-dims label span,.ut-field span,
  .as-day-h span,.app-ask-h em{font-size:11.5px;}

  /* ── and the controls with no class either ──────────────────────
     Same invisible band. The two inputs get a real minimum instead,
     because a pseudo-element cannot be attached to an input — and the
     link row gets it on the label, so the checkbox stays its size. */
  .vg-qty button,.ua-seg button,
  .ed-tabs button,.cs-kindsw button,.cs-row-h a{position:relative;}
  .vg-qty button::after,.ua-seg button::after,
  .ed-tabs button::after,.cs-kindsw button::after,.cs-row-h a::after{
    content:"";position:absolute;left:0;right:0;
    top:50%;height:44px;transform:translateY(-50%);
  }
  /* .vt a is NOT in that list, and cannot be: its ::after is already the
     underline that marks the tab you are on. Giving it the invisible band
     replaced transform:scaleX(0) with translateY(-50%), which un-hid a
     44px block filled with the accent — a white slab over every tab that
     was not the current one. It gets a real minimum height instead. */
  .vt a{min-height:44px;display:inline-flex;align-items:center;}
  .cs-bar input{min-height:44px;}
  .ua-linkrow{min-height:44px;display:flex;align-items:center;}
  .auth-legal a{min-height:40px;}
}

@media (max-width:820px){
  /* Same story — outranked by their own component rules. */
  .pk-cycle .pk-cyc i,
  .vg-ratios .vg-ratio .vg-ratio-l,
  .vg-resgrid .vg-res .vg-res-max,
  .vg-card-id .vg-card-by{font-size:11.5px;}
}

@media (max-width:820px){
  /* Last two. The switch takes its band on ::before, because ::after is
     already the knob that slides. */
  .set-topup{position:relative;}
  .set-topup::after,
  .set-sw::before{
    content:"";position:absolute;left:0;right:0;
    top:50%;height:44px;transform:translateY(-50%);
  }
}

@media (max-width:820px){

  /* ── the nav dropdowns were wider than the phone ─────────────────
     .anav-menu-eng carries min-width:404px, and the engine picker
     behind Image and Video is one of these. On a 375px screen the
     panel rendered 423px wide and ran 60px past the right edge —
     every model name and spec in it cut off mid-word, with nothing
     to scroll. The floor goes, and the ceiling becomes the viewport. */
  .anav-menu,
  .anav-menu-eng{
    min-width:0;
    max-width:calc(100vw - 24px);
    width:calc(100vw - 24px);
    left:12px;right:auto;
  }
  .anav-menu-i,
  .anav-eng-lead{min-width:0;max-width:100%;}
}

@media (max-width:820px){
  /* The panel opens 97px down and caps at 722px, which ends 7px past
     the bottom of the screen. It scrolls, so nothing was unreachable,
     but the last row sat half off the edge. */
  .anav-menu,
  .anav-menu-eng{max-height:calc(100vh - 112px);}
}

@media (max-width:820px){

  /* ── stacked panes still 32px apart ──────────────────────────────
     .app-stage-c is the upload area beside the tips panel, two
     columns on a wide screen and one on a phone. The 32px between
     them was the space between columns; stacked, it reads as a gap
     in the page. Same for the two blocks inside the tips panel. */
  .app-stage-c{gap:22px;}
  .app-tips{gap:20px;}

  /* A settings row is a label and a switch. 30px of padding on an
     85px row is a third of it. */
  .set-row{padding-top:12px;padding-bottom:12px;}
}

@media (max-width:820px){

  /* ── the composer ────────────────────────────────────────────────
     .gc-bar puts the settings and the Generate button on one row, both
     flex:1 1 0. On a phone that hands .gc-opts 130px — and the chips
     inside it are 160, 69, 65 and 145px wide, so all four wrapped into
     a single narrow column and the model chip overflowed its own
     parent. Four stacked chips beside a button: 189px of squeeze.

     Stacked instead, the settings get the full width and wrap into two
     honest rows, and Generate takes the width it deserves as the one
     thing on the panel you are actually here to press. */
  /* the width is min(1120px, 100vw - 40px), so left/right do nothing —
     the 40px is what holds it in. 24px gives the three setting chips
     the 310px they need to share one row instead of two. */
  .gc{width:calc(100vw - 24px);padding:14px 14px 12px;}
  .gc-bar{flex-direction:column;align-items:stretch;gap:10px;}
  .gc-opts{flex:0 0 auto;width:100%;gap:8px;}
  .gc-go{flex:0 0 auto;width:100%;height:50px;font-size:15px;}

  /* the model name is the longest chip and the one worth reading */
  .gc-opts .cmp-pop-w:first-child .gc-opt{max-width:100%;}
}

@media (max-width:820px){

  /* ── the destination row ─────────────────────────────────────────
     Six destinations across 597px inside a 375px screen, so the row
     scrolls. The fade that says so was 30px of a mask written for a
     desktop bar where the row rarely overflows; at phone width it is
     the main thing telling you there is more to the right, and 30px
     was too little to read as anything but a clipped word.

     Wider fade, and the tabs snap so a swipe lands on a label instead
     of halfway through one. */
  .anav-links{
    -webkit-mask-image:linear-gradient(to right,transparent,#000 10px,#000 calc(100% - 46px),transparent);
    mask-image:linear-gradient(to right,transparent,#000 10px,#000 calc(100% - 46px),transparent);
    scroll-snap-type:x proximity;
    scroll-padding-left:10px;
  }
  .anav-link{scroll-snap-align:start;}
}

/* ═══════════════════════════════════════════════════════════════════
   THE DRAWER  ·  ≤820px only
   ═══════════════════════════════════════════════════════════════════
   Built by js/anav.js from the same MENUS data the desktop dropdowns
   use. Everything here is inside a max-width query and the button and
   panel are display:none above it, so a wide screen never sees any of
   this and the horizontal bar it replaces is left exactly as it was.
   =================================================================== */

.adrawer-btn,
.adrawer,
.adrawer-veil{display:none;}

@media (max-width:820px){

  /* the row of tabs has somewhere better to live now */
  .anav-links{display:none;}
  .anav-in{height:56px;}
  .anav-logo{order:0;}

  .adrawer-btn{
    display:flex;align-items:center;justify-content:center;
    width:38px;height:38px;flex:0 0 auto;margin-left:-4px;
    border:0;border-radius:11px;background:transparent;
    color:var(--a-ink);cursor:pointer;
  }
  .adrawer-btn svg{width:19px;height:19px;}
  .adrawer-btn:active{background:var(--a-chip);}

  .adrawer-veil{
    display:block;position:fixed;inset:0;z-index:70;
    background:rgba(0,0,0,.5);
    opacity:0;pointer-events:none;
    transition:opacity .28s var(--ease,cubic-bezier(.25,1,.35,1));
  }
  .adrawer-veil.is-open{opacity:1;pointer-events:auto;}

  .adrawer{
    display:flex;flex-direction:column;
    position:fixed;top:0;bottom:0;left:0;z-index:71;
    width:min(300px,86vw);
    background:var(--a-panel);
    border-right:1px solid var(--a-line);
    box-shadow:0 0 60px rgba(0,0,0,.45);
    transform:translateX(-101%);
    transition:transform .3s var(--ease,cubic-bezier(.25,1,.35,1));
  }
  .adrawer.is-open{transform:none;}

  .adrawer-top{
    display:flex;align-items:center;gap:10px;
    height:56px;padding:0 12px;flex:0 0 auto;
    border-bottom:1px solid var(--a-line);
  }
  .adrawer-x{
    display:flex;align-items:center;justify-content:center;
    width:34px;height:34px;border:0;border-radius:10px;
    background:transparent;color:var(--a-mute);cursor:pointer;
  }
  .adrawer-x svg{width:16px;height:16px;}
  .adrawer-brand{font-size:15px;font-weight:600;color:var(--a-ink);letter-spacing:-.01em;}

  /* the list scrolls, the account row underneath does not */
  .adrawer-body{
    flex:1 1 auto;overflow-y:auto;overscroll-behavior:contain;
    padding:10px 8px 14px;
    scrollbar-width:none;-ms-overflow-style:none;
  }
  .adrawer-body::-webkit-scrollbar{width:0;}

  .adrawer-sec{padding-bottom:6px;}
  .adrawer-sec + .adrawer-sec{
    margin-top:6px;padding-top:10px;
    border-top:1px solid var(--a-line);
  }
  .adrawer-h{
    padding:4px 10px 6px;
    font-size:11px;font-weight:600;letter-spacing:.1em;text-transform:uppercase;
    color:var(--a-mute);
  }
  .adrawer-sub{
    padding:8px 10px 3px;
    font-size:11px;font-weight:500;letter-spacing:.04em;
    color:var(--a-mute);opacity:.72;
  }

  .adrawer-row{
    display:flex;align-items:center;gap:11px;
    min-height:42px;padding:0 10px;border-radius:10px;
    font-size:14.5px;color:var(--a-ink);
  }
  .adrawer-row:active{background:var(--a-chip);}
  .adrawer-row.is-here{background:var(--a-chip);font-weight:500;}
  .adrawer-i{width:17px;height:17px;flex:0 0 17px;color:var(--a-mute);}
  .adrawer-row.is-here .adrawer-i{color:var(--a-ink);}
  .adrawer-row > span{flex:1 1 auto;min-width:0;}
  .adrawer-row em{
    flex:0 0 auto;padding:2px 7px;border-radius:100px;
    background:var(--a-chip);color:var(--a-mute);
    font-size:11px;font-style:normal;font-weight:600;letter-spacing:.06em;
    text-transform:uppercase;
  }

  .adrawer-foot{
    flex:0 0 auto;padding:8px;
    border-top:1px solid var(--a-line);
  }
}

@media (max-width:820px){
  /* The two-row bar was built when .anav-links still lived up here and
     needed a line of its own. The drawer took that job, so the bar goes
     back to one row: menu, logo, actions. */
  .anav-in{flex-wrap:nowrap;height:56px;column-gap:8px;}
  .anav-logo{order:0;height:auto;}
  .anav-right{order:0;height:auto;margin-left:auto;}
  :root{--anav-h:57px;}
}

@media (max-width:820px){

  /* ── the quick row is back, cut to four ──────────────────────────
     The drawer holds everything, but the four places you move between
     all day should not need a drawer opened first. All tools, Campaign,
     Image and Video come to about 330px — they fit a 375px screen with
     no scrolling, which is the whole reason the row is worth having
     again. Edit and Templates keep their place in the drawer, where
     they are one tap away and cost this row nothing.

     Undoes the display:none the drawer block set, and puts the bar
     back on two lines: actions above, destinations below. */
  .anav-in{flex-wrap:wrap;height:auto;column-gap:8px;row-gap:0;}
  .anav-logo{order:0;height:54px;}
  .anav-right{order:1;height:54px;margin-left:auto;}
  .adrawer-btn{order:-1;}

  .anav-links{
    display:flex;
    order:3;
    flex:1 0 100%;
    width:calc(100% + 24px);
    margin:0 -12px;
    padding:0 12px;
    height:44px;
    align-self:auto;
    border-top:1px solid var(--a-line);
    /* four links fit, so nothing needs to be faded off the edge */
    -webkit-mask-image:none;mask-image:none;
    overflow-x:auto;
  }
  /* Edit and Templates live in the drawer now */
  .anav-links a[href$="edit.html"],
  .anav-links a[href$="templates.html"],
  .anav-links .anav-div{display:none;}

  .anav-link{height:36px;padding:0 10px;}

  :root{--anav-h:99px;}
}

@media (max-width:820px){

  /* ── the top line has to hold ────────────────────────────────────
     Menu, logo and the actions come to about 355px against 351px of
     usable width, so the actions dropped to a line of their own and
     the bar became three rows deep — 153px of a 812px screen before
     any content.

     Assets goes to its icon: it is a place you visit, not a call to
     action, and the picture says it. Upgrade keeps its word because
     that one is the point. Roughly 50px back, which is all the top
     line needed. */
  .anav-assets span{display:none;}
  .anav-assets{padding:0 11px;}
  .anav-right{gap:6px;flex-wrap:nowrap;}

  :root{--anav-h:99px;}
}

@media (max-width:820px){

  /* The label in .anav-assets is a bare text node, not a <span>, so the
     rule that has been trying to hide it since 820px was introduced —
     .anav-upgrade span, .anav-assets span { display:none } — has never
     matched anything. Collapsing the type is what actually works; the
     icon carries its own size and is unaffected. */
  .anav-assets{font-size:0;padding:0 11px;gap:0;}
  .anav-assets svg{width:17px;height:17px;}
}

@media (max-width:820px){

  /* ── the empty canvas ────────────────────────────────────────────
     398px of opening titles before you reach anything: a fan of four
     stills 128px deep, a 22px all-caps headline over two lines, a
     paragraph and a note. On a desktop that is a title card. On a
     phone it is the whole first screen spent on a page that has not
     done anything yet.

     Same parts, said quietly — the fan smaller, the headline down to
     a size that fits one line, and the note faded to what it is: a
     caption for the work underneath, not an instruction. The composer
     is the thing on this screen, and it should not have to compete. */
  .gw-empty{padding:22px 18px 20px;}

  .gw-fan{margin-bottom:16px;}
  .gw-fan-i{width:78px;margin:0 -9px;border-radius:11px;}
  .gw-fan-i.is-round{width:66px;}

  .gw-empty-h{font-size:17px;letter-spacing:-.01em;line-height:1.18;}
  .gw-empty-h b{font-size:17px;}
  .gw-empty-p{font-size:13.5px;line-height:1.5;padding-top:8px;max-width:290px;}
  .gw-empty-note{font-size:11.5px;opacity:.62;padding-top:10px;max-width:290px;}
}

@media (max-width:820px){
  /* Tighter still: the space between the fan, the headline and the two
     lines under it was set for a block twice this size. */
  .gw-empty{padding:16px 18px 14px;}
  .gw-fan{margin-bottom:11px;}
  .gw-empty-p{padding-top:6px;}
  .gw-empty-note{padding-top:8px;line-height:1.4;}
}

@media (max-width:820px){

  /* ── the composer, second pass ────────────────────────────────────
     Stacking the settings above a full-width Generate fixed the squeeze
     but made the panel a form: four rows, the last of them a black bar
     across the whole thing. The shape that suits a phone is the one
     where the settings wrap on the left and the action sits in the
     bottom-right corner of the same block — you read the row, then your
     thumb is already where it needs to be.

     The word "Generate" goes; the sparkle and the credit cost stay,
     which is the part that changes and the part worth looking at. */
  .gc-bar{flex-direction:row;align-items:flex-end;gap:10px;}
  .gc-opts{flex:1 1 auto;min-width:0;width:auto;flex-wrap:wrap;gap:7px;}

  .gc-go{
    flex:0 0 auto;width:auto;min-width:54px;height:44px;
    padding:0 15px;border-radius:100px;font-size:14px;
  }
  .gc-go-l{display:none;}

  /* the chips come down a size with it, so the block reads as one
     quiet row of settings rather than four buttons */
  .gc-opt{height:34px;padding:0 11px;font-size:12px;}
  .gc-count{height:34px;}
  .gc-count button{width:30px;height:30px;}
}

@media (max-width:820px){
  /* .gc-bar still carried flex-wrap:wrap from the desktop rule, so the
     settings block took the whole line and pushed the button onto one
     of its own — bottom-left, which is the one corner it should not be
     in. The bar holds one line; the wrapping happens inside the
     settings, where it belongs. */
  .gc-bar{flex-wrap:nowrap;}
  .gc-opts{flex:1 1 0;}
}

@media (max-width:820px){

  /* ── the settings pack, they do not spread ───────────────────────
     Nothing here pushes to the far edge. Once the settings wrap into a
     narrow column beside the button, an auto margin stops being
     alignment and becomes a hole — 2K on the left, a gap, the counter
     against the button. Flowing left to right they pack into rows and
     the block reads as one thing. */
  .gc-opts{align-content:flex-end;row-gap:7px;}

  /* the divider above them was sized for a single row */
  .gc-bar{padding-top:10px;}
}


@media (max-width:820px){

  /* ── two rows, not three ─────────────────────────────────────────
     The chips keep their own widths — stretched to fill a grid they
     read as four big slabs, which is worse than a ragged edge. What
     made it three rows was one pixel: the model chip and the ratio
     came to 237 against 236 of space, so the ratio dropped a line and
     dragged everything after it.

     Two pixels off each chip's padding and one off the button's, and
     the same four settings sit in two rows with room to spare:

       ● Nano Banana Pro ⌄   3:4
       2K    − 7 / 8 +              ( ✦ 14 )
  */
  .gc-opt{padding:0 10px;}
  .gc-go{padding:0 13px;}
  .gc-count{gap:5px;}
  .gc-count button{width:28px;height:28px;}
  .gc-opts{row-gap:8px;column-gap:7px;}
}

@media (max-width:820px){

  /* ── Edit joins the quick row ─────────────────────────────────────
     Five destinations instead of four. It fits because the LAYERS
     badge comes off: at 96px with it and about 48 without, the badge
     is more than half the width of the link it decorates, and on a
     375px row that is the difference between everything fitting and
     the row starting to scroll. The badge stays on the desktop bar
     and in the drawer, where there is room for it. */
  .anav-links a[href$="edit.html"]{display:flex;}
  .anav-links a[href$="edit.html"] .anav-badge{display:none;}
}

/* ═══════════════════════════════════════════════════════════════════
   THE TEMPLATE MODAL ON A PHONE  ·  ≤860px
   ═══════════════════════════════════════════════════════════════════
   There has been a rule since this panel was built saying it stacks on
   a small screen:

     @media (max-width:860px){ .tpl-modal-grid{grid-template-columns:1fr} }

   It has never once applied. Two rules further down the sheet set the
   columns as [data-app] .tpl-modal-grid — and every app page carries
   data-app on <html>, so at (0,2,0) they outrank the mobile rule at
   (0,1,0) whatever the viewport. The modal has been showing its
   desktop layout on phones the whole time: 180px for the reference
   image and 195px for everything else, which is why the prompt broke
   mid-word — "Profe / ssion / al" — and the button sat on top of the
   model row.

   Same intent as the original rule, written with the reach to land.
   =================================================================== */

@media (max-width:860px){

  [data-app] .tpl-modal-grid{grid-template-columns:1fr;}
  [data-app] .tpl-modal-ref img{min-height:0;aspect-ratio:4/3;}
  [data-app] .tpl-modal-side{padding:22px 18px 18px;}

  /* the close sits over the picture, clear of the heading below it */
  [data-app] .tpl-modal-x{top:12px;right:12px;z-index:4;}
  [data-app] .tpl-modal-title{font-size:20px;padding-right:6px;}
  [data-app] .tpl-modal-sub{font-size:13.5px;padding:6px 0 18px;}

  /* the numbered steps: the marker keeps its column, the content gets
     the rest of the width instead of 150px of it */
  [data-app] .tpl-step{gap:11px;padding-bottom:18px;}
  [data-app] .tpl-step > *:last-child{min-width:0;}

  /* the prompt was the worst of it — a fixed panel width left the text
     breaking inside words */
  [data-app] .tpl-prompt{font-size:12.5px;line-height:1.5;max-height:170px;}
  [data-app] .tpl-prompt-copy{font-size:11.5px;}

  /* the action row stops overlapping the step above it */
  [data-app] .tpl-modal-foot{
    position:sticky;bottom:0;
    display:flex;align-items:center;gap:12px;
    padding:12px 18px;margin:0 -18px -18px;
    border-top:1px solid var(--line);
    background:var(--white);
  }
  [data-app] .tpl-generate{flex:1 1 auto;min-height:46px;}
  [data-app] .tpl-cost{flex:0 0 auto;font-size:12px;line-height:1.25;}
  [data-app] .tpl-hint{text-align:left;padding-top:6px;font-size:11.5px;}
}

@media (max-width:860px){

  /* ── the action bar ──────────────────────────────────────────────
     Three things were sharing one line across 339px: the credit cost
     and the Generate button in one group, and the "add your product
     photo" note beside them. The group got 190px of it, so the button
     was rendering as "Gener".

     The note goes on its own line above — it is a status, and reading
     it is what tells you why the button is dim. The cost and the
     button take the full width underneath. */
  [data-app] .tpl-modal-foot{
    flex-direction:column;align-items:stretch;gap:8px;
    padding:12px 18px 14px;
  }
  [data-app] .tpl-hint{order:-1;text-align:left;padding:0;font-size:12px;}
  [data-app] .tpl-modal-actions{
    display:flex;align-items:center;gap:12px;width:100%;
  }
  [data-app] .tpl-cost{flex:0 0 auto;}
  [data-app] .tpl-generate{flex:1 1 auto;min-height:46px;white-space:nowrap;}
}

@media (max-width:860px){
  /* Three doors across 304px is 96px each, and a door carries a stack of
     faces, a name and a count. "Your own" was breaking over two lines to
     fit. One face fewer on the stack buys the words their room back. */
  [data-app] .tpl-door{padding:10px 10px;gap:8px;}
  [data-app] .tpl-door-faces img:nth-child(3){display:none;}
  [data-app] .tpl-door-t{white-space:nowrap;}
  [data-app] .tpl-door em{font-size:10.5px;}
}

/* ═══════════════════════════════════════════════════════════════════
   PLAN CAROUSEL  ·  the look
   ═══════════════════════════════════════════════════════════════════
   --f is written by js/plan-carousel.js on every scroll frame: 1 when a
   card is under the middle of the window, falling to 0 a card's width
   away. Everything below reads that one number, and only ever through
   transform and opacity — so the whole effect runs on the compositor
   and the swipe keeps its frame rate on a phone.
   =================================================================== */

.plan-nav{display:none;}

@media (max-width:760px){

  .price-grid,
  .pk-grid{
    display:flex;
    grid-template-columns:none;
    gap:12px;
    align-items:stretch;
    overflow-x:auto;
    scroll-snap-type:x mandatory;
    scroll-padding-left:24px;
    /* full bleed, so a card can travel to the edge instead of stopping
       inside a container's padding */
    width:100vw;margin-left:calc(50% - 50vw);
    padding:14px 24px 20px;
    scrollbar-width:none;-ms-overflow-style:none;
    -webkit-overflow-scrolling:touch;
    overscroll-behavior-x:contain;
    /* the cards dissolve at the boundary rather than being cut by it */
    -webkit-mask-image:linear-gradient(to right,transparent,#000 22px,#000 calc(100% - 22px),transparent);
    mask-image:linear-gradient(to right,transparent,#000 22px,#000 calc(100% - 22px),transparent);
  }
  .price-grid::-webkit-scrollbar,
  .pk-grid::-webkit-scrollbar{width:0;height:0;}

  .price-card,
  .pk-card{
    flex:0 0 84vw;max-width:340px;
    scroll-snap-align:start;
    /* the card you are on stands slightly proud of the ones beside it;
       they hold their place, dimmed, so the set still reads as a set */
    transform:scale(calc(.925 + .075 * var(--f, 1)));
    opacity:calc(.42 + .58 * var(--f, 1));
    transform-origin:50% 45%;
    will-change:transform,opacity;
  }

  /* the app card is a subgrid spanning three rows of .pk-grid; once the
     grid is a flex row there are no rows to span, so it becomes its own
     little column */
  .pk-card{
    display:flex;flex-direction:column;
    grid-row:auto;grid-template-rows:none;
  }

  /* the shadow arrives with the focus, so the front card lifts off the
     page rather than sitting on it */
  .price-card{
    box-shadow:
      inset 0 0 0 1px var(--line),
      0 calc(30px * var(--f, 1)) calc(60px * var(--f, 1)) -34px rgba(0,0,0,calc(.55 * var(--f, 1)));
  }
  .pk-card{
    box-shadow:
      inset 0 0 0 1px var(--a-line),
      0 calc(28px * var(--f, 1)) calc(56px * var(--f, 1)) -30px rgba(0,0,0,calc(.7 * var(--f, 1)));
  }
  /* a lift on hover is a desktop idea; here the scroll does that job */
  .pk-card:hover{transform:scale(calc(.925 + .075 * var(--f, 1)));}

  /* ── the controls ────────────────────────────────────────────────
     Big enough to hit, quiet enough not to compete with the cards. */
  .plan-nav{
    display:flex;align-items:center;justify-content:center;gap:16px;
    padding:4px 24px 0;
  }
  .plan-nav-a{
    display:flex;align-items:center;justify-content:center;
    width:44px;height:44px;flex:0 0 44px;
    border:1px solid var(--line,var(--a-line));border-radius:50%;
    background:var(--white,var(--a-panel));
    color:var(--ink,var(--a-ink));
    cursor:pointer;
    transition:transform .18s var(--e-out,cubic-bezier(.25,1,.35,1)),
               opacity .2s var(--e-out,cubic-bezier(.25,1,.35,1));
  }
  .plan-nav-a svg{width:16px;height:16px;}
  .plan-nav-a:active{transform:scale(.9);}
  .plan-nav-a:disabled{opacity:.25;cursor:default;transform:none;}

  .plan-dots{display:flex;align-items:center;gap:7px;}
  .plan-dot{
    position:relative;
    width:7px;height:7px;padding:0;border:0;border-radius:100px;
    background:var(--line,var(--a-line));cursor:pointer;
    transition:width .3s var(--e-out,cubic-bezier(.25,1,.35,1)),
               background .3s var(--e-out,cubic-bezier(.25,1,.35,1));
  }
  /* the active dot stretches into the gap rather than just changing
     colour — the movement is what tells you which way you went */
  .plan-dot.is-on{width:22px;background:var(--ink-strong,var(--a-ink));}
  /* 7px of paint, 40px of target */
  .plan-dot::after{
    content:"";position:absolute;left:50%;top:50%;
    width:40px;height:40px;transform:translate(-50%,-50%);
  }
}

@media (prefers-reduced-motion:reduce){
  .price-card,.pk-card{transform:none!important;opacity:1!important;}
  .plan-dot,.plan-nav-a{transition:none;}
}

@media (max-width:760px){
  /* .price-card carries an entrance animation that deals the four cards
     in from the left, and a running CSS animation outranks a normal
     declaration for the properties it touches — so it was holding
     transform and opacity at the animation's values and the focus
     effect never showed. The deal-in is a desktop idea anyway: here the
     cards arrive one at a time under your thumb, which is its own
     entrance. */
  .price-card,
  .pk-card{animation:none!important;}
}

@media (max-width:760px){

  /* ── why these carry !important ───────────────────────────────────
     The reveal that deals these cards in is GSAP, and GSAP finishes by
     writing its result to the element:

       transform: translate(0px, 0px); opacity: 1;
       translate: none; rotate: none; scale: none;

     Inline, and permanent. A stylesheet cannot outrank an inline style
     by specificity — !important is the only thing that does, and this
     is the case it exists for. Scoped to the phone, to these two cards,
     to the two properties the carousel drives. */
  .price-card,
  .pk-card{
    transform:scale(calc(.925 + .075 * var(--f, 1)))!important;
    opacity:calc(.42 + .58 * var(--f, 1))!important;
  }
  .pk-card:hover{transform:scale(calc(.925 + .075 * var(--f, 1)))!important;}
}

@media (max-width:760px) and (prefers-reduced-motion:reduce){
  .price-card,.pk-card{transform:none!important;opacity:1!important;}
}

@media (max-width:860px){

  /* ── the reference frame ─────────────────────────────────────────
     Every template still is a portrait — 720×964, ratio 0.75 — and the
     frame was 4:3 landscape with object-fit:contain. So the picture sat
     in the middle of a box 44% the wrong shape, with a band of dark
     either side of it. On a 375px phone the bands are narrow enough to
     read as padding; at 488 they are wide enough that the whole modal
     looks like it has come apart.

     4:5 is six percent off the source instead of forty-four, and cover
     fills the frame — the picture goes edge to edge, which is what a
     reference image is for.

     A height cap has to be a height, not an aspect ratio: aspect-ratio
     plus max-height makes the box shrink in BOTH axes, so the frame
     came out 415px wide inside a 488px modal with a dark gutter down
     the right. Explicit width + explicit height, no ratio. */
  [data-app] .tpl-modal-ref{
    width:100%;
    height:min(58vh,520px);
    min-height:260px;
    aspect-ratio:auto;
    overflow:hidden;
  }
  [data-app] .tpl-modal-ref img{
    width:100%;height:100%;
    aspect-ratio:auto;min-height:0;max-height:none;
    object-fit:cover;object-position:50% 40%;
  }

  /* ── the cast doors ──────────────────────────────────────────────
     `.tpl-cast-doors > *{flex:1}` sizes three doors to the row, which
     is right on a wide column and wrong at 375: the row is 304px and
     the three doors want 345, so each one was squeezed to 96px and its
     label ran under the faces. Let them keep their own width and wrap
     onto a second line instead — two up, one under. */
  [data-app] .tpl-cast-doors{flex-wrap:wrap;gap:8px;}
  [data-app] .tpl-cast-doors > *{flex:0 0 auto;min-width:0;}
  [data-app] .tpl-door{padding:9px 12px 9px 8px;gap:8px;}
  [data-app] .tpl-door em{margin-left:6px;font-size:11px;}
  [data-app] .tpl-door-faces img{width:26px;height:26px;}
  [data-app] .tpl-door-faces.is-add{width:26px;height:26px;}

  /* ── the saved-upload strip ──────────────────────────────────────
     This is what was actually cutting the modal off, and it only shows
     once you have uploads saved — which is why an empty browser looked
     fine. `.tpl-modal-side` is a grid item with min-width:auto, so the
     1fr track takes its minimum from the content: twelve 46px thumbs
     blew the column out to 700px inside a 462px screen and everything
     — picture included — was clipped at the modal's right edge.

     minmax(0,1fr) caps the track at the screen; min-width:0 down the
     chain lets the strip scroll on its own instead of pushing. */
  [data-app] .tpl-modal-grid{grid-template-columns:minmax(0,1fr);}
  [data-app] .tpl-modal-side,
  [data-app] .tpl-modal-form,
  [data-app] .tpl-step,
  [data-app] .tpl-step-body,
  [data-app] .tpl-lib,
  [data-app] .tpl-lib-row,
  [data-app] .tpl-prompt{min-width:0;}
  [data-app] .tpl-lib-row{overflow-x:auto;-webkit-overflow-scrolling:touch;}
}

/* ══ Templates — the way down the panel ═════════════════════════════
   Phone only. The rest state below is written under .has-scrollfx,
   which js/tpl-scroll.js adds only once it has decided to run — so a
   reader who has asked for less motion, or anyone on a wide screen,
   never meets a step waiting at opacity zero for a script that is not
   coming. ════════════════════════════════════════════════════════════ */
@media (max-width:860px){

  /* ── the picture lags, and darkens as it leaves ── */
  [data-app] .tpl-modal.has-scrollfx .tpl-modal-ref{--pp:0px;--pz:1;--pv:0;}
  [data-app] .tpl-modal.has-scrollfx .tpl-modal-ref [data-tpl-modal-img]{
    transform:translate3d(0,var(--pp),0) scale(var(--pz));
    transform-origin:50% 40%;
    will-change:transform;
  }
  [data-app] .tpl-modal.has-scrollfx .tpl-modal-ref::after{
    content:'';position:absolute;inset:0;z-index:1;pointer-events:none;
    background:linear-gradient(180deg,
      rgba(0,0,0,.30) 0%, rgba(0,0,0,0) 32%, rgba(0,0,0,.58) 100%);
    opacity:var(--pv);
  }
  /* the veil is scenery — it goes under everything you can act on */
  [data-app] .tpl-modal.has-scrollfx .tpl-modal-ref figcaption{
    z-index:4;will-change:opacity,transform;
  }

  /* a new template arrives on its own rather than cutting in */
  [data-app] .tpl-modal.has-scrollfx .tpl-modal-ref.is-swap [data-tpl-modal-img]{
    animation:tplSwapIn .55s cubic-bezier(.22,.61,.36,1) both;
  }
  @keyframes tplSwapIn{
    from{opacity:0;transform:translate3d(0,var(--pp),0) scale(1.05);}
    to{opacity:1;transform:translate3d(0,var(--pp),0) scale(var(--pz));}
  }

  /* ── each step arrives as you reach it ── */
  [data-app] .tpl-modal.has-scrollfx .tpl-modal-title,
  [data-app] .tpl-modal.has-scrollfx .tpl-step{
    opacity:0;transform:translate3d(0,18px,0);
    transition:opacity .58s cubic-bezier(.22,.61,.36,1),
               transform .66s cubic-bezier(.22,.61,.36,1);
  }
  [data-app] .tpl-modal.has-scrollfx .tpl-modal-title.is-in,
  [data-app] .tpl-modal.has-scrollfx .tpl-step.is-in{
    opacity:1;transform:none;
  }

  /* the number lands a beat behind its step, which is what makes the
     step read as one thing arriving rather than two */
  [data-app] .tpl-modal.has-scrollfx .tpl-step .tpl-step-n{
    opacity:0;transform:scale(.62);
    transition:transform .52s cubic-bezier(.34,1.56,.64,1) .11s,
               opacity .32s ease .11s;
  }
  [data-app] .tpl-modal.has-scrollfx .tpl-step.is-in .tpl-step-n{
    opacity:1;transform:none;
  }

  /* ── and a rail is drawn between them ──
     Absolutely positioned, so it is not a flex item in a row that is
     already spoken for. It stops at the last step actually drawn. */
  [data-app] .tpl-modal.has-scrollfx .tpl-step{position:relative;}
  [data-app] .tpl-modal.has-scrollfx .tpl-step::before{
    content:'';position:absolute;left:11.25px;top:29px;bottom:3px;width:1.5px;
    background:linear-gradient(180deg,var(--a-line) 0%,var(--a-line) 76%,transparent 100%);
    transform:scaleY(0);transform-origin:50% 0;
    transition:transform .68s cubic-bezier(.22,.61,.36,1) .17s;
  }
  [data-app] .tpl-modal.has-scrollfx .tpl-step.is-in::before{transform:scaleY(1);}
  [data-app] .tpl-modal.has-scrollfx .tpl-step.is-last::before{display:none;}
}

/* ══════════════════════════════════════════════════════════════════
   COMMUNITY

   A wall of frames other people made, and under each one the two things
   that make it worth looking at rather than only looking nice: the
   prompt behind it and the references that went in.

   The card leads with the picture and follows with the words, because
   that is the order you read it in — you decide whether you care from
   the frame, and only then want to know how it was done.
   ══════════════════════════════════════════════════════════════════ */
.cm-main{padding:52px 0 90px;}
.cm-head{max-width:720px;margin-bottom:30px;}
.cm-head .hub-sub{max-width:620px;}

.cm-bar{
  display:flex;align-items:center;justify-content:space-between;gap:16px;
  flex-wrap:wrap;padding-bottom:22px;
}
.cm-filters{display:flex;gap:7px;flex-wrap:wrap;}
.cm-filter{
  padding:8px 15px;border-radius:100px;cursor:pointer;
  font-size:13px;font-weight:500;letter-spacing:-.005em;
  color:var(--ink-mute);background:var(--wash);
  border:1px solid transparent;
  transition:color .2s var(--ease),background .2s var(--ease);
}
.cm-filter:hover{color:var(--ink-strong);}
.cm-filter.is-on{background:var(--ink-strong);color:var(--white);}
.cm-count{font-size:13px;color:var(--ink-mute);font-variant-numeric:tabular-nums;}

.cm-grid{
  display:grid;grid-template-columns:repeat(auto-fill,minmax(268px,1fr));gap:20px;
}

.cm-card{
  display:flex;flex-direction:column;border-radius:16px;overflow:hidden;
  background:var(--white);
  box-shadow:0 1px 2px rgba(0,0,0,.04),0 20px 40px -34px rgba(0,0,0,.35);
  transition:transform .4s var(--ease),box-shadow .4s var(--ease);
}
.cm-card:hover{transform:translateY(-3px);box-shadow:0 1px 2px rgba(0,0,0,.04),0 32px 54px -30px rgba(0,0,0,.45);}

.cm-card-media{
  position:relative;display:block;width:100%;padding:0;cursor:pointer;
  aspect-ratio:4/5;background:var(--wash);overflow:hidden;border:0;
}
.cm-card-img{width:100%;height:100%;object-fit:cover;display:block;
  transition:transform .8s var(--ease);}
.cm-card-media:hover .cm-card-img{transform:scale(1.03);}
.cm-play{
  position:absolute;left:12px;bottom:12px;width:30px;height:30px;border-radius:50%;
  display:flex;align-items:center;justify-content:center;
  background:rgba(255,255,255,.9);color:#151515;
  box-shadow:0 8px 20px -10px rgba(0,0,0,.7);
}
.cm-play svg{width:13px;height:13px;margin-left:1px;}

.cm-card-body{padding:14px 15px 16px;display:flex;flex-direction:column;gap:10px;}

/* ── who made it ── */
.cm-who{display:flex;align-items:center;gap:9px;}
.cm-ava{
  flex:0 0 auto;width:28px;height:28px;border-radius:50%;
  display:flex;align-items:center;justify-content:center;
  background:var(--ink-strong);color:var(--white);
  font-size:11px;font-weight:600;letter-spacing:.02em;
}
.cm-who-t{display:flex;flex-direction:column;min-width:0;flex:1 1 auto;}
.cm-who-t b{font-size:13px;font-weight:600;color:var(--ink-strong);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.cm-who-t em{font-size:11.5px;font-style:normal;color:var(--ink-mute);}

.cm-like{
  flex:0 0 auto;display:inline-flex;align-items:center;gap:5px;cursor:pointer;
  padding:5px 9px;border-radius:100px;background:var(--wash);
  font-size:12px;font-weight:600;color:var(--ink-mute);
  font-variant-numeric:tabular-nums;
  transition:color .2s var(--ease),background .2s var(--ease);
}
.cm-like svg{width:14px;height:14px;}
.cm-like:hover{color:var(--ink-strong);}
.cm-like.is-on{color:var(--ink-strong);}
/* the glyph is two paths now, so the fill lives on the solid one */

.cm-caption{font-size:13px;line-height:1.5;color:var(--ink-strong);}

/* The prompt is the point, so it is shown rather than hidden behind a
   toggle — but only the opening of it. Three lines is enough to tell
   whether you want the rest, and the rest is one tap away. */
.cm-card-prompt{
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
  font-size:11.5px;line-height:1.65;color:var(--ink-mute);
  display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;
  overflow:hidden;
  padding:10px 11px;border-radius:10px;background:var(--wash);
}

/* ── the references ── */
.cm-refs{display:flex;gap:6px;flex-wrap:wrap;}
.cm-ref{
  width:38px;height:38px;border-radius:8px;overflow:hidden;flex:0 0 auto;
  background:var(--wash);box-shadow:inset 0 0 0 1px var(--line);
}
.cm-ref img{width:100%;height:100%;object-fit:cover;display:block;}
.cm-refs.is-large .cm-ref{width:56px;height:56px;border-radius:10px;}

/* ── nothing to show ── */
.cm-empty{
  text-align:center;padding:64px 24px;max-width:460px;margin:0 auto;
  display:flex;flex-direction:column;align-items:center;gap:12px;
}
.cm-empty svg{width:34px;height:34px;color:var(--ink-mute);opacity:.7;}
.cm-empty h2{font-size:19px;font-weight:500;letter-spacing:-.3px;color:var(--ink-strong);}
.cm-empty p{font-size:14px;line-height:1.6;color:var(--ink-mute);}
.cm-empty-go{
  margin-top:6px;padding:11px 20px;border-radius:100px;
  background:var(--ink-strong);color:var(--white);
  font-size:13.5px;font-weight:500;
}

.cm-more-w{display:flex;justify-content:center;padding-top:34px;}
.cm-more{
  padding:11px 22px;border-radius:100px;cursor:pointer;
  font-size:13.5px;font-weight:500;color:var(--ink-strong);
  background:var(--wash);
  transition:background .2s var(--ease);
}
.cm-more:hover{background:var(--line);}
.cm-more[disabled]{opacity:.5;cursor:default;}

/* ══ the post, opened ══ */
.cm-modal{
  position:fixed;inset:0;z-index:220;
  display:flex;align-items:center;justify-content:center;padding:26px;
}
.cm-modal-veil{position:absolute;inset:0;background:rgba(0,0,0,.62);
  backdrop-filter:blur(3px);-webkit-backdrop-filter:blur(3px);}
.cm-modal-box{
  position:relative;width:100%;max-width:1180px;max-height:calc(100vh - 52px);
  overflow:auto;border-radius:18px;background:var(--white);
  box-shadow:0 40px 90px -40px rgba(0,0,0,.7);
}
.cm-modal-x{
  position:absolute;top:14px;right:14px;z-index:5;
  width:34px;height:34px;border-radius:50%;cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  color:#151515;background:rgba(255,255,255,.92);
  box-shadow:0 10px 26px -12px rgba(0,0,0,.8);
}
.cm-modal-x svg{width:15px;height:15px;}
.cm-modal-grid{display:grid;grid-template-columns:1.05fr 1fr;}
.cm-modal-ref{margin:0;position:relative;background:var(--wash);
  display:flex;align-items:center;justify-content:center;}
.cm-modal-img{width:100%;height:100%;max-height:calc(100vh - 52px);
  object-fit:contain;display:block;}
.cm-modal-side{padding:30px 30px 26px;display:flex;flex-direction:column;gap:20px;}
.cm-modal-caption{font-size:15px;line-height:1.6;color:var(--ink-strong);}

.cm-block{display:flex;flex-direction:column;gap:9px;}
.cm-block h3{font-size:12px;font-weight:600;letter-spacing:.07em;
  text-transform:uppercase;color:var(--ink-mute);}
.cm-prompt{position:relative;padding:14px 15px;border-radius:12px;background:var(--wash);}
.cm-prompt p{
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
  font-size:12.5px;line-height:1.75;color:var(--ink-strong);
  white-space:pre-wrap;word-break:break-word;padding-right:64px;
}
.cm-copy{
  position:absolute;top:10px;right:10px;cursor:pointer;
  display:inline-flex;align-items:center;gap:5px;
  padding:5px 9px;border-radius:8px;
  font-size:11.5px;font-weight:600;color:var(--ink-strong);
  background:var(--white);box-shadow:0 0 0 1px var(--line);
}
.cm-copy svg{width:12px;height:12px;}
.cm-meta{font-size:12px;color:var(--ink-mute);}

.cm-modal-foot{display:flex;align-items:center;gap:9px;flex-wrap:wrap;margin-top:auto;padding-top:6px;}
.cm-btn{
  display:inline-flex;align-items:center;gap:6px;cursor:pointer;
  padding:11px 17px;border-radius:100px;
  font-size:13.5px;font-weight:500;color:var(--ink-strong);
  background:var(--wash);
  transition:background .2s var(--ease),color .2s var(--ease);
}
.cm-btn svg{width:15px;height:15px;}
.cm-btn:hover{background:var(--line);}
.cm-btn.is-solid{background:var(--ink-strong);color:var(--white);}
.cm-btn.is-solid:hover{opacity:.88;background:var(--ink-strong);}
.cm-btn.is-quiet{background:transparent;color:var(--ink-mute);margin-left:auto;}
.cm-btn.is-quiet:hover{color:var(--a-danger,#e0364a);background:transparent;}
.cm-btn.is-on{color:var(--ink-strong);}


/* ══ the share dialog ══
   Injected by js/share.js on every page that can make a frame, so it is
   written once here rather than styled per page. */
.shr-veil{
  position:fixed;inset:0;z-index:240;background:rgba(0,0,0,.6);
  backdrop-filter:blur(3px);-webkit-backdrop-filter:blur(3px);
  opacity:0;pointer-events:none;transition:opacity .3s var(--ease);
}
.shr-veil.is-open{opacity:1;pointer-events:auto;}
.shr-dlg{
  position:fixed;z-index:241;left:50%;top:50%;
  width:min(660px,calc(100vw - 40px));max-height:calc(100vh - 56px);
  display:flex;flex-direction:column;overflow:hidden;
  border-radius:18px;background:var(--white);
  box-shadow:0 40px 90px -40px rgba(0,0,0,.7);
  transform:translate(-50%,-46%) scale(.97);opacity:0;pointer-events:none;
  transition:transform .34s cubic-bezier(.22,.61,.36,1),opacity .26s var(--ease);
}
.shr-dlg.is-open{transform:translate(-50%,-50%) scale(1);opacity:1;pointer-events:auto;}
.shr-x{
  position:absolute;top:13px;right:13px;z-index:3;
  width:30px;height:30px;border-radius:50%;cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  color:var(--ink-mute);background:var(--wash);
}
.shr-x svg{width:14px;height:14px;}
.shr-head{padding:24px 26px 0;}
.shr-head h2{font-size:19px;font-weight:500;letter-spacing:-.35px;color:var(--ink-strong);}
.shr-head p{font-size:13px;line-height:1.55;color:var(--ink-mute);padding-top:5px;max-width:420px;}

.shr-body{display:grid;grid-template-columns:200px 1fr;gap:18px;padding:20px 26px 4px;
  overflow:auto;}
.shr-shot{margin:0;border-radius:12px;overflow:hidden;background:var(--wash);
  aspect-ratio:4/5;}
.shr-shot img,.shr-shot video{width:100%;height:100%;object-fit:cover;display:block;}
.shr-form{display:flex;flex-direction:column;gap:14px;min-width:0;}
.shr-as{font-size:13px;color:var(--ink-mute);}
.shr-as b{color:var(--ink-strong);font-weight:600;}
.shr-field{display:flex;flex-direction:column;gap:6px;}
.shr-field > span{font-size:12.5px;font-weight:500;color:var(--ink-strong);}
.shr-field em{font-style:normal;font-weight:400;color:var(--ink-mute);}
.shr-field input{
  width:100%;padding:11px 13px;border-radius:10px;
  font-size:13.5px;color:var(--ink-strong);
  background:var(--wash);border:1px solid var(--line);
}
.shr-field input:focus{outline:none;border-color:var(--ink-strong);}
.shr-what{display:flex;flex-direction:column;gap:8px;}
.shr-what h3{font-size:11.5px;font-weight:600;letter-spacing:.07em;
  text-transform:uppercase;color:var(--ink-mute);}
.shr-prompt{
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
  font-size:11.5px;line-height:1.7;color:var(--ink-mute);
  padding:11px 12px;border-radius:10px;background:var(--wash);
  max-height:118px;overflow:auto;white-space:pre-wrap;word-break:break-word;
}
.shr-refs{display:flex;gap:6px;flex-wrap:wrap;}

.shr-foot{
  display:flex;align-items:center;gap:9px;
  padding:16px 26px 20px;border-top:1px solid var(--line);margin-top:16px;
}
.shr-note{flex:1 1 auto;font-size:12.5px;color:var(--ink-mute);min-width:0;}
.shr-note.is-bad{color:var(--a-danger,#e0364a);}
.shr-btn{
  padding:11px 18px;border-radius:100px;cursor:pointer;
  font-size:13.5px;font-weight:500;color:var(--ink-strong);background:var(--wash);
  transition:background .2s var(--ease),opacity .2s var(--ease);
}
.shr-btn:hover{background:var(--line);}
.shr-btn.is-solid{background:var(--ink-strong);color:var(--white);}
.shr-btn.is-solid:hover{opacity:.88;background:var(--ink-strong);}
.shr-btn[disabled]{opacity:.55;cursor:default;}

/* the one line of feedback both halves share */
.cm-toast{
  position:fixed;left:50%;bottom:28px;z-index:260;
  transform:translate(-50%,14px);opacity:0;
  padding:11px 18px;border-radius:100px;max-width:min(440px,calc(100vw - 32px));
  font-size:13px;line-height:1.4;text-align:center;
  color:var(--white);background:var(--ink-strong);
  box-shadow:0 20px 44px -20px rgba(0,0,0,.7);
  transition:transform .3s var(--ease),opacity .3s var(--ease);
}
.cm-toast.is-in{transform:translate(-50%,0);opacity:1;}

/* the share action on the video stage, once there is a clip to share */
.vg-stage-share{
  position:absolute;right:14px;bottom:14px;z-index:4;cursor:pointer;
  display:inline-flex;align-items:center;gap:7px;
  padding:9px 15px;border-radius:100px;
  font-size:12.5px;font-weight:500;color:#151515;
  background:rgba(255,255,255,.93);
  backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);
  box-shadow:0 12px 30px -14px rgba(0,0,0,.8);
  transition:transform .25s var(--ease);
}
.vg-stage-share svg{width:15px;height:15px;}
.vg-stage-share:hover{transform:translateY(-1px);}

/* ══ COMMUNITY ON A PHONE ══
   One column, and the post opens as a sheet rather than as two columns
   side by side — the same shape the templates modal takes, for the same
   reason: at 390px there is only ever one column. */
@media (max-width:860px){
  [data-app] .cm-main{padding:26px 0 64px;}
  [data-app] .cm-head{margin-bottom:20px;}
  [data-app] .cm-bar{padding-bottom:16px;gap:10px;}
  [data-app] .cm-filters{
    flex-wrap:nowrap;overflow-x:auto;width:100%;
    scrollbar-width:none;-webkit-overflow-scrolling:touch;
  }
  [data-app] .cm-filters::-webkit-scrollbar{height:0;}
  [data-app] .cm-filter{flex:0 0 auto;padding:9px 15px;font-size:13px;}

  [data-app] .cm-grid{grid-template-columns:1fr;gap:16px;}
  [data-app] .cm-card-media{aspect-ratio:4/5;}
  [data-app] .cm-card-body{padding:13px 14px 15px;gap:9px;}
  [data-app] .cm-card-prompt{-webkit-line-clamp:2;font-size:11.5px;}

  [data-app] .cm-modal{padding:0;align-items:stretch;}
  [data-app] .cm-modal-box{
    max-width:none;width:100%;max-height:100%;border-radius:0;
  }
  /* Same shape as the templates modal: the picture at the top, capped so
     it cannot take the whole screen, and everything else read under it.
     Explicit height rather than an aspect ratio — a ratio plus a height
     cap shrinks the box in both directions and leaves a gutter. */
  [data-app] .cm-modal-grid{grid-template-columns:minmax(0,1fr);}
  [data-app] .cm-modal-ref{
    width:100%;height:min(56vh,500px);min-height:240px;overflow:hidden;
  }
  [data-app] .cm-modal-img{max-height:none;object-fit:cover;object-position:50% 40%;}
  [data-app] .cm-modal-side{padding:20px 18px 24px;gap:16px;min-width:0;}
  [data-app] .cm-modal-side,
  [data-app] .cm-block,
  [data-app] .cm-prompt,
  [data-app] .cm-refs{min-width:0;}
  [data-app] .cm-modal-caption{font-size:14px;}
  [data-app] .cm-prompt p{padding-right:0;padding-top:26px;font-size:12px;}
  [data-app] .cm-copy{top:8px;right:8px;}
  [data-app] .cm-modal-foot{gap:8px;}
  [data-app] .cm-btn{padding:11px 15px;font-size:13px;}
  [data-app] .cm-btn.is-solid{flex:1 1 auto;justify-content:center;}
  [data-app] .cm-btn.is-quiet{margin-left:0;}

  [data-app] .cm-empty{padding:44px 18px;}

  /* the dialog becomes a sheet off the bottom, which is where a thumb is */
  .shr-dlg{
    left:0;right:0;bottom:0;top:auto;width:100%;
    max-height:min(90vh,760px);border-radius:18px 18px 0 0;
    transform:translateY(100%);
  }
  .shr-dlg.is-open{transform:translateY(0);}
  .shr-head{padding:20px 18px 0;}
  .shr-head h2{font-size:17px;}
  .shr-body{grid-template-columns:1fr;gap:14px;padding:16px 18px 4px;}
  .shr-shot{aspect-ratio:16/10;max-height:220px;}
  .shr-shot img,.shr-shot video{object-position:50% 40%;}
  .shr-foot{padding:14px 18px calc(16px + env(safe-area-inset-bottom));flex-wrap:wrap;}
  .shr-note{flex:1 1 100%;order:-1;}
  .shr-btn{flex:1 1 0;text-align:center;}
}


/* ══════════════════════════════════════════════════════════════════
   THE HEART

   Three places use it — the rail on a frame, the open window, and the
   community wall — and until now all three did something different: the
   rail turned the whole button gold, the window turned the glyph red,
   the wall used a third red. One mark, one treatment, one behaviour.

   ── black and white, like everything else ──
   No red. The studio is monochrome and a single red mark in it reads as
   a sticker somebody put on the interface. The heart says it is full by
   filling in and by lighting up, not by changing hue: it takes the ink
   of whatever surface it is on — white on the glass buttons over a
   photograph, page ink in the open window and on the wall — and carries
   a soft glow of the same colour.

   The glyph is two hearts stacked: an outline that is the resting state
   and a solid one that grows into it. A single glyph that only changes
   colour cannot say the difference between an empty heart and a full
   one, and without colour to lean on that difference is the whole
   message.

   ── the press ──
   Three things at once, none longer than six tenths of a second: the
   button takes the press (squash, then overshoot), the solid heart
   springs up through its own size behind a flare of glow, and one ring
   leaves the button and fades. Letting go of a favourite gets none of
   it — the heart shrinks back out, because taking something back should
   not be celebrated.
   ══════════════════════════════════════════════════════════════════ */
:root{ --heart-glow:rgba(255,255,255,.55); }
[data-app="light"]{ --heart-glow:rgba(18,18,18,.30); }
[data-theme="paper"]{ --heart-glow:rgba(21,19,15,.30); }

.hrt{overflow:visible;}
.hrt-o,.hrt-f{transform-box:fill-box;transform-origin:50% 50%;}
.hrt-f{
  transform:scale(.15);opacity:0;
  transition:transform .3s cubic-bezier(.34,1.56,.64,1),opacity .18s ease;
}
.hrt-o{opacity:1;transition:opacity .18s ease .04s;}
.is-on .hrt-f{transform:none;opacity:1;}
.is-on .hrt-o{opacity:0;transition-delay:0s;}

/* The glow is the colour signal, so it only exists once the heart is
   full. Two shadows rather than one: a tight core that reads as weight
   and a wide falloff that reads as light. */
.hrt{filter:none;transition:filter .26s var(--ease);}
.is-on .hrt{
  filter:drop-shadow(0 0 3px var(--heart-glow))
         drop-shadow(0 0 9px var(--heart-glow));
}

/* ── the press ── */
@keyframes heartPop{
  0%   {transform:scale(1);}
  26%  {transform:scale(.84);}
  58%  {transform:scale(1.16);}
  100% {transform:scale(1);}
}
@keyframes heartFill{
  0%   {transform:scale(.2);opacity:.45;}
  48%  {transform:scale(1.32);opacity:1;}
  100% {transform:scale(1);opacity:1;}
}
@keyframes heartFlare{
  0%   {filter:drop-shadow(0 0 0 var(--heart-glow)) drop-shadow(0 0 0 var(--heart-glow));}
  40%  {filter:drop-shadow(0 0 7px var(--heart-glow)) drop-shadow(0 0 20px var(--heart-glow));}
  100% {filter:drop-shadow(0 0 3px var(--heart-glow)) drop-shadow(0 0 9px var(--heart-glow));}
}
@keyframes heartRing{
  0%   {transform:scale(.7);opacity:.9;border-width:2.5px;}
  100% {transform:scale(2.15);opacity:0;border-width:.5px;}
}

.is-pop .hrt-f{animation:heartFill .5s cubic-bezier(.34,1.56,.64,1);}
.is-pop .hrt{animation:heartFlare .58s cubic-bezier(.2,.7,.3,1);}

/* ── the rail on a frame ──
   The button keeps its dark glass in both states. Filling the whole
   circle read as a coloured dot on the photograph rather than as a heart
   somebody filled in. The rest of the rail sits at .94 white; the kept
   heart goes to a full white and lights up, so it is the brightest thing
   on the column without being a different colour from it. */
/* This button is dark glass over a photograph whatever the page is set
   to, so its glow is its own rather than the page mode's — otherwise a
   white heart in light mode glowed near-black and the light went
   missing. Paper turns the button white, and takes the glow with it. */
.gw-act{position:relative;--heart-glow:rgba(255,255,255,.55);}
[data-theme="paper"] .gw-act{--heart-glow:rgba(21,19,15,.32);}
.gw-act.is-on{opacity:1;transform:none;background:rgba(10,9,8,.62);color:#fff;}
.gw-act.is-on:hover{background:rgba(255,255,255,.2);color:#fff;}
.gw-act.is-pop{animation:heartPop .46s cubic-bezier(.34,1.56,.64,1);}
/* ::before, not ::after — ::after is already the 44px tap target below.
   Sized explicitly rather than with inset:0: the ring has to be square to
   stay a circle. currentColor, so it is the same mark as the heart. */
.gw-act[data-gw-like]::before{
  content:'';position:absolute;left:50%;top:50%;
  width:30px;height:30px;margin:-15px 0 0 -15px;
  border-radius:100px;border:2px solid currentColor;
  opacity:0;pointer-events:none;
}
.gw-act.is-pop::before{animation:heartRing .58s cubic-bezier(.2,.7,.3,1);}

/* the paper theme turns that button into a white one, so the mark on it
   is ink rather than white — and the glow with it */
[data-theme="paper"] .gw-act.is-on{background:rgba(255,255,255,.8);color:#15130f;}

/* the open window — page ink, so it follows light and dark on its own */
.lb-icon{position:relative;}
.lb-icon.is-on{color:var(--a-ink,var(--ink-strong));}
.lb-icon.is-pop{animation:heartPop .46s cubic-bezier(.34,1.56,.64,1);}
.lb-icon[data-lb-do="fav"]::before{
  content:'';position:absolute;left:50%;top:50%;width:34px;height:34px;
  margin:-17px 0 0 -17px;border-radius:100px;
  border:2px solid currentColor;
  opacity:0;pointer-events:none;
}
.lb-icon.is-pop::before{animation:heartRing .58s cubic-bezier(.2,.7,.3,1);}

/* the community wall */
.cm-like,.cm-btn[data-cm-modal-like]{position:relative;}
.cm-like.is-on{color:var(--ink-strong);}
.cm-btn.is-on{color:var(--ink-strong);}
.cm-like.is-pop,.cm-btn.is-pop{animation:heartPop .46s cubic-bezier(.34,1.56,.64,1);}
/* Centred on the glyph, not on the button — both of these carry a count
   beside the heart, so the middle of the button is not the middle of the
   mark. The offsets are the padding plus half the icon. */
.cm-like::before,.cm-btn[data-cm-modal-like]::before{
  content:'';position:absolute;left:16px;top:50%;width:26px;height:26px;
  margin:-13px 0 0 -13px;border-radius:100px;
  border:2px solid currentColor;
  opacity:0;pointer-events:none;
}
.cm-btn[data-cm-modal-like]::before{left:25px;width:30px;height:30px;margin:-15px 0 0 -15px;}
.cm-like.is-pop::before,.cm-btn.is-pop::before{animation:heartRing .58s cubic-bezier(.2,.7,.3,1);}

/* A press is worth confirming; a press that jumps is not. Everything
   above collapses to the state change and the glow on its own. */
@media (prefers-reduced-motion:reduce){
  .hrt-f,.hrt-o,.hrt{transition:none;}
  .gw-act.is-pop,.lb-icon.is-pop,.cm-like.is-pop,.cm-btn.is-pop{animation:none;}
  .gw-act.is-pop::before,.lb-icon.is-pop::before,
  .cm-like.is-pop::before,.cm-btn.is-pop::before{animation:none;}
  .is-pop .hrt-f,.is-pop .hrt{animation:none;}
}

/* ── the rail retracts once you have used it ──
   Pressing the heart used to leave all five buttons sitting over the
   picture, so the thing you had just marked was still behind a menu.
   Now the other four leave together and the heart stays as the answer.
   Taken off on mouseleave, so the next hover is the full set again. */
/* Hover only. Retracting is a pointer manner — you pressed one of them,
   the rest get out of the way of what you just marked. Somebody working
   the keyboard is walking the buttons one at a time and needs all of
   them, so arriving by Tab always shows the full set. */
.gw-cell.is-acted:hover .gw-act:not([data-gw-like]){
  opacity:0;transform:translateY(-6px) scale(.9);
  pointer-events:none;transition-delay:0s;
}
/* and the heart holds, lit or not — un-marking something has to leave
   you somewhere to press again */
.gw-cell.is-acted .gw-act[data-gw-like]{opacity:1;transform:none;}

/* ══════════════════════════════════════════════════════════════════
   THE CAPTION ON A TEMPLATE

   It was a white slab across the bottom of the picture: a bright bar in
   a dark interface, sitting on the photograph rather than belonging to
   it, with the category at one end and two unrelated pieces of text
   jammed against the other.

   Now it is a scrim rising out of the frame with the words on the
   photograph — the treatment a still gets in an editorial layout rather
   than the one a toolbar gets. Two lines: what this is and where you
   are on the first, what it is for on the second. And a hairline across
   the very bottom carrying the position, because the arrows walk 263
   frames and a number alone does not show how far in you have come.
   ══════════════════════════════════════════════════════════════════ */
.tpl-modal-ref figcaption{
  position:absolute;left:0;right:0;bottom:0;
  display:flex;flex-direction:column;gap:6px;
  /* Both of these have to be said, not left out: the rule this replaces
     centred its children and let them wrap, and a column that inherits
     align-items:center shrink-wraps every line to its own text and puts
     it in the middle of the picture. */
  align-items:stretch;flex-wrap:nowrap;
  padding:96px 22px 22px;
  border-radius:0;
  backdrop-filter:none;-webkit-backdrop-filter:none;
  /* Five stops rather than two: a straight fade to transparent leaves a
     visible edge halfway up and the eye finds it every time. */
  background:linear-gradient(to top,
    rgba(0,0,0,.93) 0%,
    rgba(0,0,0,.84) 16%,
    rgba(0,0,0,.62) 38%,
    rgba(0,0,0,.32) 62%,
    rgba(0,0,0,.09) 82%,
    rgba(0,0,0,0) 100%);
  /* Nothing in here is clickable, and the scrim covers a third of the
     picture — so it lets everything through rather than swallowing it. */
  pointer-events:none;
}
/* The gradient was on a ::before at z-index:-1 so it could sit under the
   words. It sat under the photograph instead: the figcaption is
   positioned but makes no stacking context of its own, so a negative
   z-index inside it goes behind the whole figure, image included. There
   was never a reason for the extra layer — a background paints under the
   text on its own. */

.tpl-cap-line{display:flex;align-items:center;gap:14px;width:100%;min-width:0;}

/* the category, as glass on the photograph rather than a filled pill */
[data-app] .tpl-modal-ref .tpl-chip{
  flex:0 0 auto;
  padding:5px 11px 5px 10px;border-radius:100px;
  font-size:10px;font-weight:600;letter-spacing:.14em;text-transform:uppercase;
  color:#fff;background:rgba(255,255,255,.15);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.28);
  backdrop-filter:blur(10px) saturate(1.2);
  -webkit-backdrop-filter:blur(10px) saturate(1.2);
}

/* where you are: the frame you are on takes the weight, the total steps
   back, and the slash between them is nearly gone */
.tpl-modal-ref .tpl-modal-pos{
  margin-left:auto;flex:0 0 auto;
  display:inline-flex;align-items:baseline;gap:5px;
  font-variant-numeric:tabular-nums;
  font-size:12px;color:rgba(255,255,255,.55);
  text-shadow:0 1px 10px rgba(0,0,0,.5);
}
.tpl-modal-ref .tpl-modal-pos b{
  font-size:15px;font-weight:500;letter-spacing:-.01em;color:#fff;
}
.tpl-modal-ref .tpl-modal-pos i{font-style:normal;opacity:.35;}
.tpl-modal-ref .tpl-modal-pos em{font-style:normal;}

.tpl-modal-ref .tpl-modal-ref-note{
  font-size:12.5px;line-height:1.4;color:rgba(255,255,255,.72);
  letter-spacing:.005em;
  text-shadow:0 1px 10px rgba(0,0,0,.5);
}

/* ── the rail ──
   Flush to the bottom edge of the frame, the width of the run behind
   you. It animates because the arrows change it and a number that jumps
   tells you less than a length that travels. */
.tpl-cap-rail{
  position:absolute;left:0;right:0;bottom:0;height:2px;
  background:rgba(255,255,255,.16);overflow:hidden;
}
.tpl-cap-rail i{
  display:block;height:100%;width:0;
  background:#fff;box-shadow:0 0 10px rgba(255,255,255,.6);
  transition:width .55s cubic-bezier(.22,.61,.36,1);
}
@media (prefers-reduced-motion:reduce){
  .tpl-cap-rail i{transition:none;}
}

/* On a phone the frame is barely 470px tall, so a 78px run-up would put
   the scrim across half the picture. */
@media (max-width:860px){
  [data-app] .tpl-modal-ref figcaption{padding:70px 18px 18px;gap:5px;}
  /* the same 10px as the wide screen — an uppercase tracked label reads
     at a size lowercase body text could not */
  [data-app] .tpl-modal-ref .tpl-chip{padding:4px 10px;letter-spacing:.12em;}
  [data-app] .tpl-modal-ref .tpl-modal-pos{font-size:11.5px;}
  [data-app] .tpl-modal-ref .tpl-modal-pos b{font-size:14px;}
  [data-app] .tpl-modal-ref .tpl-modal-ref-note{font-size:12px;}
}

/* ══════════════════════════════════════════════════════════════════
   THE VIDEO COMPOSER, REDRAWN

   What was wrong was not any one control — it was that every control
   was its own island. A picture card, an uploader, a segmented switch,
   a prompt box, a row, three pills, another row, a counter, a button:
   nine shapes, nine radii, nine borders, stacked. That is what makes an
   interface look like a tool somebody assembled rather than a product
   somebody designed, and it is why it read as the same page as everyone
   else's.

   Three moves fix it, and they are the same three every expensive
   interface makes:

     ONE SURFACE. Settings stop being boxes and become a list — one
     container, hairlines between rows. Nothing floats.

     ONE HIERARCHY. The prompt is what you came to write, so it is the
     largest thing on the panel. The look becomes a line, not a poster.
     Section names become quiet eyebrows rather than headings competing
     with the fields under them.

     ONE RHYTHM. Rows are 52px. Radii are 14 outside and 0 inside a
     group. Gaps are 10 within a group and 22 between groups. Every
     number here appears more than once on purpose.

   Nothing below changes a data hook or a class the script reads.
   ══════════════════════════════════════════════════════════════════ */

/* ── the panel ──
   Wider, quieter, and no drop shadow: a lifted card inside a dark page
   is a card floating over nothing. A hairline is enough. */
.vg{
  flex:0 0 452px;max-width:452px;
  gap:22px;padding:22px 20px 20px;border-radius:22px;
  background:var(--a-panel);
  box-shadow:inset 0 0 0 1px var(--a-line);
}
/* The panel scrolls inside its own column, which makes it a column flex
   container with a fixed height — and a flex child in one of those gives
   up its height before the parent gives up any. The settings list came
   out 79px tall holding 168px of rows. Nothing here shrinks; the panel
   scrolls instead. */
.vg > *{flex:0 0 auto;}

/* ── the tool tabs ──
   Text, not chrome. The strip they sat on was a third bordered box
   before the panel had even started. */
.vg .vt{
  display:flex;gap:22px;margin:0 0 -6px;padding:0 2px 12px;
  box-shadow:inset 0 -1px 0 var(--a-line);
}
.vg .vt a{
  position:relative;padding:0 0 12px;margin-bottom:-12px;
  font-size:13.5px;font-weight:500;letter-spacing:-.005em;
  color:var(--a-mute);transition:color .2s var(--e-out);
}
.vg .vt a:hover{color:var(--a-ink);}
.vg .vt a.is-on{color:var(--a-ink);font-weight:600;}
.vg .vt a.is-on::after{
  content:'';position:absolute;left:0;right:0;bottom:0;height:1.5px;
  background:var(--a-ink);
}

/* ── the look ──
   It was a 132px poster with the name set in 19px uppercase accent over
   a photograph — the loudest thing on a panel where it is the smallest
   decision. Now it is a line: a thumbnail, what it is, and the way out. */
.vg-look{
  display:flex;align-items:center;gap:12px;
  height:auto;padding:9px 10px 9px 9px;border-radius:14px;
  background:var(--a-sunk);box-shadow:inset 0 0 0 1px var(--a-line);
  overflow:visible;
}
.vg-look img{
  position:static;width:44px;height:44px;flex:0 0 auto;
  border-radius:10px;object-fit:cover;
}
.vg-look:hover img{transform:none;}
.vg-look::after{display:none;}
.vg-look-body{
  position:static;display:flex;flex-direction:column;gap:1px;
  flex:1 1 auto;min-width:0;
}
.vg-look-body b{
  font-size:13.5px;font-weight:600;letter-spacing:-.01em;text-transform:none;
  color:var(--a-ink);text-shadow:none;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.vg-look-body em{font-size:11.5px;color:var(--a-mute);}
.vg-look-change{
  position:static;flex:0 0 auto;
  padding:8px 12px;border-radius:9px;
  background:transparent;box-shadow:inset 0 0 0 1px var(--a-line);
  backdrop-filter:none;-webkit-backdrop-filter:none;
  color:var(--a-mute);font-size:12px;font-weight:500;
  transition:color .2s var(--e-out),box-shadow .2s var(--e-out);
}
.vg-look-change:hover{color:var(--a-ink);box-shadow:inset 0 0 0 1px var(--a-mute);background:transparent;}
.vg-look-change svg{width:12px;height:12px;}

/* ── section names ──
   An eyebrow rather than a heading. A 13px semibold title sitting above
   a 13.5px semibold value makes two things of equal weight and neither
   of them reads as a label. */
.vg-h{
  font-size:10.5px;font-weight:600;letter-spacing:.12em;text-transform:uppercase;
  color:var(--a-mute);
}
.vg-h-row{display:flex;align-items:baseline;justify-content:space-between;gap:10px;}
.vg-h-n{font-size:11.5px;color:var(--a-mute);font-variant-numeric:tabular-nums;}
.vg-h-n b{color:var(--a-ink);font-weight:600;}
.vg-block{gap:11px;}
.vg-note{font-size:11px;line-height:1.5;color:var(--a-mute);opacity:.75;}

/* ── the prompt ──
   The one thing on this panel you actually author, so it is the one
   thing given room. Sixteen pixels of padding, a 132px floor, and type
   you can read rather than type that fits. */
.vg-prompt{
  border-radius:16px;background:var(--a-sunk);
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:box-shadow .22s var(--e-out);
}
.vg-prompt:focus-within{box-shadow:inset 0 0 0 1.5px var(--a-ink);}
.vg-prompt-h{padding:13px 15px 0;}
.vg-prompt-h .vg-h{font-size:10.5px;}
.vg-prompt textarea{
  padding:9px 15px 4px;min-height:132px;
  font-size:14px;line-height:1.6;letter-spacing:-.005em;color:var(--a-ink);
}
.vg-prompt textarea::placeholder{color:var(--a-mute);opacity:.8;}
.vg-prompt-bar{padding:8px 11px 11px;gap:6px;}

/* the small controls under the prompt, one weight quieter than before */
.vg-pill-s{
  padding:7px 11px;border-radius:9px;
  font-size:12px;font-weight:500;color:var(--a-mute);
  background:transparent;box-shadow:inset 0 0 0 1px var(--a-line);
  transition:color .18s var(--e-out),box-shadow .18s var(--e-out);
}
.vg-pill-s:hover{color:var(--a-ink);box-shadow:inset 0 0 0 1px var(--a-mute);}
/* The base rule fills this with the accent, which on the mono accent is
   white — and the quiet ink I set for the redesign then painted white on
   white. The background has to be said here too, not just the colour. */
.vg-pill-s.is-on{
  color:var(--a-ink);background:var(--a-chip-2);
  box-shadow:inset 0 0 0 1px var(--a-mute);
}

/* ── the reference tiles ──
   A square grid with one add slot, all the same size. The add slot is
   drawn with a hairline rather than a dashed border: dashes read as an
   unfinished state on every other surface in this studio. */
.vg-tiles{
  display:grid;grid-template-columns:repeat(4,1fr);gap:8px;
}
.vg-tiles .vg-tile{aspect-ratio:1;width:auto;height:auto;border-radius:12px;}
.vg-tiles .vg-tile.is-add{
  display:flex;align-items:center;justify-content:center;cursor:pointer;
  background:var(--a-sunk);box-shadow:inset 0 0 0 1px var(--a-line);
  color:var(--a-mute);font-size:18px;font-weight:300;line-height:1;
  transition:color .2s var(--e-out),box-shadow .2s var(--e-out);
}
.vg-tiles .vg-tile.is-add:hover{color:var(--a-ink);box-shadow:inset 0 0 0 1px var(--a-mute);}
/* Nothing added yet. One small square beside three empty columns reads as
   something that failed to load, so with nothing to sit next to it the
   slot takes the row and says what it is for. */
.vg-tiles .vg-tile.is-add:only-child{
  grid-column:1 / -1;aspect-ratio:auto;min-height:90px;
  flex-direction:column;gap:8px;font-size:0;
}
.vg-tiles .vg-tile.is-add:only-child::before{content:'+';font-size:20px;font-weight:300;line-height:1;}
.vg-tiles .vg-tile.is-add:only-child::after{
  content:'Add an element';font-size:12px;font-weight:500;letter-spacing:-.005em;
}

/* ── the two input modes ──
   A track with one lit segment, not two buttons in a tray. */
.vg-switchrow{
  gap:0;padding:3px;border-radius:11px;
  background:var(--a-sunk);box-shadow:inset 0 0 0 1px var(--a-line);
}
.vg-seg2{
  padding:8px 6px;border-radius:8px;
  font-size:12px;font-weight:500;letter-spacing:-.005em;
}
.vg-seg2.is-on{
  background:var(--a-panel);color:var(--a-ink);font-weight:600;
  box-shadow:0 1px 2px rgba(0,0,0,.28),inset 0 0 0 1px var(--a-line);
}

/* ══ the settings list ══════════════════════════════════════════════
   One container. The rows inside lose their own borders and radii and
   are separated by a hairline instead — which is the whole difference
   between a list and a stack of cards. */
.vg-set{
  border-radius:14px;overflow:hidden;
  background:var(--a-sunk);box-shadow:inset 0 0 0 1px var(--a-line);
}
.vg-set > .vg-row{border-radius:0;background:transparent;box-shadow:none;}
/* The divider was written as `> * + *`, which is one class and two
   universals — less specific than the `> .vg-row` above it, whose
   box-shadow:none then wiped every line in the list. Same specificity or
   the rows have no edges at all, and a list with no edges is a paragraph. */
.vg-set > .vg-row + .vg-row{box-shadow:inset 0 1px 0 var(--a-line);}
.vg-set > .vg-row{padding:0 12px 0 14px;min-height:46px;}
.vg-set > .vg-row:hover{background:transparent;box-shadow:none;}
.vg-set > .vg-row + .vg-row:hover{box-shadow:inset 0 1px 0 var(--a-line);}

/* ── label left, VALUE as a control ──
   The first pass had this the wrong way round: the label in bright ink
   and the value in grey. The label is the part that never changes and
   the value is the part you came to set, so the value takes the weight —
   and it takes it as a chip, because a chip reads as something you can
   press and a line of grey text reads as something you can only look at.
   That one inversion is most of the difference between a settings screen
   and an inspector. */
.vg-set .vg-row-txt{
  flex-direction:row;align-items:center;justify-content:space-between;gap:12px;
}
.vg-set .vg-row-txt em{
  font-size:12.5px;font-weight:400;letter-spacing:-.005em;color:var(--a-mute);
}
.vg-set .vg-row-txt b{
  padding:6px 10px;border-radius:9px;
  font-size:12.5px;font-weight:500;letter-spacing:-.005em;
  color:var(--a-ink);background:var(--a-chip);
  box-shadow:inset 0 0 0 1px transparent;
  font-variant-numeric:tabular-nums;
  transition:background-color .18s var(--e-out),box-shadow .18s var(--e-out);
}
.vg-set > .vg-row:hover .vg-row-txt b{
  background:var(--a-chip-2);box-shadow:inset 0 0 0 1px var(--a-mute);
}
.vg-set > .vg-row:hover .vg-row-txt em{color:var(--a-ink);}
.vg-set > .vg-row:hover .vg-chev{opacity:1;}
.vg-set .vg-row-mark{width:22px;height:22px;border-radius:7px;font-size:10.5px;}
.vg-set .vg-row-ic{width:17px;height:17px;}
.vg-set .vg-chev{width:14px;height:14px;opacity:.6;}

/* No leading icons in this list. One row carried a lettered brand mark,
   another a 20px glyph, the rest nothing — three different left edges for
   five labels that should start at the same x. The chevron on the right is
   the only ornament a settings list needs. */
.vg-set .vg-row-mark,
.vg-set .vg-row-ic{display:none;}
/* The chevron stops being a permanent mark on every row and becomes the
   thing that answers your pointer. Five arrows down the right of a list
   nobody is touching is five pieces of furniture. */
.vg-set .vg-chev{width:14px;height:14px;opacity:0;transition:opacity .18s var(--e-out);}
.vg-set .vg-row{gap:0;}

/* the bitrate badge was a filled accent chip for a setting that is not
   an event — it reads as an alert. A word is enough. */
.vg-spark{display:none;}

/* ══ the foot ══════════════════════════════════════════════════════
   The count and the button were two rows for one action. One row: the
   stepper holds its own width, Generate takes the rest. */
.vg-stick{
  position:sticky;bottom:0;z-index:3;
  margin:0 -20px -20px;padding:16px 20px 20px;
  background:linear-gradient(180deg,transparent,var(--a-panel) 34%);
  /* The stepper and the button are siblings here, not nested, so the row
     is made at this level: count on the left at its own width, Generate
     taking everything that is left, the small print under both. */
  display:grid;grid-template-columns:auto 1fr;gap:10px;align-items:stretch;
}
.vg-foot{display:flex;align-items:stretch;padding:0;}
.vg-legal{grid-column:1 / -1;}
.vg-qty{
  flex:0 0 auto;display:flex;align-items:center;gap:2px;
  padding:0 4px;border-radius:13px;
  background:var(--a-sunk);box-shadow:inset 0 0 0 1px var(--a-line);
}
.vg-qty button{
  width:32px;height:100%;min-height:52px;border-radius:10px;cursor:pointer;
  color:var(--a-mute);font-size:16px;line-height:1;
  transition:color .18s var(--e-out),background-color .18s var(--e-out);
}
.vg-qty button:hover{color:var(--a-ink);background:var(--a-chip);}
.vg-qty span{
  min-width:34px;text-align:center;
  font-size:12.5px;color:var(--a-mute);font-variant-numeric:tabular-nums;
}
.vg-qty span b{color:var(--a-ink);font-weight:600;font-size:13.5px;}

.vg-create{
  flex:1 1 auto;min-height:52px;border-radius:13px;
  display:flex;align-items:center;justify-content:center;gap:10px;
  font-size:14px;font-weight:600;letter-spacing:-.01em;
}
.vg-legal{
  padding-top:10px;text-align:center;
  font-size:11px;line-height:1.5;color:var(--a-mute);opacity:.75;
}

/* ══ the stage ═════════════════════════════════════════════════════
   The frame was right — it is drawn at the ratio you picked — but the
   header above it repeated the panel and the empty state sat in the
   middle of it like a dropped receipt. */
.vg-stage-top{
  gap:9px;padding:0 2px 2px;
}
.vg-stage-mark{width:22px;height:22px;border-radius:7px;font-size:10.5px;}
.vg-stage-name{font-size:13px;font-weight:600;letter-spacing:-.005em;}
.vg-stage-spec{
  margin-left:auto;
  font-size:11.5px;color:var(--a-mute);letter-spacing:.02em;
  font-variant-numeric:tabular-nums;
}
.vg-stage-frame{border-radius:16px;box-shadow:inset 0 0 0 1px var(--a-line);}
.vg-stage-empty b{
  font-size:15px;font-weight:500;letter-spacing:-.01em;color:var(--a-ink);
}
.vg-stage-empty > span{font-size:12.5px;line-height:1.55;color:var(--a-mute);}
.vg-samples-note{
  font-size:10px;font-weight:600;letter-spacing:.14em;text-transform:uppercase;
  color:var(--a-mute);opacity:.55;
}
.vg-stage-ratio{
  font-size:10.5px;font-weight:600;letter-spacing:.1em;
  color:var(--a-mute);
}

/* ══ narrower than 1180: the panel gives ground before the stage ══ */
@media (max-width:1180px){
  .vg{flex:0 0 400px;max-width:400px;}
}

/* ══════════════════════════════════════════════════════════════════
   THE ENGINE, SEPARATED

   The model sat as the first of five identical rows, which told you it
   mattered exactly as much as the bitrate. It does not: it decides which
   lengths exist, which ratios, how far the resolution goes. So it leaves
   the list and gets a card of its own, with the maker mark at a size you
   can see, the name set larger than anything else in the settings, and
   one line saying what this engine is for.

   The four rows left behind get quieter to match. Their values stop
   being filled pills and become outlined ones: still obviously pressable,
   no longer five solid shapes competing with the card above them.
   ══════════════════════════════════════════════════════════════════ */
.vg-model{
  display:flex;align-items:center;gap:13px;width:100%;
  padding:13px 13px 13px 12px;border-radius:16px;cursor:pointer;text-align:left;
  background:linear-gradient(180deg,rgba(255,255,255,.05),rgba(255,255,255,.015));
  box-shadow:inset 0 0 0 1px var(--a-line),inset 0 1px 0 rgba(255,255,255,.05);
  transition:box-shadow .2s var(--e-out);
}
.vg-model:hover{box-shadow:inset 0 0 0 1px var(--a-mute),inset 0 1px 0 rgba(255,255,255,.06);}
.vg-model:focus-visible{outline-offset:2px;}

.vg-model-mark{
  width:46px;height:46px;border-radius:13px;flex:0 0 auto;
  display:flex;align-items:center;justify-content:center;
  color:#fff;font-size:17px;font-weight:700;letter-spacing:-.01em;
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.14),0 6px 18px -10px rgba(0,0,0,.8);
}
.vg-model-mark svg{width:21px;height:21px;}
.vg-model-mark img{width:27px;height:27px;object-fit:contain;}

.vg-model-txt{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:2px;}
.vg-model-txt em{
  font-style:normal;font-size:10px;font-weight:600;letter-spacing:.14em;
  text-transform:uppercase;color:var(--a-mute);
}
.vg-model-txt b{
  font-size:15.5px;font-weight:600;letter-spacing:-.015em;color:var(--a-ink);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.vg-model-desc{
  font-size:12px;line-height:1.4;color:var(--a-mute);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}

.vg-model-change{
  flex:0 0 auto;padding:7px 12px;border-radius:9px;
  font-size:12px;font-weight:500;letter-spacing:-.005em;color:var(--a-ink);
  background:var(--a-chip);box-shadow:inset 0 0 0 1px var(--a-line);
  transition:background-color .18s var(--e-out),box-shadow .18s var(--e-out);
}
.vg-model:hover .vg-model-change{background:var(--a-chip-2);box-shadow:inset 0 0 0 1px var(--a-mute);}

/* ── the four rows under it, one step quieter ── */
.vg-set > .vg-row{min-height:44px;}
.vg-set .vg-row-txt b{
  padding:5px 10px;border-radius:8px;
  background:transparent;
  box-shadow:inset 0 0 0 1px var(--a-line);
  color:var(--a-ink);
}
.vg-set > .vg-row:hover .vg-row-txt b{
  background:var(--a-chip);box-shadow:inset 0 0 0 1px var(--a-mute);
}

/* The look row carried the model name as its second line. With the engine
   now in its own card directly under it, that line said the same name
   twice within eighty pixels. The look is the style, the card is the engine. */
.vg-look-body em{display:none;}


/* ══════════════════════════════════════════════════════════════════
   THE ENGINE PICKER, AS A SHEET

   It used to swap itself in for the stage: the preview vanished, a grey
   column of thirty-one small cards appeared in its place, and nothing
   about the change said "this is a decision". Now it arrives the way an
   important choice should.

     The studio stays where it is, blurred and dimmed behind a scrim, so
     you never lose your place.

     The sheet rises into the middle of the screen, sharpening out of a
     blur as it scales up. Leaving is animated too, just faster.

     The cards come in as a run, one after another, rather than all at
     once — and only when the sheet opens, never while you type a search.

     Under the pointer each card carries a soft light that follows the
     cursor, the chosen engine wears a ring and a tick, and the search
     bar stays pinned while thirty-one engines scroll beneath it.

   Everything is scoped to .is-sheet, which js/video.js adds only to the
   model panel, so the look and output panels are untouched.
   ══════════════════════════════════════════════════════════════════ */

html.vg-sheet-lock,
html.vg-sheet-lock body{overflow:hidden;}

/* ── the scrim ── */
.vg-scrim{
  position:fixed;inset:0;z-index:240;
  background:radial-gradient(120% 90% at 50% 40%,rgba(8,8,9,.42),rgba(4,4,5,.8));
  -webkit-backdrop-filter:blur(16px) saturate(1.1);
  backdrop-filter:blur(16px) saturate(1.1);
  animation:vgScrimIn .42s cubic-bezier(.16,1,.3,1) both;
}
.vg-scrim.is-leaving{animation:vgScrimOut .21s ease both;}
@keyframes vgScrimIn{from{opacity:0;}to{opacity:1;}}
@keyframes vgScrimOut{from{opacity:1;}to{opacity:0;}}

/* ── the sheet ── */
.vg-panel.is-sheet{
  position:fixed;z-index:241;left:50%;top:50%;
  flex:none;align-self:auto;
  width:min(1120px,calc(100vw - 48px));
  height:min(86vh,880px);max-height:none;
  transform:translate(-50%,-50%);
  border-radius:24px;overflow:hidden;
  background:
    radial-gradient(90% 60% at 50% -10%,rgba(255,255,255,.06),rgba(255,255,255,0) 60%),
    var(--a-panel);
  box-shadow:
    inset 0 0 0 1px var(--a-line),
    inset 0 1px 0 rgba(255,255,255,.07),
    0 50px 120px -30px rgba(0,0,0,.85),
    0 0 0 1px rgba(0,0,0,.35);
  animation:vgSheetIn .52s cubic-bezier(.16,1,.3,1) both;
}
.vg-panel.is-sheet.is-leaving{animation:vgSheetOut .21s cubic-bezier(.4,0,1,1) both;}
@keyframes vgSheetIn{
  from{opacity:0;transform:translate(-50%,-47%) scale(.96);filter:blur(8px);}
  to{opacity:1;transform:translate(-50%,-50%) scale(1);filter:blur(0);}
}
@keyframes vgSheetOut{
  from{opacity:1;transform:translate(-50%,-50%) scale(1);}
  to{opacity:0;transform:translate(-50%,-49%) scale(.98);}
}

/* ── the head ── */
.vg-panel.is-sheet .vg-panel-head{
  position:relative;align-items:flex-start;
  padding:26px 30px 14px;border-bottom:0;background:transparent;
}
.vg-sheet-title{display:flex;flex-direction:column;gap:5px;min-width:0;}
.vg-panel.is-sheet .vg-sheet-title h2{
  font-size:23px;font-weight:600;letter-spacing:-.03em;line-height:1.15;
}
.vg-sheet-title p{margin:0;font-size:13px;line-height:1.5;color:var(--a-mute);}
.vg-panel.is-sheet .vg-panel-head [data-vg-close]{
  flex:0 0 auto;width:38px;height:38px;border-radius:50%;
  display:grid;place-items:center;
  color:var(--a-ink);background:var(--a-chip);
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:background-color .2s ease,transform .35s cubic-bezier(.16,1,.3,1);
}
.vg-panel.is-sheet .vg-panel-head [data-vg-close]:hover{
  background:var(--a-chip-2);transform:rotate(90deg);
}
.vg-panel.is-sheet .vg-panel-head [data-vg-close] svg{width:16px;height:16px;}

/* ── the body ── */
.vg-panel.is-sheet .vg-panel-body{
  padding:6px 30px 40px;scrollbar-width:thin;
}
.vg-panel.is-sheet .vg-panel-h{
  font-size:10.5px;letter-spacing:.16em;margin:0 0 12px;
}
.vg-panel.is-sheet .vg-panel-h + *{margin-bottom:24px;}

/* ── the two recommended engines, as the heroes of the sheet ── */
.vg-panel.is-sheet .vg-feat{
  grid-template-columns:repeat(auto-fit,minmax(min(320px,100%),1fr));gap:14px;
}
.vg-panel.is-sheet .vg-feat-card{
  position:relative;overflow:hidden;
  min-height:190px;padding:20px;border-radius:18px;
  display:flex;flex-direction:column;justify-content:flex-end;gap:6px;
  background-size:cover;background-position:center;
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.1),0 20px 50px -30px rgba(0,0,0,.9);
  transition:transform .55s cubic-bezier(.16,1,.3,1),box-shadow .3s ease;
}
.vg-panel.is-sheet .vg-feat-card:hover{
  transform:translateY(-4px);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.3),0 30px 60px -28px rgba(0,0,0,.95);
}
.vg-panel.is-sheet .vg-feat-name{
  position:relative;z-index:1;
  font-size:21px;font-weight:600;letter-spacing:-.025em;
}
.vg-panel.is-sheet .vg-feat-desc{
  position:relative;z-index:1;
  font-size:13px;line-height:1.45;color:rgba(255,255,255,.8);max-width:36ch;
}
.vg-panel.is-sheet .vg-feat-card.is-on{
  box-shadow:
    inset 0 0 0 2px #fff,
    0 0 0 4px rgba(255,255,255,.08),
    0 30px 60px -28px rgba(0,0,0,.95);
}
.vg-panel.is-sheet .vg-feat-card.is-on::after{
  content:'';position:absolute;z-index:2;top:14px;right:14px;
  width:26px;height:26px;border-radius:50%;
  background:#fff url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M3.6 8.4l2.9 2.9 5.9-6.6' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/></svg>") center/13px no-repeat;
  box-shadow:0 6px 16px -6px rgba(0,0,0,.6);
  animation:vgTick .45s cubic-bezier(.34,1.56,.64,1) both;
}
@keyframes vgTick{from{transform:scale(.4);opacity:0;}to{transform:none;opacity:1;}}

/* ── the light that follows the pointer ──
   js/video.js writes --mx and --my on the card under the cursor. */
.vg-panel.is-sheet .vg-feat-card::before,
.vg-panel.is-sheet .vg-card::before{
  content:'';position:absolute;inset:0;pointer-events:none;
  border-radius:inherit;opacity:0;
  background:radial-gradient(300px circle at var(--mx,50%) var(--my,50%),
    rgba(255,255,255,.13),rgba(255,255,255,0) 62%);
  transition:opacity .35s ease;
}
.vg-panel.is-sheet .vg-feat-card:hover::before,
.vg-panel.is-sheet .vg-card:hover::before{opacity:1;}

/* ── the search bar, pinned while the engines scroll under it ── */
.vg-panel.is-sheet .vg-filters{
  position:sticky;top:-6px;z-index:5;
  flex-wrap:nowrap;gap:10px;
  margin:0 -30px 18px;padding:14px 30px;
  background:linear-gradient(180deg,var(--a-panel) 76%,transparent);
}
.vg-panel.is-sheet .vg-search{
  flex:1 1 auto;height:46px;padding:0 16px;gap:10px;border-radius:14px;
  background:var(--a-sunk);box-shadow:inset 0 0 0 1px var(--a-line);
  transition:box-shadow .22s ease;
}
.vg-panel.is-sheet .vg-search:focus-within{
  box-shadow:inset 0 0 0 1.5px var(--a-ink),0 0 0 5px color-mix(in srgb,var(--a-ink) 6%,transparent);
}
.vg-panel.is-sheet .vg-search svg{width:17px;height:17px;}
.vg-panel.is-sheet .vg-search input{font-size:14px;letter-spacing:-.005em;}
.vg-panel.is-sheet .vg-search input::placeholder{color:var(--a-mute);}

.vg-panel.is-sheet .vg-select{
  flex:0 0 auto;height:46px;padding:0 38px 0 15px;border:0;border-radius:14px;
  -webkit-appearance:none;appearance:none;cursor:pointer;
  font-size:13px;font-weight:500;color:var(--a-ink);
  background:var(--a-sunk) url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M4.5 6.5L8 10l3.5-3.5' fill='none' stroke='%23999' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/></svg>") right 13px center/14px no-repeat;
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:box-shadow .2s ease;
}
.vg-panel.is-sheet .vg-select:hover{box-shadow:inset 0 0 0 1px var(--a-mute);}
.vg-panel.is-sheet .vg-select option{background:var(--a-panel);color:var(--a-ink);}
.vg-panel.is-sheet .vg-count{flex:0 0 auto;margin-left:2px;}
.vg-panel.is-sheet .vg-count b{
  padding:0 4px;background:transparent;
  font-size:12.5px;font-weight:500;color:var(--a-mute);
}

/* ── the shelves, one per maker ── */
.vg-panel.is-sheet .vg-list{gap:34px;}
.vg-panel.is-sheet .vg-group-h{margin:0 0 14px;gap:10px;}
.vg-panel.is-sheet .vg-group-ico{width:26px;height:26px;border-radius:8px;}
.vg-panel.is-sheet .vg-group-ico svg{width:13px;height:13px;}
.vg-panel.is-sheet .vg-group-h b{font-size:11px;letter-spacing:.16em;}
.vg-panel.is-sheet .vg-group-h em{font-size:10.5px;padding:2px 8px;}
.vg-panel.is-sheet .vg-group-h i{background:linear-gradient(90deg,var(--a-line),transparent);}
.vg-panel.is-sheet .vg-group-g{
  grid-template-columns:repeat(auto-fill,minmax(min(310px,100%),1fr));gap:12px;
}

/* ── the engine cards ── */
.vg-panel.is-sheet .vg-card{
  position:relative;overflow:hidden;
  padding:16px 16px 14px;gap:11px;border-radius:16px;
  background:linear-gradient(180deg,rgba(255,255,255,.035),rgba(255,255,255,.008)),var(--a-sunk);
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:transform .45s cubic-bezier(.16,1,.3,1),box-shadow .25s ease;
}
.vg-panel.is-sheet .vg-card > *{position:relative;z-index:1;}
.vg-panel.is-sheet .vg-card:hover{
  transform:translateY(-3px);
  box-shadow:inset 0 0 0 1px var(--a-mute),0 22px 44px -26px rgba(0,0,0,.95);
}
.vg-panel.is-sheet .vg-card-top{gap:12px;}
.vg-panel.is-sheet .vg-card-ico{width:38px;height:38px;border-radius:11px;}
.vg-panel.is-sheet .vg-card-ico svg{width:17px;height:17px;}
.vg-panel.is-sheet .vg-card .vg-item-name{font-size:14.5px;font-weight:600;letter-spacing:-.015em;}
.vg-panel.is-sheet .vg-card .vg-card-by{font-size:10px;letter-spacing:.14em;}
.vg-panel.is-sheet .vg-card .vg-item-desc{
  font-size:12.5px;line-height:1.5;height:3em;
  color:color-mix(in srgb,var(--a-ink) 74%,transparent);
}
.vg-panel.is-sheet .vg-cap.is-ico{width:24px;height:24px;border-radius:7px;}
.vg-panel.is-sheet .vg-card-spec{font-size:11px;}

/* the one you are on: a ring, a halo, and the tick pops in */
.vg-panel.is-sheet .vg-card.is-on{
  background:linear-gradient(180deg,rgba(255,255,255,.08),rgba(255,255,255,.02)),var(--a-sunk);
  box-shadow:
    inset 0 0 0 1.5px var(--a-ink),
    0 0 0 4px color-mix(in srgb,var(--a-ink) 8%,transparent),
    0 24px 50px -28px rgba(0,0,0,.9);
}
.vg-panel.is-sheet .vg-card.is-on .vg-card-ico:not(.has-logo){background:var(--a-ink);color:var(--a-panel);}
.vg-panel.is-sheet .vg-card-on{
  width:22px;height:22px;background:var(--a-ink);color:var(--a-panel);
  animation:vgTick .45s cubic-bezier(.34,1.56,.64,1) both;
}

/* ── the entrance run ──
   Only a from-state, so each card animates to whatever it really is — a
   not-yet-connected engine settles at its dimmed opacity instead of
   flashing to full first. */
@keyframes vgCardIn{from{opacity:0;transform:translateY(14px) scale(.985);}}
.vg-panel.is-sheet.is-entering .vg-card,
.vg-panel.is-sheet.is-entering .vg-feat-card{
  animation:vgCardIn .55s cubic-bezier(.16,1,.3,1) both;
  animation-delay:calc(110ms + min(var(--i,0),20) * 24ms);
}

/* ── light mode ── */
[data-app="light"] .vg-scrim{
  background:radial-gradient(120% 90% at 50% 40%,rgba(250,250,250,.3),rgba(228,228,228,.72));
}
[data-app="light"] .vg-panel.is-sheet{
  box-shadow:inset 0 0 0 1px var(--a-line),0 40px 100px -30px rgba(0,0,0,.28);
}
[data-app="light"] .vg-panel.is-sheet .vg-card:hover{
  box-shadow:inset 0 0 0 1px var(--a-mute),0 18px 40px -26px rgba(0,0,0,.25);
}
[data-app="light"] .vg-panel.is-sheet .vg-card::before{
  background:radial-gradient(300px circle at var(--mx,50%) var(--my,50%),
    rgba(0,0,0,.05),rgba(0,0,0,0) 62%);
}

/* ── less motion ── */
@media (prefers-reduced-motion:reduce){
  .vg-scrim,.vg-scrim.is-leaving,
  .vg-panel.is-sheet,.vg-panel.is-sheet.is-leaving,
  .vg-panel.is-sheet.is-entering .vg-card,
  .vg-panel.is-sheet.is-entering .vg-feat-card,
  .vg-panel.is-sheet .vg-card-on,
  .vg-panel.is-sheet .vg-feat-card.is-on::after{animation:none;}
  .vg-panel.is-sheet .vg-card:hover,
  .vg-panel.is-sheet .vg-feat-card:hover,
  .vg-panel.is-sheet .vg-panel-head [data-vg-close]:hover{transform:none;}
}

/* ── a phone: the sheet comes up from the bottom ── */
@media (max-width:760px){
  .vg-panel.is-sheet{
    left:0;right:0;top:auto;bottom:0;width:100%;
    height:94vh;height:94dvh;
    border-radius:22px 22px 0 0;transform:none;
    animation:vgSheetUp .48s cubic-bezier(.16,1,.3,1) both;
  }
  .vg-panel.is-sheet.is-leaving{animation:vgSheetDown .22s cubic-bezier(.4,0,1,1) both;}
  @keyframes vgSheetUp{from{transform:translateY(100%);}to{transform:none;}}
  @keyframes vgSheetDown{from{transform:none;}to{transform:translateY(100%);}}
  .vg-panel.is-sheet .vg-panel-head{padding:20px 18px 10px;}
  .vg-panel.is-sheet .vg-sheet-title h2{font-size:19px;}
  .vg-panel.is-sheet .vg-sheet-title p{font-size:12.5px;}
  .vg-panel.is-sheet .vg-panel-body{padding:4px 16px 30px;}
  .vg-panel.is-sheet .vg-filters{margin:0 -16px 14px;padding:10px 16px;flex-wrap:wrap;}
  .vg-panel.is-sheet .vg-search{flex:1 1 100%;height:44px;}
  .vg-panel.is-sheet .vg-select{flex:1 1 0;min-width:0;height:40px;}
  .vg-panel.is-sheet .vg-count{display:none;}
  .vg-panel.is-sheet .vg-feat{grid-template-columns:1fr 1fr;gap:10px;}
  .vg-panel.is-sheet .vg-feat-card{min-height:134px;padding:13px;border-radius:15px;}
  .vg-panel.is-sheet .vg-feat-name{font-size:15px;}
  .vg-panel.is-sheet .vg-feat-desc{font-size:11.5px;}
  .vg-panel.is-sheet .vg-group-g{grid-template-columns:1fr;gap:10px;}
  .vg-panel.is-sheet .vg-card{padding:14px;}
}


/* ══════════════════════════════════════════════════════════════════
   EDIT VIDEO, BROUGHT IN LINE WITH CREATE VIDEO

   The two pages share one stylesheet but not one structure, so every
   change made for Create Video landed here half-fitted: Generate squeezed
   into a narrow column, the engine still a plain row, resolution and
   bitrate crammed side by side as two different shapes, and two tall
   empty wells that pushed everything below the fold.

   Now the column reads the same as its sibling: the engine gets its card,
   the settings are one list with the values as chips, the picker opens
   as the same sheet, and the two uploads are compact rows — a tile, what
   it wants, and one clear action — instead of centred boxes of air.
   ══════════════════════════════════════════════════════════════════ */

/* Generate on a page with no clip counter. The foot is a two-column grid
   built for Create Video, where a stepper sits left of the button; here
   the button is the first child, fell into the narrow column and came out
   123px wide. With nothing beside it, it takes the whole row. */
.vg-stick > .vg-create:first-child{grid-column:1 / -1;}

/* ── the two uploads, as rows ── */
.vge .vge-drop{
  border-radius:16px;
  background:linear-gradient(180deg,rgba(255,255,255,.03),rgba(255,255,255,.008)),var(--a-sunk);
  box-shadow:inset 0 0 0 1px var(--a-line);
}
.vge .vge-drop:hover{box-shadow:inset 0 0 0 1px var(--a-mute);}
.vge .vge-drop.is-over{box-shadow:inset 0 0 0 1.5px var(--a-ink);}

.vge .vge-drop-empty{
  display:grid;grid-template-columns:auto minmax(0,1fr) auto;
  grid-template-rows:auto auto;column-gap:14px;row-gap:2px;
  align-items:center;justify-items:start;
  padding:14px 14px 14px 14px;text-align:left;
}
.vge .vge-drop.is-lead .vge-drop-empty{padding:18px 14px;}

.vge .vge-drop-ic{
  grid-row:1 / span 2;grid-column:1;
  width:46px;height:46px;margin:0;border-radius:13px;
  background:var(--a-chip);color:var(--a-ink);
  box-shadow:inset 0 0 0 1px var(--a-line);
}
.vge .vge-drop-ic svg{width:20px;height:20px;}

.vge .vge-drop-empty b{
  grid-column:2;grid-row:1;align-self:end;
  font-size:13.5px;font-weight:600;letter-spacing:-.01em;color:var(--a-ink);
}
.vge .vge-drop-empty em{
  grid-column:2;grid-row:2;align-self:start;
  font-size:12px;line-height:1.4;color:var(--a-mute);
}

/* one clear action on the right, the same weight as Change on the look */
.vge .vge-drop-empty::after{
  content:'Upload';grid-column:3;grid-row:1 / span 2;align-self:center;
  padding:8px 13px;border-radius:9px;
  font-size:12px;font-weight:500;letter-spacing:-.005em;color:var(--a-ink);
  background:var(--a-chip);box-shadow:inset 0 0 0 1px var(--a-line);
  transition:background-color .18s var(--e-out),box-shadow .18s var(--e-out);
}
.vge .vge-drop:not(.is-lead) .vge-drop-empty::after{content:'Add';}
.vge .vge-drop:hover .vge-drop-empty::after{
  background:var(--a-chip-2);box-shadow:inset 0 0 0 1px var(--a-mute);
}

/* pictures and sound: two small tiles overlapped inside one square */
.vge .vge-drop-ic.is-pair{
  position:relative;display:block;
  width:46px;height:46px;border-radius:13px;
  background:var(--a-chip);box-shadow:inset 0 0 0 1px var(--a-line);
}
.vge .vge-drop-ic.is-pair i{
  position:absolute;display:grid;place-items:center;
  width:27px;height:27px;border-radius:8px;margin:0;
  background:var(--a-sunk);color:var(--a-ink);
  box-shadow:inset 0 0 0 1px var(--a-line),0 0 0 2px var(--a-chip);
}
.vge .vge-drop-ic.is-pair i:first-child{left:5px;top:5px;}
.vge .vge-drop-ic.is-pair i + i{margin:0;right:5px;bottom:5px;}
.vge .vge-drop-ic.is-pair svg{width:14px;height:14px;}

/* an engine that takes no references: the row says so by fading, and
   its action goes quiet rather than inviting a click that does nothing */
.vge .vge-drop.is-off{opacity:.42;}
.vge .vge-drop.is-off .vge-drop-empty::after{content:'Not on this model';background:transparent;box-shadow:none;color:var(--a-mute);}

/* the clip once it is in */
.vge .vge-drop-full video{max-height:220px;}
.vge .vge-drop-meta{padding:10px 14px;}

@media (max-width:420px){
  .vge .vge-drop-empty{column-gap:12px;padding:13px 12px;}
  .vge .vge-drop-empty::after{padding:7px 11px;}
}


/* ══════════════════════════════════════════════════════════════════
   THE CLIP WELL

   The video card keeps its header — what it wants and how long the clip
   may be — and gains a proper place to put the clip underneath: a well,
   rather than a small button off to the side.

     A dashed edge that starts to move when the pointer arrives, so the
     well reads as a target before anything is dragged over it.

     An upload mark in a lit ring, breathing slowly, whose arrow lifts on
     hover; a sheen that crosses the well once as you arrive.

     Hold a file over it and the edge goes solid, the well swells a hair,
     the ring comes forward and the words change to "Let go to add it".

   The well lives inside .vge-drop-empty, so it disappears with it the
   moment a clip is in and the preview takes its place.
   ══════════════════════════════════════════════════════════════════ */

/* the lead card: header on top, the well under it */
.vge .vge-drop.is-lead .vge-drop-empty{
  grid-template-columns:auto minmax(0,1fr);
  grid-template-rows:auto auto auto;
  padding:16px;
}
.vge .vge-drop.is-lead .vge-drop-empty::after{content:none;display:none;}
.vge .vge-drop.is-lead:hover{box-shadow:inset 0 0 0 1px var(--a-line);}

.vge-well{
  grid-column:1 / -1;grid-row:3;justify-self:stretch;
  position:relative;isolation:isolate;
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;
  min-height:178px;margin-top:14px;padding:24px 16px;border-radius:14px;
  text-align:center;overflow:hidden;
  background:
    radial-gradient(90% 80% at 50% 0%,rgba(255,255,255,.07),rgba(255,255,255,0) 62%),
    rgba(0,0,0,.22);
  transition:background-color .3s ease,transform .5s cubic-bezier(.16,1,.3,1);
}

/* the sheen that crosses once on arrival */
.vge-well::before{
  content:'';position:absolute;z-index:-1;inset:-40% -60%;
  background:linear-gradient(105deg,transparent 40%,rgba(255,255,255,.075) 50%,transparent 60%);
  transform:translateX(-60%);opacity:0;pointer-events:none;
}
@keyframes vgeSheen{from{transform:translateX(-60%);opacity:1;}to{transform:translateX(60%);opacity:1;}}

/* the dashed edge */
.vge-well-edge{
  position:absolute;inset:0;width:100%;height:100%;
  pointer-events:none;overflow:visible;
}
.vge-well-edge rect{
  width:calc(100% - 2px);height:calc(100% - 2px);
  fill:none;stroke:rgba(255,255,255,.2);stroke-width:1.2;stroke-dasharray:7 7;
  transition:stroke .3s ease,stroke-width .2s ease;
}
@keyframes vgeMarch{to{stroke-dashoffset:-28;}}

/* the upload mark */
.vge-well-ring{
  position:relative;width:56px;height:56px;border-radius:50%;
  display:grid;place-items:center;color:var(--a-ink);
  background:linear-gradient(180deg,rgba(255,255,255,.14),rgba(255,255,255,.04));
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.16),0 12px 30px -14px rgba(0,0,0,.9);
  transition:transform .5s cubic-bezier(.34,1.56,.64,1),box-shadow .3s ease;
}
.vge-well-ring::before{
  content:'';position:absolute;inset:-7px;border-radius:50%;
  border:1px solid rgba(255,255,255,.16);
  animation:vgeRing 2.8s cubic-bezier(.16,1,.3,1) infinite;
}
@keyframes vgeRing{
  0%{transform:scale(.82);opacity:0;}
  35%{opacity:1;}
  100%{transform:scale(1.4);opacity:0;}
}
.vge-well-ring svg{width:23px;height:23px;transition:transform .5s cubic-bezier(.34,1.56,.64,1);}

.vge-well-t{font-size:14px;font-weight:600;letter-spacing:-.01em;color:var(--a-ink);}
.vge-well-t .is-drag{display:none;}

.vge-well-btn{
  display:inline-flex;align-items:center;gap:7px;
  padding:9px 17px;border-radius:100px;
  font-size:12.5px;font-weight:600;letter-spacing:-.005em;
  color:var(--a-btn-ink);background:var(--a-btn);
  box-shadow:0 8px 22px -12px rgba(0,0,0,.8);
  transition:transform .35s cubic-bezier(.16,1,.3,1),box-shadow .3s ease;
}

/* ── arriving, on devices that really hover ── */
@media (hover:hover){
  .vge-drop.is-lead:hover .vge-well::before{animation:vgeSheen 1.5s cubic-bezier(.16,1,.3,1) both;}
  .vge-drop.is-lead:hover .vge-well-edge rect{
    stroke:rgba(255,255,255,.42);animation:vgeMarch 1.1s linear infinite;
  }
  .vge-drop.is-lead:hover .vge-well-ring{
    box-shadow:inset 0 0 0 1px rgba(255,255,255,.3),0 16px 36px -14px rgba(0,0,0,.95),0 0 30px -6px rgba(255,255,255,.2);
  }
  .vge-drop.is-lead:hover .vge-well-ring svg{transform:translateY(-3px);}
  .vge-drop.is-lead:hover .vge-well-btn{
    transform:translateY(-1px);
    box-shadow:0 12px 26px -12px rgba(0,0,0,.9),0 0 0 4px color-mix(in srgb,var(--a-btn) 14%,transparent);
  }
}

/* ── a file held over the well ── */
.vge-drop.is-over .vge-well{
  transform:scale(1.012);
  background:
    radial-gradient(90% 80% at 50% 0%,rgba(255,255,255,.13),rgba(255,255,255,0) 62%),
    rgba(255,255,255,.04);
}
.vge-drop.is-over .vge-well-edge rect{stroke:var(--a-ink);stroke-dasharray:none;stroke-width:1.5;animation:none;}
.vge-drop.is-over .vge-well-ring{transform:scale(1.08);}
.vge-drop.is-over .vge-well-ring svg{transform:translateY(-4px);}
.vge-drop.is-over .vge-well-t .is-idle{display:none;}
.vge-drop.is-over .vge-well-t .is-drag{display:inline;}

/* ── light mode ── */
[data-app="light"] .vge-well{
  background:
    radial-gradient(90% 80% at 50% 0%,rgba(0,0,0,.035),rgba(0,0,0,0) 62%),
    rgba(0,0,0,.025);
}
[data-app="light"] .vge-well::before{
  background:linear-gradient(105deg,transparent 40%,rgba(0,0,0,.045) 50%,transparent 60%);
}
[data-app="light"] .vge-well-edge rect{stroke:rgba(0,0,0,.22);}
[data-app="light"] .vge-well-ring{
  background:linear-gradient(180deg,#fff,#f1f1f1);
  box-shadow:inset 0 0 0 1px rgba(0,0,0,.1),0 10px 24px -14px rgba(0,0,0,.35);
}
[data-app="light"] .vge-well-ring::before{border-color:rgba(0,0,0,.12);}
@media (hover:hover){
  [data-app="light"] .vge-drop.is-lead:hover .vge-well-edge rect{stroke:rgba(0,0,0,.42);}
  [data-app="light"] .vge-drop.is-lead:hover .vge-well-ring{
    box-shadow:inset 0 0 0 1px rgba(0,0,0,.18),0 14px 30px -14px rgba(0,0,0,.4);
  }
}

/* ── less motion ── */
@media (prefers-reduced-motion:reduce){
  .vge-well-ring::before{animation:none;opacity:0;}
  .vge-drop.is-lead:hover .vge-well-edge rect,
  .vge-drop.is-lead:hover .vge-well::before{animation:none;}
  .vge-drop.is-lead:hover .vge-well-ring svg,
  .vge-drop.is-over .vge-well-ring svg,
  .vge-drop.is-over .vge-well,
  .vge-drop.is-over .vge-well-ring{transform:none;}
}

/* ── a phone ── */
@media (max-width:760px){
  .vge-well{min-height:152px;padding:20px 14px;gap:10px;}
  .vge-well-ring{width:50px;height:50px;}
  .vge-well-ring svg{width:21px;height:21px;}
}

/* ══════════════════════════════════════════════════════════════════
   EDIT VIDEO, FITTED TO ONE SCREEN

   Measured before this: the column held 1133px of content in an 812px
   panel on a 1440x900 screen, so the settings and the model sat under
   the Generate bar until you scrolled. The fat was spread thin rather
   than in one place: 22px between eight blocks (154px on its own), a
   181px upload well, a 132px prompt floor, 46px tiles everywhere and a
   131px foot. Every one of them gives some back here, and nothing is
   removed, only tightened.

   A second tier below 860px of height tightens further, for laptops.
   The phone layout scrolls the page rather than the column, so none of
   this is about phones, but none of it breaks them either.
   ══════════════════════════════════════════════════════════════════ */

/* the column: half the gaps, a little less padding, the foot tucked in */
.vg.vge{gap:10px;padding:14px 16px 14px;}
.vg.vge .vt{padding-bottom:10px;margin-bottom:-2px;}
.vge .vg-stick{margin:0 -16px -14px;padding:10px 16px 14px;row-gap:6px;}
.vge .vg-create{min-height:46px;}
.vge .vg-legal{padding-top:2px;}

/* the look */
.vge .vg-look{padding:6px 8px 6px 6px;}
.vge .vg-look img{width:36px;height:36px;border-radius:9px;}

/* the clip card: a smaller header, a shallower well */
.vge .vge-drop.is-lead .vge-drop-empty{padding:12px;}
.vge .vge-drop-ic{width:36px;height:36px;border-radius:10px;}
.vge .vge-drop-ic svg{width:17px;height:17px;}
.vge .vge-well{min-height:112px;margin-top:10px;padding:14px;gap:8px;}
.vge .vge-well-ring{width:40px;height:40px;}
.vge .vge-well-ring::before{inset:-5px;}
.vge .vge-well-ring svg{width:18px;height:18px;}
.vge .vge-well-t{font-size:13px;}
.vge .vge-well-btn{padding:7px 14px;font-size:12px;}

/* the references row */
.vge .vge-drop:not(.is-lead) .vge-drop-empty{padding:9px 10px;column-gap:12px;}
.vge .vge-drop-ic.is-pair{width:36px;height:36px;border-radius:10px;}
.vge .vge-drop-ic.is-pair i{width:21px;height:21px;border-radius:6px;}
.vge .vge-drop-ic.is-pair i:first-child{left:4px;top:4px;}
.vge .vge-drop-ic.is-pair i + i{right:4px;bottom:4px;}
.vge .vge-drop-ic.is-pair svg{width:12px;height:12px;}

/* and when this engine takes no references, it is one quiet line: no
   tile, no subtitle, just the name of the thing and why it is resting */
.vge .vge-drop.is-off .vge-drop-ic,
.vge .vge-drop.is-off .vge-drop-empty em{display:none;}
.vge .vge-drop.is-off .vge-drop-empty{grid-template-columns:minmax(0,1fr) auto;padding:10px 12px;}
.vge .vge-drop.is-off .vge-drop-empty b{grid-column:1;grid-row:1 / span 2;align-self:center;font-size:12.5px;}
.vge .vge-drop.is-off .vge-drop-empty::after{grid-column:2;padding:0;}

/* the prompt: a lower floor, the expand button still opens it up */
.vge .vg-prompt-h{padding:10px 13px 0;}
.vge .vg-prompt textarea{min-height:72px;padding:6px 13px 2px;}
.vge .vg-prompt.is-tall textarea{min-height:200px;}
.vge .vg-prompt-bar{padding:4px 9px 8px;}

/* the engine card and the two settings */
.vge .vg-model{padding:9px 10px 9px 9px;gap:11px;}
.vge .vg-model-mark{width:40px;height:40px;border-radius:11px;}
.vge .vg-model-txt b{font-size:14.5px;}
.vge .vg-set > .vg-row{min-height:38px;}

/* ── laptops: under 860px of height, one step tighter ── */
@media (min-width:861px) and (max-height:860px){
  .vg.vge{gap:8px;padding-top:12px;}
  .vge .vg-look img{width:32px;height:32px;}
  .vge .vge-well{min-height:84px;padding:10px 12px;gap:6px;margin-top:8px;}
  .vge .vge-well-ring{width:32px;height:32px;}
  .vge .vge-well-ring svg{width:15px;height:15px;}
  .vge .vge-well-t{font-size:12.5px;}
  .vge .vge-well-btn{padding:6px 12px;}
  .vge .vg-prompt textarea{min-height:52px;}
  .vge .vg-model-desc{display:none;}
  .vge .vg-set > .vg-row{min-height:36px;}
  .vge .vg-legal{display:none;}
  .vge .vg-create{min-height:44px;}
}

/* ── second pass, from the measurements ──
   The prompt stayed at 98px after the first pass because the textarea
   carries rows="4", and a min-height below that intrinsic height does
   nothing. It needs an explicit height, with the expanded state still
   winning. On short screens the well was held up by its own content,
   ring over words over button, so there it lays out in a single row. */
.vge .vg-prompt textarea{height:66px;min-height:0;}
.vge .vg-prompt.is-tall textarea{height:200px;min-height:200px;}
.vge .vge-well{min-height:96px;}
.vge .vg-stick{padding:8px 16px 12px;}
.vge .vg-set > .vg-row{min-height:36px;}

@media (min-width:861px) and (max-height:860px){
  .vg.vge{gap:6px;}
  .vge .vg-prompt textarea{height:48px;}
  .vge .vg-prompt.is-tall textarea{height:180px;min-height:180px;}
  .vge .vge-well{
    flex-direction:row;justify-content:center;gap:12px;
    min-height:0;padding:10px 12px;margin-top:8px;
  }
  .vge .vge-well-t{text-align:left;}
}

/* measured after the second pass: the column fit exactly at 1440x900,
   with the settings list 2px under the soft top edge of the Generate foot.
   One pixel less between each block gives it a few pixels of air. */
.vg.vge{gap:9px;}
/* ...but that rule sits later than the laptop tier and has the same
   specificity, so on short screens it would undo the tier gap of 6px.
   Said again here, after it. */
@media (min-width:861px) and (max-height:860px){
  .vg.vge{gap:6px;}
}

/* ══════════════════════════════════════════════════════════════════
   EDIT VIDEO, FILLING THE COLUMN

   The fit above was tuned for the tightest case, a 900px screen, and on
   a taller one it left the whole column squeezed against the top with
   a tall empty band under Generate. Tight is right only when space is
   short. So the column now adapts to its height instead of assuming one:

     Generate sits at the bottom of the column, always.
     Spare height goes to the two places that can use it, the upload
     well and the prompt field, each with a ceiling so neither balloons.
     The gaps between blocks open up as the screen gets taller.
     Tall screens give the tiles and rows back some of their size.

   None of it adds height where there is none to spare, so the 900px and
   768px fits measured before still hold. Desktop layout only: on a phone
   the page scrolls and there is no column height to fill.
   ══════════════════════════════════════════════════════════════════ */
@media (min-width:861px){
  .vge .vg-stick{margin-top:auto;}

  .vge .vge-drop.is-lead{flex:1 1 auto;display:flex;flex-direction:column;max-height:380px;}
  .vge .vge-drop.is-lead.is-full{flex:0 0 auto;max-height:none;}
  .vge .vge-drop.is-lead .vge-drop-empty{flex:1 1 auto;grid-template-rows:auto auto minmax(0,1fr);}
  .vge .vge-well{align-self:stretch;}

  .vge .vg-prompt{flex:1 1 auto;display:flex;flex-direction:column;max-height:300px;}
  .vge .vg-prompt textarea{flex:1 1 0;height:auto;min-height:var(--vge-ta-min,66px);}
  .vge .vg-prompt.is-tall{max-height:none;}
  .vge .vg-prompt.is-tall textarea{flex:0 0 auto;height:200px;min-height:200px;}
}
@media (min-width:861px) and (max-height:860px){
  .vg.vge{--vge-ta-min:48px;}
  .vge .vg-prompt.is-tall textarea{height:180px;min-height:180px;}
}
@media (min-width:861px) and (min-height:861px){
  .vg.vge{gap:clamp(9px,calc((100vh - 810px) / 10),16px);}
}
@media (min-width:861px) and (min-height:1000px){
  .vge .vg-look img{width:40px;height:40px;}
  .vge .vge-drop-ic,
  .vge .vge-drop-ic.is-pair{width:40px;height:40px;}
  .vge .vg-model-mark{width:44px;height:44px;}
  .vge .vg-set > .vg-row{min-height:42px;}
  .vge .vg-create{min-height:50px;}
}

/* ── the foot, flush with the bottom ──
   A sticky element is kept out of its scroll container's padding. The
   foot reached 14px into the column's bottom padding through a negative
   margin, so the browser lifted it 14px, over the last settings row.
   The empty band that used to sit above it hid this; once the column
   filled its height, the settings showed under Generate. The bottom
   space now lives in the foot itself instead of the column, which keeps
   every height the same and gives sticky nothing to correct. */
@media (min-width:861px){
  .vg.vge{padding-bottom:0;}
  .vge .vg-stick{margin-bottom:0;}
}

/* EDIT VIDEO: GROW, NEVER CLIP
   The upload card and the prompt grow into spare height. The upload card
   clips what is inside it, and a flex item that clips may be shrunk below
   its own content, so opening the tall prompt squeezed the card and cut
   the bottom off the drop well. Neither may shrink now; they only grow.
   When the tall prompt does not fit, the column scrolls under its foot. */
@media (min-width:861px){
  .vge .vge-drop.is-lead,
  .vge .vg-prompt{flex-shrink:0;}
}

/* EDIT VIDEO: THE CLIP GIVES WAY
   With a clip in, the upload card was a fixed 257px. On a laptop it pushed
   Quality and Bitrate under the Generate bar; on a tall screen it stood
   still while the rest of the column grew. The preview is now the part of
   the card that bends: it grows with the column up to the cap of the empty
   card, and on a short screen it gives up height first, cropping the frame
   instead of hiding the settings, down to a floor where the column scrolls.
   The large preview on the stage is untouched. */
@media (min-width:861px){
  .vge .vge-drop.is-lead.is-full{flex:1 1 auto;min-height:150px;max-height:380px;}
  .vge .vge-drop.is-lead.is-full .vge-drop-full{flex:1 1 auto;min-height:0;display:flex;flex-direction:column;}
  .vge .vge-drop.is-lead.is-full .vge-drop-full video{flex:1 1 220px;min-height:0;max-height:none;}
  .vge .vge-drop.is-lead.is-full .vge-drop-meta{flex:0 0 auto;}
}

/* ══════════════════════════════════════════════════════════════════
   THE ENGINE PICKER, TIGHTENED

   The sheet read well but spent its height on air: 190px heroes, cards
   that kept room for a second description line most of them never use,
   24px feature tiles, and 34px between shelves. Same look, less scroll:

     the two heroes come down to 132px, the feature glyphs to 18px, and
     the cards lose about a third of their height.

   A card keeps its second description line only when the text needs
   it. Rows still line up: cards in a row stretch to the tallest one,
   and the description takes up the slack, so every footer stays on
   the bottom edge.
   ══════════════════════════════════════════════════════════════════ */

/* ── the engine cards ── */
.vg-panel.is-sheet .vg-card{
  grid-template-rows:auto 1fr auto;
  padding:12px 13px 11px;gap:8px;border-radius:14px;
}
.vg-panel.is-sheet .vg-card-top{gap:10px;}
.vg-panel.is-sheet .vg-card-ico{width:32px;height:32px;border-radius:9px;}
.vg-panel.is-sheet .vg-card-ico svg{width:15px;height:15px;}
.vg-panel.is-sheet .vg-card .vg-item-name{font-size:14px;}
.vg-panel.is-sheet .vg-card .vg-card-by{font-size:9.5px;}
.vg-panel.is-sheet .vg-card .vg-item-desc{
  align-self:start;height:auto;max-height:2.9em;line-height:1.45;
}
.vg-panel.is-sheet .vg-card-on{width:20px;height:20px;}

/* the glyphs along the bottom: smaller tiles, finer marks */
.vg-panel.is-sheet .vg-card-foot{min-height:18px;}
.vg-panel.is-sheet .vg-card .vg-caps{gap:4px;}
.vg-panel.is-sheet .vg-cap.is-ico{width:18px;height:18px;border-radius:5px;}
.vg-panel.is-sheet .vg-cap.is-ico svg{width:10px;height:10px;}
.vg-panel.is-sheet .vg-card-spec{font-size:10.5px;}

/* ── the two recommended engines ── */
.vg-panel.is-sheet .vg-feat{gap:12px;}
.vg-panel.is-sheet .vg-feat-card{min-height:132px;padding:16px 18px;border-radius:16px;gap:4px;}
.vg-panel.is-sheet .vg-feat-name{font-size:18px;}
.vg-panel.is-sheet .vg-feat-desc{font-size:12.5px;}
.vg-panel.is-sheet .vg-feat-card.is-on::after{top:12px;right:12px;width:22px;height:22px;background-size:11px;}

/* ── the shelves ── */
.vg-panel.is-sheet .vg-list{gap:20px;}
.vg-panel.is-sheet .vg-group-h{margin:0 0 10px;}
.vg-panel.is-sheet .vg-group-ico{width:22px;height:22px;border-radius:7px;}
.vg-panel.is-sheet .vg-group-ico svg{width:12px;height:12px;}
.vg-panel.is-sheet .vg-group-g{gap:10px;}

/* ── head, search row and margins, on a desk ──
   Kept off the phone sheet, whose side padding is 16px and would not
   survive the -26px bleed the pinned search row uses here. */
@media (min-width:761px){
  .vg-panel.is-sheet .vg-panel-head{padding:20px 26px 8px;}
  .vg-sheet-title{gap:3px;}
  .vg-panel.is-sheet .vg-sheet-title h2{font-size:22px;}
  .vg-panel.is-sheet .vg-panel-body{padding:4px 26px 28px;}
  .vg-panel.is-sheet .vg-panel-h{margin:0 0 9px;}
  .vg-panel.is-sheet .vg-panel-h + *{margin-bottom:6px;}
  .vg-panel.is-sheet .vg-filters{top:-4px;margin:0 -26px 8px;padding:10px 26px;}
  .vg-panel.is-sheet .vg-search,
  .vg-panel.is-sheet .vg-select{height:40px;border-radius:12px;}
}

/* ── a phone keeps its own, smaller heroes ── */
@media (max-width:760px){
  .vg-panel.is-sheet .vg-feat-card{min-height:112px;padding:12px;border-radius:14px;}
  .vg-panel.is-sheet .vg-feat-name{font-size:15px;}
  .vg-panel.is-sheet .vg-feat-desc{font-size:11.5px;}
  .vg-panel.is-sheet .vg-card{padding:12px;}
}

/* EDIT VIDEO: THE LOOK ROW MATCHES CREATE VIDEO
   The fitted pass shrank this row on Edit Video only (a 36px thumbnail
   and 6px padding, 32px on short screens, 40px on tall ones), so the same
   row and the same Change button read smaller than on Create Video.
   Both pages now use Create Video's row at every height. */
.vge .vg-look{padding:9px 10px 9px 9px;}
.vge .vg-look img{width:44px;height:44px;border-radius:10px;}

/* TEMPLATES: THE ROSTER STAYS INSIDE THE PANEL
   js/templates.js measures the room between the doors and the top of the
   column and hands it over as --tpl-sheet-room. The sheet never grows past
   it and the faces scroll inside; a fade on the bottom edge says there are
   more until the last row is in view. Flex only while shown, so the hidden
   attribute still hides it. */
.tpl-cast-sheet:not([hidden]){
  display:flex;flex-direction:column;
  max-height:var(--tpl-sheet-room,none);
}
.tpl-cast-sheet-top{flex:none;}
.tpl-cast-sheet .tpl-cast-row{flex:1 1 auto;min-height:0;}
.tpl-cast-sheet.has-more .tpl-cast-row{
  -webkit-mask-image:linear-gradient(180deg,#000 calc(100% - 44px),transparent);
  mask-image:linear-gradient(180deg,#000 calc(100% - 44px),transparent);
}

/* GENERATE: A TILE THAT IS STILL BEING MADE
   From the press of Generate there is a tile where the picture will be,
   turning, one for each frame asked for. js/wall.js puts them up, fills
   each one as its picture lands, and takes down whatever is left over
   when the run ends. No pointer events: there is nothing to open yet. */
.gw-cell.is-pending{
  pointer-events:none;cursor:default;
  display:grid;place-items:center;
  background:linear-gradient(180deg,var(--a-chip),var(--a-panel));
}
.gw-cell.is-pending::before{
  content:"";position:absolute;inset:0;
  background:linear-gradient(105deg,transparent 40%,
    color-mix(in srgb,var(--a-ink) 7%,transparent) 50%,transparent 60%);
  transform:translateX(-60%);
  animation:gwWait 1.7s linear infinite;
}
@keyframes gwWait{to{transform:translateX(60%);}}
.gw-spin{
  position:relative;z-index:1;
  width:34px;height:34px;border-radius:50%;
  border:2px solid color-mix(in srgb,var(--a-ink) 16%,transparent);
  border-top-color:var(--a-ink);
  animation:gwSpin .9s linear infinite;
}
@keyframes gwSpin{to{transform:rotate(360deg);}}
@media (prefers-reduced-motion:reduce){
  .gw-cell.is-pending::before{animation:none;}
  .gw-spin{animation:none;border-top-color:color-mix(in srgb,var(--a-ink) 16%,transparent);}
}

/* THE COMPOSER, WITH PICTURES IN IT
   The reference strip shared its line with the prompt and wrapped into
   three rows once there were more than three pictures, leaving the prompt
   a narrow column beside a block of thumbnails. With something in it the
   strip now takes its own line above the prompt: one row, scrolled
   sideways when it is long, with a hairline under it so the bar still
   reads as one thing. Empty, it keeps sharing the line with the prompt,
   because a lone + on a row of its own is a wasted row. */
.gc:has(.gc-ref-item) .gc-top{flex-direction:column;align-items:stretch;gap:0;}
.gc:has(.gc-ref-item) .gc-refs{
  max-width:none;flex-wrap:nowrap;gap:8px;
  padding:1px 2px 10px;margin-bottom:9px;
  border-bottom:1px solid var(--a-line);
  overflow-x:auto;overflow-y:hidden;
  scrollbar-width:none;-ms-overflow-style:none;
}
.gc:has(.gc-ref-item) .gc-refs::-webkit-scrollbar{display:none;}
/* `flex:1` is right while the prompt shares a row with the tray — it is
   the width it should take. The moment a reference arrives the row turns
   into a column and that same declaration becomes a HEIGHT of basis 0,
   which threw away the height the prompt had grown to: a ten-line brief
   collapsed to 46px and the text you were about to send was invisible.
   In the column it sizes itself, and it never opens shorter than four
   lines, so there is always prompt on screen to read. */
.gc:has(.gc-ref-item) .gc-input{
  flex:0 0 auto;
  padding:0 4px;min-height:92px;
}
.gc .gc-ref{box-shadow:inset 0 0 0 1px var(--a-line);}
.gc .gc-ref-item img{transition:transform .35s var(--e-out);}
.gc .gc-ref-item:hover img{transform:scale(1.05);}

/* THE FRAME WINDOW: WHAT MADE THE PICTURE, IN ONE BOX
   The prompt sits in a card of its own with the reference pictures above
   it, because the pictures handed to the engine are as much of the record
   as the words are. A long prompt is clamped to nine lines with See all
   under it, and Copy sits in the section heading. */
.lb-promptbox{
  padding:12px;border-radius:14px;
  background:var(--vz-chip,var(--wash));
  box-shadow:inset 0 0 0 1px var(--vz-line,var(--line));
}
.lb-refs{display:flex;flex-wrap:wrap;gap:6px;padding-bottom:11px;}
.lb-ref{
  width:52px;height:52px;border-radius:10px;overflow:hidden;flex:0 0 auto;
  background:var(--vz-bg,var(--wash));
  box-shadow:inset 0 0 0 1px var(--vz-line,var(--line));
}
.lb-ref img{width:100%;height:100%;object-fit:cover;display:block;}
.lb-ref.is-gone{display:none;}
.lb-promptbox .lb-prompt{
  display:-webkit-box;-webkit-line-clamp:9;-webkit-box-orient:vertical;overflow:hidden;
  white-space:pre-wrap;font-size:13.5px;line-height:1.6;
}
.lb-promptbox .lb-prompt.is-open{display:block;-webkit-line-clamp:unset;}
.lb-more{
  margin-top:9px;padding:0;border:0;background:none;cursor:pointer;
  font-size:12.5px;font-weight:500;letter-spacing:-.005em;
  color:var(--vz-muted,var(--ink-mute));
  transition:color .18s var(--ease);
}
.lb-more:hover{color:var(--vz-text,var(--ink-strong));}
.lb-more[hidden]{display:none;}

/* ══════════════════════════════════════════════════════════════════
   THE FRAME WINDOW, REDRAWN

   The panel read as a stack: a filename in 25px, a label, a card, a list
   of six rows and then seven buttons of four different weights, each one
   as loud as the last. Nothing in it said what mattered.

   It now reads top to bottom in one voice. The engine is the title and
   the file name steps down to the line beneath it. Section headings are
   small capitals with a rule running out to the edge. The prompt and the
   details each sit in a quiet card on the sunk ground, with the long
   prompt fading out rather than being cut mid-line. And the buttons find
   their order: one solid thing to do, two beside it, then a row of quiet
   tools that say what they are on hover.

   Scoped to [data-app] so it outranks the themed rules further up, and
   written against the shared .lb- classes so the Assets window is
   redrawn with it rather than left behind.
   ══════════════════════════════════════════════════════════════════ */

[data-app] .lb-panel{
  background:var(--a-panel);
  box-shadow:inset 1px 0 0 var(--a-line);
}

/* ── the head ── */
[data-app] .lb-head{padding:22px 24px 16px;border-bottom:1px solid var(--a-line);}
[data-app] .lb-kicker{
  display:flex;align-items:center;gap:7px;
  font-size:9.5px;letter-spacing:.2em;color:var(--a-mute);
}
[data-app] .lb-kicker i{
  width:5px;height:5px;border-radius:50%;
  background:var(--a-ink);opacity:.7;
}
[data-app] .lb-h{
  padding-top:9px;
  font-size:18px;font-weight:600;letter-spacing:-.02em;line-height:1.25;
  color:var(--a-ink);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
[data-app] .lb-sub{
  padding-top:4px;font-size:11.5px;line-height:1.5;color:var(--a-mute);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
[data-app] .lb-x{
  top:20px;right:20px;width:30px;height:30px;
  color:var(--a-mute);background:var(--a-chip);
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:color .2s var(--e-out),background-color .2s var(--e-out),
             transform .35s cubic-bezier(.16,1,.3,1);
}
[data-app] .lb-x:hover{color:var(--a-ink);background:var(--a-chip-2);transform:rotate(90deg);}

/* ── the body ── */
[data-app] .lb-scroll{padding:20px 24px 10px;scrollbar-width:thin;}
[data-app] .lb-sec{padding-bottom:22px;}
[data-app] .lb-sec-h{
  gap:12px;padding-bottom:11px;
  font-size:9.5px;letter-spacing:.2em;color:var(--a-mute);
}
/* the rule runs out to the edge, so a heading reads as a shelf label */
[data-app] .lb-sec-h > span{flex:0 0 auto;}
[data-app] .lb-sec-h::after{
  content:"";order:1;flex:1 1 auto;height:1px;
  background:linear-gradient(90deg,var(--a-line),transparent);
}
[data-app] .lb-sec-h .lb-copy{order:2;}

[data-app] .lb-copy{
  display:inline-flex;align-items:center;gap:6px;flex:0 0 auto;
  height:27px;padding:0 11px;border-radius:9px;cursor:pointer;
  font-size:11px;font-weight:500;letter-spacing:0;text-transform:none;
  color:var(--a-mute);background:var(--a-chip);
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:color .18s var(--e-out),background-color .18s var(--e-out);
}
[data-app] .lb-copy svg{width:12px;height:12px;}
[data-app] .lb-copy:hover{color:var(--a-ink);background:var(--a-chip-2);}

/* the prompt, with what went into it on top */
[data-app] .lb-promptbox{
  padding:14px;border-radius:14px;
  background:var(--a-sunk);
  box-shadow:inset 0 0 0 1px var(--a-line);
}
[data-app] .lb-refs{gap:7px;padding-bottom:12px;}
[data-app] .lb-ref{
  width:46px;height:46px;border-radius:11px;
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:transform .35s var(--e-out);
}
[data-app] .lb-ref:hover{transform:translateY(-2px);}
[data-app] .lb-promptbox .lb-prompt{
  font-size:13px;line-height:1.7;
  color:color-mix(in srgb,var(--a-ink) 88%,transparent);
}
/* A clamp that fades out instead of cutting a line in half — and only on a
   prompt that is really being cut short. On one that fits, the fade just
   dimmed its last line for no reason. */
[data-app] .lb-promptbox .lb-prompt.is-clamped:not(.is-open){
  -webkit-mask-image:linear-gradient(180deg,#000 calc(100% - 26px),transparent);
  mask-image:linear-gradient(180deg,#000 calc(100% - 26px),transparent);
}
[data-app] .lb-more{margin-top:10px;font-size:11.5px;color:var(--a-mute);}
[data-app] .lb-more:hover{color:var(--a-ink);}

/* the details, as one quiet card */
[data-app] .lb-rows{
  padding:2px 14px;border-radius:14px;
  background:var(--a-sunk);
  box-shadow:inset 0 0 0 1px var(--a-line);
}
[data-app] .lb-rows > div{
  gap:16px;padding:10px 0;
  border-top:1px solid color-mix(in srgb,var(--a-line) 65%,transparent);
}
[data-app] .lb-rows dt{font-size:11.5px;color:var(--a-mute);}
[data-app] .lb-rows dd{font-size:12.5px;font-weight:500;color:var(--a-ink);}
[data-app] .lb-flag{font-size:11.5px;color:var(--a-mute);}

/* ── the actions: one thing to do, two beside it, then the quiet tools ── */
[data-app] .lb-actions{
  position:sticky;bottom:0;z-index:2;
  display:flex;flex-direction:column;gap:9px;
  padding:14px 24px 18px;
  border-top:1px solid var(--a-line);
  background:linear-gradient(180deg,
    color-mix(in srgb,var(--a-panel) 45%,transparent),var(--a-panel) 24%);
}
[data-app] .lb-actions .lb-primary{
  width:100%;height:46px;border-radius:13px;
  font-size:13.5px;font-weight:600;letter-spacing:-.01em;
}
[data-app] .lb-duo,[data-app] .lb-pair{display:grid;grid-template-columns:1fr 1fr;gap:9px;}
[data-app] .lb-actions .lb-btn{
  height:42px;border-radius:12px;
  font-size:12.5px;font-weight:500;
  color:var(--a-ink);background:var(--a-chip);
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:background-color .2s var(--e-out),box-shadow .2s var(--e-out),
             transform .3s var(--e-out);
}
[data-app] .lb-actions .lb-btn:hover{
  background:var(--a-chip-2);box-shadow:inset 0 0 0 1px var(--a-mute);
  transform:translateY(-1px);
}
[data-app] .lb-ic svg{width:14px;height:14px;}

/* six tools on a generated frame, four on a video in Assets: the row
   divides itself by however many there are rather than by a fixed count */
[data-app] .lb-tools{display:grid;grid-auto-flow:column;grid-auto-columns:minmax(0,1fr);gap:7px;}
[data-app] .lb-mini{display:grid;grid-template-columns:repeat(2,1fr);gap:7px;}
[data-app] .lb-tools .lb-icon,
[data-app] .lb-mini .lb-icon{
  width:auto;height:38px;border-radius:11px;
  color:var(--a-mute);background:var(--a-chip);
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:color .18s var(--e-out),background-color .18s var(--e-out);
}
[data-app] .lb-tools .lb-icon:hover,
[data-app] .lb-mini .lb-icon:hover{color:var(--a-ink);background:var(--a-chip-2);}
[data-app] .lb-tools .lb-icon.is-on{color:var(--a-ink);}
[data-app] .lb-tools .lb-icon svg,
[data-app] .lb-mini .lb-icon svg{width:15px;height:15px;}

/* Assets still builds the older stack of ghost links; same manners */
[data-app] .lb-ghosts{display:flex;flex-wrap:wrap;gap:7px;}
[data-app] .lb-ghost{
  flex:1 1 auto;height:34px;padding:0 12px;border-radius:10px;
  font-size:11.5px;color:var(--a-mute);background:transparent;
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:color .18s var(--e-out),background-color .18s var(--e-out);
}
[data-app] .lb-ghost:hover{color:var(--a-ink);background:var(--a-chip);}

/* ── a phone ──
   Stacked, the panel gets what the picture leaves, and that was not much:
   the head and the buttons ate it and the prompt was left with one line
   showing. So the panel takes a larger share, every control loses a few
   pixels of height, and the six tools stay on one line — two rows of
   three cost 45px that the reading needed more. */
@media (max-width:820px){
  [data-app] .lb-panel{max-height:56vh;}
  [data-app] .lb-head{padding:16px 18px 12px;}
  [data-app] .lb-scroll{padding:14px 18px 6px;}
  [data-app] .lb-sec{padding-bottom:18px;}
  [data-app] .lb-actions{gap:8px;padding:12px 18px 16px;}
  [data-app] .lb-actions .lb-primary{height:44px;}
  [data-app] .lb-actions .lb-btn{height:40px;}
  [data-app] .lb-tools .lb-icon,
  [data-app] .lb-mini .lb-icon{height:36px;}
}

/* ══════════════════════════════════════════════════════════════════
   AN ENGINE THAT TAKES NO PICTURES

   Ten of the twenty-six read a prompt and nothing else. The bar used to
   accept a reference for any of them and admit afterwards that it had
   been dropped — a correction arriving after the credits were spent.
   Now the + says no while that engine is chosen, and any reference
   already in the tray sits greyed out rather than looking live.
   ══════════════════════════════════════════════════════════════════ */
.gc-ref-add.is-off,
.cmp-ref-add.is-off{
  cursor:not-allowed;opacity:.42;
  background:transparent;
  box-shadow:inset 0 0 0 1px var(--a-line,var(--line));
}
.gc-ref-add.is-off:hover,
.cmp-ref-add.is-off:hover{
  background:transparent;color:var(--a-mute,var(--ink-mute));
}
/* references held for an engine that cannot read them: still there, and
   plainly not in play */
.gc-refs.is-off .gc-ref-item,
.cmp-refs.is-off .cmp-ref-item{opacity:.34;filter:grayscale(1);}

/* the picker, while a reference is in the tray */
.cmp-mrow.is-norefs{opacity:.5;}
.cmp-mrow.is-norefs:hover,.cmp-mrow.is-norefs:focus-visible{opacity:.72;}
.cmp-mrow.is-norefs .cmp-mrow-ic{background:transparent;box-shadow:inset 0 0 0 1px var(--a-line);}
.cmp-mrow.is-norefs .cmp-mrow-tick{opacity:1;color:var(--a-mute);}

/* The line above the reference thumbnails. A row of small pictures is
   easy to read past, and "was a reference used here" is a question the
   panel should answer in words as well as in pictures. */
[data-app] .lb-refs-h{
  padding-bottom:8px;
  font-size:9.5px;letter-spacing:.2em;text-transform:uppercase;
  color:var(--a-mute);
}

/* ══════════════════════════════════════════════════════════════════
   THE ROSTER LEAVES THE WAY IT ARRIVED

   The sheet springs open over the doors and used to vanish on the frame
   you picked a face — the roster was there, and then it was not, with
   nothing to say which face had been chosen or where the choice went.
   Now the pick confirms itself, the rest of the roster steps back, and
   the sheet settles down onto the door it belongs to. Out is quicker
   than in and accelerates away: leaving should not ask for attention.
   ══════════════════════════════════════════════════════════════════ */
@keyframes tplSheetOut{
  from{opacity:1;transform:none;}
  to{opacity:0;transform:translateY(9px) scale(.965);}
}
.tpl-cast-sheet.is-closing{
  animation:tplSheetOut .3s cubic-bezier(.4,0,1,1) both;
  pointer-events:none;
}
/* the faces that were not chosen stand down first. `animation:none` is
   load-bearing: each face is dealt in with `tplFace … both`, and a filled
   animation holds its own opacity against any declaration here — the
   faces simply stayed lit until the whole sheet went. */
.tpl-cast-sheet.is-closing .tpl-cast-pick{
  animation:none;
  opacity:.3;
  transition:opacity .18s var(--e-out);
}
.tpl-cast-sheet.is-closing .tpl-cast-pick.is-chosen{opacity:1;}

/* and the one that was gives a single nod */
@keyframes tplPicked{
  0%{transform:none;}
  40%{transform:scale(1.08);}
  100%{transform:scale(1);}
}
.tpl-cast-pick.is-chosen img{
  box-shadow:inset 0 0 0 2px var(--a-ink);
  animation:tplPicked .34s cubic-bezier(.2,1.2,.36,1) both;
}

@media (prefers-reduced-motion: reduce){
  .tpl-cast-sheet.is-closing,
  .tpl-cast-pick.is-chosen img{animation:none;}
}

/* The result and the template share one stage, and in the studio shell
   both are drawn whole inside it — so with the template still showing,
   a result of a different shape appeared as a band across its middle
   with the original above and below. The template steps aside while its
   answer is up, and comes back for the next run. */
[data-app] .tpl-modal-ref.has-out [data-tpl-modal-img]{
  opacity:0;
  transition:opacity .3s var(--e-out);
}
.tpl-modal-ref.has-out [data-tpl-modal-img]{opacity:0;}

/* ══════════════════════════════════════════════════════════════════
   TEMPLATES: THE WAIT, AND WHAT COMES BACK

   Pressing Generate used to black the frame out behind a spinner, hold
   there with nothing to say for as long as it took, and then swap the
   picture in on a plain fade. Three moments, none of them designed.

   Now: the frame being copied stays on screen and steps back, a light
   passes down it while the work happens, and the engine's name and the
   seconds it has been going sit under the ring — a wait that says
   nothing reads as a hang. The result opens out from the middle rather
   than fading over the top, with one pass of light across it as it
   lands. And underneath, four things to do with it, dealt in.
   ══════════════════════════════════════════════════════════════════ */
.tpl-modal-busy{
  gap:0;overflow:hidden;
  background:linear-gradient(180deg,rgba(8,8,9,.58),rgba(8,8,9,.76));
  backdrop-filter:blur(7px) saturate(.72);
  -webkit-backdrop-filter:blur(7px) saturate(.72);
  animation:tplBusyIn .26s var(--e-out) both;
}
@keyframes tplBusyIn{from{opacity:0;}to{opacity:1;}}

/* the light that passes down the frame while it is being worked on */
.tpl-busy-sweep{
  position:absolute;left:0;right:0;top:-38%;height:38%;
  background:linear-gradient(180deg,transparent,rgba(255,255,255,.11),transparent);
  animation:tplSweep 2.6s cubic-bezier(.45,0,.55,1) infinite;
}
@keyframes tplSweep{
  0%{transform:translateY(0);opacity:0;}
  12%{opacity:1;}
  84%{opacity:1;}
  100%{transform:translateY(365%);opacity:0;}
}

.tpl-busy-mid{
  position:relative;z-index:1;
  display:flex;flex-direction:column;align-items:center;gap:12px;
}
.tpl-busy-ring{
  width:30px;height:30px;border-radius:50%;
  border:2px solid rgba(255,255,255,.16);border-top-color:#fff;
  animation:upSpin .85s linear infinite;
}
.tpl-busy-mid b{font-size:14px;font-weight:600;letter-spacing:-.01em;}
.tpl-busy-mid em{
  font-style:normal;font-size:11.5px;font-weight:500;
  letter-spacing:.01em;color:rgba(255,255,255,.6);
  font-variant-numeric:tabular-nums;
}

/* and a line at the foot of the stage, so the wait has a pulse */
.tpl-busy-bar{
  position:absolute;left:0;right:0;bottom:0;height:2px;
  background:rgba(255,255,255,.12);overflow:hidden;
}
.tpl-busy-bar i{
  position:absolute;top:0;bottom:0;left:0;width:36%;
  background:linear-gradient(90deg,transparent,rgba(255,255,255,.95),transparent);
  animation:tplBar 1.5s cubic-bezier(.45,0,.55,1) infinite;
}
@keyframes tplBar{from{transform:translateX(-110%);}to{transform:translateX(320%);}}

/* the frame arriving: opened out from the middle, not faded over the top */
.tpl-modal-out{animation:tplReveal .6s cubic-bezier(.22,1,.36,1) both;}
@keyframes tplReveal{
  from{opacity:0;transform:scale(1.035);clip-path:inset(13% 0 13% 0);}
  to{opacity:1;transform:none;clip-path:inset(0 0 0 0);}
}
/* one pass of light as it lands, and then never again */
/* `is-fresh` is added with the frame and taken off a second and a half
   later by js/templates.js. Without it this band lived on the picture for
   as long as the picture did: an animation that never runs — reduced
   motion, a background tab, a finished run with `both` fill — leaves its
   element painted exactly where it stood, which here is a bright stripe
   down the middle of the frame you just made. It cannot outlive the
   moment if it is not in the document. */
.tpl-modal-ref.has-out.is-fresh::before{
  content:"";position:absolute;inset:0;z-index:3;pointer-events:none;
  background:linear-gradient(105deg,transparent 38%,rgba(255,255,255,.15) 50%,transparent 62%);
  animation:tplSheen .95s .2s cubic-bezier(.4,0,.2,1) both;
}
@keyframes tplSheen{from{transform:translateX(-120%);}to{transform:translateX(120%);}}

/* what to do with it: two by two, dealt in rather than appearing */
.tpl-done{
  display:grid;grid-template-columns:1fr 1fr;gap:8px;padding-top:12px;
}
.tpl-done-btn{
  display:flex;align-items:center;justify-content:center;gap:8px;
  padding:11px 12px;border-radius:12px;
  animation:tplDeal .44s var(--e-out) both;
}
.tpl-done-btn svg{width:14px;height:14px;flex:0 0 auto;}
.tpl-done-btn:nth-child(1){animation-delay:.02s;}
.tpl-done-btn:nth-child(2){animation-delay:.07s;}
.tpl-done-btn:nth-child(3){animation-delay:.12s;}
.tpl-done-btn:nth-child(4){animation-delay:.17s;}
@keyframes tplDeal{from{opacity:0;transform:translateY(7px);}to{opacity:1;transform:none;}}

@media (prefers-reduced-motion: reduce){
  .tpl-busy-sweep,.tpl-busy-bar i{animation:none;}
  /* not `animation:none` — that would leave the band standing in the
     middle of the frame. The pass of light simply does not happen. */
  .tpl-modal-ref.has-out.is-fresh::before{content:none;}
  .tpl-modal-out,.tpl-done-btn,.tpl-ver{animation:none;opacity:1;transform:none;clip-path:none;}
}

/* ══════════════════════════════════════════════════════════════════
   TEMPLATES: TRYING AGAIN WITHOUT STARTING OVER

   A frame comes back and it is almost right — the lipstick too dark,
   the hand too high. The only answer used to be another roll of the
   dice from the template, which changes everything including the parts
   that were already right.

   So: say what to change, and the frame on the stage goes back in as
   the reference with instructions to keep everything else. Each attempt
   is kept, the template first, and one click puts any of them back on
   the stage — a conversation you can scroll back through, rather than a
   series of losses.
   ══════════════════════════════════════════════════════════════════ */
.tpl-refine{
  padding-top:14px;margin-top:14px;
  border-top:1px solid var(--a-line);
  animation:tplDeal .4s var(--e-out) both;
}
.tpl-refine[hidden]{display:none;}
.tpl-refine.is-working{opacity:.45;pointer-events:none;}

/* the versions, template first */
.tpl-vers{
  display:flex;gap:7px;padding-bottom:11px;
  overflow-x:auto;scrollbar-width:none;-ms-overflow-style:none;
}
.tpl-vers::-webkit-scrollbar{display:none;}
.tpl-ver{
  position:relative;flex:0 0 auto;width:46px;height:46px;
  border-radius:11px;overflow:hidden;cursor:pointer;
  background:var(--a-sunk);
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:box-shadow .2s var(--e-out),transform .3s var(--e-out);
  animation:tplDeal .34s var(--e-out) both;
}
.tpl-ver img{width:100%;height:100%;object-fit:cover;display:block;}
.tpl-ver b{
  position:absolute;left:0;right:0;bottom:0;
  padding:7px 3px 2px;
  font-size:8.5px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;
  color:#fff;text-align:center;
  background:linear-gradient(180deg,transparent,rgba(0,0,0,.75));
}
.tpl-ver:hover{transform:translateY(-2px);}
.tpl-ver.is-on{box-shadow:inset 0 0 0 2px var(--a-ink);}
.tpl-ver.is-tpl img{opacity:.66;}
.tpl-ver.is-tpl.is-on img{opacity:1;}

/* what to change */
.tpl-refine-row{display:flex;gap:8px;}
.tpl-refine-in{
  flex:1;min-width:0;height:42px;padding:0 13px;
  border:0;border-radius:12px;
  font-family:inherit;font-size:13px;letter-spacing:-.005em;
  color:var(--a-ink);background:var(--a-sunk);
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:box-shadow .2s var(--e-out);
}
.tpl-refine-in::placeholder{color:var(--a-mute);}
.tpl-refine-in:focus{outline:none;box-shadow:inset 0 0 0 1.5px var(--a-mute);}
.tpl-refine-go{
  flex:0 0 auto;display:flex;align-items:center;gap:8px;
  height:42px;padding:0 17px;border-radius:12px;cursor:pointer;
  font-size:12.5px;font-weight:600;letter-spacing:-.01em;
  color:var(--a-btn-ink);background:var(--a-btn);
  transition:opacity .2s var(--e-out),transform .2s var(--e-out);
}
.tpl-refine-go svg{width:15px;height:15px;}
.tpl-refine-go:hover{opacity:.9;transform:translateY(-1px);}

/* The foot fades into the panel at its top edge, and the fade used to be
   30% of its own height. That was fine while it held one row; with the
   refine line and four buttons in it, a third of the foot is 60px of
   see-through and the scrolled prompt showed straight through the words
   on top of it. A fixed 22px of fade instead — soft edge, solid foot,
   whatever the foot grows to. */
@media (min-width:861px){
  [data-app] .tpl-modal-foot{
    background:linear-gradient(180deg,transparent 0,var(--a-panel) 22px);
  }
}
/* Stacked, the foot is a bar across the bottom of the sheet rather than
   something the column fades into, so it is solid to its own top edge —
   a fade there let the title of the panel show through the words on it. */
@media (max-width:860px){
  [data-app] .tpl-modal-foot{
    background:var(--a-panel);
    border-top:1px solid var(--a-line);
  }
}

/* The stage is cut to the shape of the frame in it. How tall this window
   is was settled by the panel on the right; what was left for the
   picture was a fixed fraction of the width, so a portrait floated
   between two bands of empty ground in a window opened to look at it.
   js/templates.js measures the frame and sets --tpl-stage; the box is
   allowed to be wider so there is room for that to mean something. */
/* Scoped to the wide layout: stacked, the sheet is full-bleed and a max
   width here would put a 20px margin around it that was never there. */
@media (min-width:861px){
  [data-app] .tpl-modal-box{max-width:min(1460px,calc(100vw - 40px));}
  [data-app] .tpl-modal-grid{
    grid-template-columns:var(--tpl-stage,minmax(0,.92fr)) minmax(0,1fr);
  }
}

/* The window is as tall as its panel needs and no taller. Forcing it to
   90vh made the frame as large as the screen allowed, which sounds like
   what you want until you see it: the picture became the whole left half
   of the display, and the panel — three short steps — was left with a
   hole of empty ground under the casting row reaching down to its
   buttons. A window the size of what is in it, with the picture cut to
   fill its own half of it, is the better of the two.

   But it still may not grow past the screen. Once a run adds a refine
   line and four buttons the panel can want more than 90vh, and the box
   scrolling as a whole took the picture with it — a frame taller than
   the display, in a window opened to look at it. So the box stops at
   90vh and the column of controls takes the scrollbar; the stage is
   never taller than what is actually on screen. */
@media (min-width:861px){
  [data-app] .tpl-modal-box{display:flex;flex-direction:column;overflow:hidden;}
  [data-app] .tpl-modal-grid{
    flex:1 1 auto;min-height:0;grid-template-rows:minmax(0,1fr);
  }
  [data-app] .tpl-modal-side{overflow-y:auto;min-height:0;scrollbar-width:thin;}
}

/* ══════════════════════════════════════════════════════════════════
   HOW LARGE THE FRAMES ARE HUNG

   Six across is a contact sheet you scan for the one that worked; two
   across is a print you look at. Which one you want changes a dozen
   times an hour, so it is a slider rather than a decision made once in
   a stylesheet. It sits at the right edge, quiet until a hand goes near
   it — a control at full strength beside forty photographs is one more
   thing competing with them.
   ══════════════════════════════════════════════════════════════════ */
/* Down in the corner beside the composer, not up the right-hand edge.
   Standing there it sat exactly where a frame puts its own row of
   buttons — heart, download, recreate — on every tile in the last
   column, so reaching for one meant reaching through the other. The
   bottom strip is chrome already; nothing on the wall lives there. */
.gw-zoom{
  position:fixed;right:16px;bottom:30px;
  z-index:30;display:flex;flex-direction:row;align-items:center;gap:9px;
  padding:7px 11px;border-radius:99px;
  background:color-mix(in srgb,var(--a-panel) 74%,transparent);
  backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);
  box-shadow:inset 0 0 0 1px var(--a-line),0 18px 40px -24px rgba(0,0,0,.85);
  opacity:.4;
  transition:opacity .25s var(--e-out);
}
.gw-zoom:hover,.gw-zoom:focus-within,.gw-zoom.is-live{opacity:1;}

.gw-zoom-b{
  display:grid;place-items:center;width:20px;height:20px;cursor:pointer;
  color:var(--a-mute);border-radius:6px;
  transition:color .16s var(--e-out);
}
.gw-zoom-b:hover{color:var(--a-ink);}
.gw-zoom-b svg{width:13px;height:13px;}

.gw-zoom-track{
  position:relative;width:96px;height:4px;border-radius:99px;
  background:var(--a-chip-2);cursor:ew-resize;touch-action:none;
}
/* The line is 4px because that is how thin it should look. Four pixels
   is not something a hand can catch, so the part that answers the mouse
   is the height of the pill — invisible, and the only one you can miss
   is the one you can see. */
.gw-zoom-track::before{content:"";position:absolute;inset:-13px -7px;}
.gw-zoom-track:focus-visible{outline:2px solid var(--a-mute);outline-offset:5px;}
.gw-zoom-fill{
  position:absolute;left:0;top:0;bottom:0;width:0;border-radius:99px;
  background:var(--a-mute);
}
.gw-zoom-knob{
  position:absolute;top:50%;left:0;width:14px;height:14px;border-radius:50%;
  transform:translate(-50%,-50%);
  background:var(--a-ink);
  box-shadow:0 2px 7px rgba(0,0,0,.55);
  transition:transform .18s var(--e-out);
}
.gw-zoom.is-live .gw-zoom-knob{transform:translate(-50%,-50%) scale(1.15);}

/* The composer is 1120px wide and centred, so the room beside it is
   (screen − 1120) ÷ 2. Under about 1410px there is not enough of it for
   this without the two overlapping, and a control sitting on top of the
   prompt box is worse than no control — the wall keeps whatever size it
   was last given instead. */
@media (max-width:1409px){.gw-zoom{display:none;}}

/* ══════════════════════════════════════════════════════════════════
   EDIT VIDEO: QUALITY OPENS WHERE IT IS ASKED

   Picking a resolution used to replace the whole right-hand side of the
   page with an Output page: the clip you were working on left the
   screen so you could choose between two numbers. It opens over the row
   that asked for it now, and closes on a pick, a click elsewhere or
   Escape.
   ══════════════════════════════════════════════════════════════════ */
.vg.vge{position:relative;}
.vg-qpop{
  position:absolute;left:0;right:0;z-index:8;
  padding:12px;border-radius:15px;
  background:color-mix(in srgb,var(--a-panel) 94%,transparent);
  backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);
  box-shadow:
    inset 0 0 0 1px var(--a-line),
    inset 0 1px 0 rgba(255,255,255,.06),
    0 26px 54px -20px rgba(0,0,0,.9);
  transform-origin:50% 100%;
  animation:vgQPop .28s cubic-bezier(.2,1.2,.36,1) both;
}
.vg-qpop[hidden]{display:none;}
@keyframes vgQPop{
  from{opacity:0;transform:translateY(8px) scale(.97);}
  to{opacity:1;transform:none;}
}
.vg-qpop-h{
  display:block;padding:1px 3px 9px;
  font-size:11px;font-weight:600;letter-spacing:.07em;text-transform:uppercase;
  color:var(--a-mute);
}
.vg-qpop .vg-hint{padding-top:9px;margin:0;font-size:11.5px;color:var(--a-mute);}
/* the row that opened it reads as pressed in while it is open */
.vg-row.is-open{background:var(--a-chip-2);}

@media (prefers-reduced-motion: reduce){
  .vg-qpop{animation:none;}
}

/* ══════════════════════════════════════════════════════════════════
   RESIZE: GENERATING THE NEW SPACE

   Keeping the whole picture in a shape that does not fit it leaves a
   margin, and until now that margin could only be blurred, mirrored or
   painted flat — all of which are the photograph repeated, not the
   scene continued. This is the third option: the picture stays exactly
   as it is and only what was never photographed is invented.
   ══════════════════════════════════════════════════════════════════ */
.ut-fillai{padding-top:9px;}
.ut-fillai[hidden]{display:none;}
.ut-fillai-go{
  width:100%;
  color:var(--a-btn-ink,var(--white));
  background:var(--a-btn,var(--ink-strong));
  box-shadow:none;
}
.ut-fillai-go:hover{opacity:.9;}
/* Waiting on the size above. Held rather than hidden: a control that
   vanishes teaches nothing, and the line underneath says what it wants. */
.ut-fillai-go:disabled{opacity:.42;cursor:not-allowed;}
.ut-fillai-go:disabled:hover{opacity:.42;}
.ut-aiwait{
  display:block;padding-top:7px;
  font-style:normal;font-size:11px;line-height:1.45;
  color:var(--ink-mute);text-align:center;
}
.ut-aiwait[hidden]{display:none;}

/* One line under the chips, not a paragraph: it belongs to the chip
   that is pressed and changes with it. */
[data-ut-fillnote]{
  display:block;padding-top:8px;
  font-style:normal;font-size:11px;line-height:1.45;
  color:var(--ink-mute);
}

/* ══════════════════════════════════════════════════════════════════
   RESIZE: THE TWO CHOICES, DRAWN

   Both of these were system dropdowns. A dropdown suits a long list of
   equivalent values; it does not suit three operations that do entirely
   different things to a photograph, because it hides two of them until
   you go looking and then renders all three in the operating system's
   own font, in the middle of a page that looks nothing like it.
   ══════════════════════════════════════════════════════════════════ */
.ut-opts{display:flex;flex-direction:column;gap:7px;}
.ut-opt{
  display:flex;align-items:center;gap:11px;width:100%;
  padding:9px 11px;border-radius:12px;cursor:pointer;text-align:left;
  background:var(--white);
  box-shadow:inset 0 0 0 1px var(--line);
  transition:box-shadow .18s var(--ease),background-color .18s var(--ease);
}
.ut-opt:hover{background:var(--wash);}
.ut-opt.is-on{box-shadow:inset 0 0 0 1.5px var(--ink-strong);}
.ut-opt-ic{
  flex:0 0 auto;display:grid;place-items:center;width:34px;height:26px;
  color:var(--ink-mute);
}
.ut-opt.is-on .ut-opt-ic{color:var(--ink-strong);}
.ut-opt-ic svg{width:28px;height:22px;}
.ut-opt-t{display:block;min-width:0;}
.ut-opt-t b{
  display:block;font-size:12.5px;font-weight:600;letter-spacing:-.01em;
  color:var(--ink-strong);
}
.ut-opt-t em{
  display:block;padding-top:2px;font-style:normal;
  font-size:11px;line-height:1.4;color:var(--ink-mute);
}

/* The fill. A row of flexing chips in a 200px column squeezed each one
   under its own word — "Blu", "Mir", "G" — so they are a grid of two
   instead: every chip the same width, none of them shrinking, all six
   readable. */
.ut-fills{display:grid;grid-template-columns:1fr 1fr;gap:6px;}
.ut-fill{
  display:flex;align-items:center;justify-content:center;gap:5px;
  min-width:0;padding:8px 6px;border-radius:10px;cursor:pointer;
  font-size:12px;font-weight:500;color:var(--ink);white-space:nowrap;
  background:var(--white);
  box-shadow:inset 0 0 0 1px var(--line);
  transition:box-shadow .18s var(--ease),background-color .18s var(--ease),color .18s var(--ease);
}
.ut-fill:hover{background:var(--wash);}
.ut-fill svg{width:12px;height:12px;flex:0 0 auto;}
.ut-fill.is-on{
  color:var(--a-btn-ink,var(--white));
  background:var(--a-btn,var(--ink-strong));
  box-shadow:none;
}

/* The third way of meeting a shape: grow the picture rather than cut it
   or squash it. It carries its price on the card, because it is the one
   of the three that spends anything. */
.ut-opt.is-ai.is-on{
  box-shadow:inset 0 0 0 1.5px var(--ink-strong);
  background:var(--wash);
}
/* The price sits at the far end of the title line rather than after the
   words, where a narrow card wrapped it onto a line of its own. */
.ut-opt.is-ai .ut-opt-t b{
  display:flex;align-items:center;justify-content:space-between;gap:8px;
}
/* The price, said the way the rest of the studio says it: the star is
   what marks a number as credits, so the number can just be a number.
   "cr" was an abbreviation nobody had been taught. */
/* `.ut-opt-t em` sets every em in the card to display:block, and it is
   the more specific of the two — so the star and the number stacked one
   above the other inside the pill. Named through the card to win, and
   the inherited type reset with it. */
.ut-cost,
.ut-opt-t .ut-cost{
  flex:0 0 auto;
  display:inline-flex;align-items:center;gap:4px;white-space:nowrap;
  padding:2px 8px 2px 6px;border-radius:99px;
  font-style:normal;font-size:10.5px;font-weight:600;letter-spacing:.01em;
  line-height:1.4;
  color:var(--ink-mute);background:var(--wash);
  box-shadow:inset 0 0 0 1px var(--line);
}
.ut-opt-t .ut-cost{padding-top:2px;}
.ut-cost svg{width:9px;height:9px;opacity:.75;flex:0 0 auto;}
.ut-cost b,
.ut-opt-t .ut-cost b{
  display:inline;font-size:10.5px;font-weight:600;
  color:inherit;font-variant-numeric:tabular-nums;
}
.ut-opt.is-on .ut-cost{color:var(--ink-strong);}
.ut-opt.is-on .ut-cost svg{opacity:1;}

/* On the solid button the pill is a hole in the fill rather than a chip
   on top of it — a bordered box inside a button reads as two buttons. */
.ut-fillai-go .ut-cost{
  color:inherit;background:rgba(0,0,0,.09);box-shadow:none;
}
.ut-fillai-go .ut-cost svg{opacity:.85;}


/* ══════════════════════════════════════════════════════════════════
   THE ASSIST AGENT

   A panel you talk to, over the studio rather than beside it: you open
   it, use it, close it, and no tool underneath had to be rebuilt around
   a column that is shut most of the time.

   Two things it does not do. It does not bring its own palette — a chat
   panel arriving with somebody else's blues and somebody else's bubbles
   is another product embedded in yours. And it does not sit on top of
   the studio's own composer: while it is open that bar is hidden, since
   the two ask for the same thing and a Generate button underneath an
   assistant is a second way to do what you are already doing.
   ══════════════════════════════════════════════════════════════════ */

/* Beside Generate, as its quieter twin: outlined where that one is
   filled, the same height, the same corner radius, so the pair reads as
   two ways of asking for the same thing rather than as a button and an
   advertisement. */
.ag-gobtn{
  display:inline-flex;align-items:center;gap:8px;flex:none;
  /* the same 54 and the same 16 as Generate: side by side they are a
     pair, and a pair that differs by fourteen pixels of height is a
     mistake nobody can name but everybody sees. */
  height:54px;padding:0 22px;margin-left:auto;
  border:1px solid var(--a-line);border-radius:16px;cursor:pointer;
  /* font:600 14px/1 inherit was the bug. A family of `inherit` is not
     valid inside the font shorthand, so the whole declaration was
     dropped and the button fell back to the browser's own button font —
     which is why it looked like it came from another website. Every
     other control here sets font:inherit and then the size, and so does
     this one now. */
  font:inherit;font-size:14.5px;font-weight:600;line-height:1;
  letter-spacing:-.012em;
  color:var(--a-ink);background:transparent;
  transition:background-color .2s cubic-bezier(.2,.8,.2,1),
             border-color .2s cubic-bezier(.2,.8,.2,1),
             transform .2s cubic-bezier(.2,.8,.2,1);
}
.gc-bar .ag-gobtn + .gc-go{margin-left:8px;}
.ag-gobtn svg{width:14px;height:14px;flex:none;transition:transform .35s cubic-bezier(.2,.8,.2,1);}
.ag-gobtn:hover{background:var(--a-chip);border-color:var(--a-chip-2);transform:translateY(-1px);}
.ag-gobtn:hover svg{transform:rotate(90deg) scale(1.1);}
.ag-gobtn:active{transform:translateY(0) scale(.985);}
.ag-gobtn.is-on{color:var(--a-btn-ink);background:var(--a-btn);border-color:transparent;}
@media (max-width:860px){
  .ag-gobtn{margin-left:0;}
  .ag-gobtn span{display:none;}
  .ag-gobtn{padding:0 13px;}
}

/* The fallback, for any page with no studio bar. */
.ag-launch{
  position:fixed;right:18px;bottom:18px;z-index:241;
  display:inline-flex;align-items:center;gap:8px;
  padding:11px 16px 11px 13px;border:0;border-radius:999px;cursor:pointer;
  font:inherit;font-size:13.5px;font-weight:600;line-height:1;letter-spacing:-.01em;
  color:var(--a-btn-ink);background:var(--a-btn);
  box-shadow:0 14px 32px -16px rgba(0,0,0,.6);
  transition:transform .18s cubic-bezier(.2,.8,.2,1),opacity .18s;
}
.ag-launch svg{width:15px;height:15px;flex:none;}
.ag-launch:hover{transform:translateY(-2px);}
body.ag-on .ag-launch{opacity:0;pointer-events:none;}

/* The studio's own composer stands down while the panel is open. */
body.ag-on .gc,
body.ag-on .cmp{opacity:0;pointer-events:none;}
body.ag-on .gc{transform:translateY(14px);}
.gc,.cmp{transition:opacity .22s cubic-bezier(.2,.8,.2,1),transform .22s cubic-bezier(.2,.8,.2,1);}

.ag-panel{
  position:fixed;z-index:242;right:16px;bottom:16px;top:78px;width:412px;
  display:flex;flex-direction:column;overflow:hidden;
  border:1px solid var(--a-line);border-radius:22px;
  background:var(--a-panel);box-shadow:0 40px 90px -44px rgba(0,0,0,.75);
  animation:ag-in .24s cubic-bezier(.2,.8,.2,1) both;
}
.ag-panel[hidden]{display:none;}
@keyframes ag-in{from{opacity:0;transform:translateY(12px) scale(.99);}to{opacity:1;transform:none;}}
@media (prefers-reduced-motion:reduce){.ag-panel{animation:none;}}

.ag-head{
  display:flex;align-items:center;justify-content:space-between;gap:10px;
  padding:15px 12px 15px 18px;border-bottom:1px solid var(--a-line);
}
.ag-head b{font-size:13.5px;letter-spacing:.01em;color:var(--a-ink);}
.ag-headbtns{display:flex;gap:2px;}
.ag-icon{
  display:grid;place-items:center;width:31px;height:31px;
  border:0;border-radius:10px;cursor:pointer;
  color:var(--a-mute);background:transparent;transition:background .15s,color .15s;
}
.ag-icon svg{width:16px;height:16px;}
.ag-icon:hover{background:var(--a-chip);color:var(--a-ink);}

/* ── the conversation ── */
.ag-log{flex:1;min-height:0;overflow-y:auto;padding:18px 16px 4px;}
.ag-log::-webkit-scrollbar{width:8px;}
.ag-log::-webkit-scrollbar-thumb{background:var(--a-chip-2);border-radius:99px;}

.ag-turn{margin-bottom:20px;}
.ag-turn.is-me{display:flex;flex-direction:column;align-items:flex-end;gap:6px;}
.ag-msg{font-size:13px;line-height:1.5;}
.ag-msg.is-me{
  max-width:88%;padding:10px 15px;border-radius:18px 18px 5px 18px;
  color:var(--a-btn-ink);background:var(--a-btn);white-space:pre-wrap;
}
.ag-mine-refs{display:flex;gap:5px;}
.ag-mine-ref{
  width:52px;height:52px;object-fit:cover;
  border-radius:10px;border:1px solid var(--a-line);
}
.ag-turn.is-bot p{margin:0 0 9px;font-size:13px;line-height:1.55;color:var(--a-ink);}

/* ── what came back ── */
.ag-grid{display:grid;grid-template-columns:1fr 1fr;gap:7px;--ag-ar:1;margin-bottom:11px;}
.ag-tile{
  position:relative;aspect-ratio:var(--ag-ar,1);overflow:hidden;padding:0;
  border:0;border-radius:13px;cursor:pointer;
  background:var(--a-sunk);transition:transform .18s cubic-bezier(.2,.8,.2,1);
}
.ag-tile img{width:100%;height:100%;object-fit:cover;display:block;}
.ag-tile:hover{transform:scale(1.018);}
.ag-tile.is-wait{cursor:default;}
.ag-tile.is-wait::after{
  content:'';position:absolute;inset:0;
  background:linear-gradient(100deg,transparent 20%,var(--a-chip) 50%,transparent 80%);
  background-size:220% 100%;animation:ag-shine 1.5s linear infinite;
}
@keyframes ag-shine{from{background-position:180% 0;}to{background-position:-80% 0;}}
@media (prefers-reduced-motion:reduce){.ag-tile.is-wait::after{animation:none;}}

.ag-all{
  width:100%;margin-bottom:11px;padding:11px;
  border:1px solid var(--a-line);border-radius:999px;cursor:pointer;
  font-size:12.5px;font-weight:600;
  color:var(--a-ink);background:transparent;transition:background .15s;
}
.ag-all:hover{background:var(--a-chip);}
.ag-note{font-size:11px;color:var(--a-mute);}

/* The prompt it wrote, folded away. It is the work, and worth reading
   once — but not above every set of pictures forever. */
.ag-written{margin:0 0 9px;}
.ag-written summary{
  display:inline-block;padding:5px 11px;border-radius:999px;cursor:pointer;
  font-size:11px;color:var(--a-mute);background:var(--a-chip);
  list-style:none;
}
.ag-written summary::-webkit-details-marker{display:none;}
.ag-written summary:hover{color:var(--a-ink);}
.ag-written[open] summary{margin-bottom:7px;}
.ag-written p{
  margin:0;padding:10px 12px;
  border-left:2px solid var(--a-chip-2);border-radius:0 11px 11px 0;
  font-size:11.5px;line-height:1.55;color:var(--a-mute);background:var(--a-chip);
}

/* ── the empty panel ── */
.ag-hello{padding:6px 2px 10px;}
.ag-hello b{display:block;font-size:16px;letter-spacing:-.01em;color:var(--a-ink);}
.ag-hello p{margin:6px 0 16px;font-size:12.5px;line-height:1.5;color:var(--a-mute);}
.ag-seeds{display:flex;flex-direction:column;gap:7px;}
.ag-seed{
  padding:12px 14px;border:1px solid var(--a-line);border-radius:14px;cursor:pointer;
  font-size:12.5px;line-height:1.45;text-align:left;
  color:var(--a-ink);background:transparent;transition:background .15s,border-color .15s;
}
.ag-seed:hover{background:var(--a-chip);border-color:var(--a-chip-2);}

/* ── what it will run with ──
   A model is a name, a house and a price; a shape is a shape. Both were
   system dropdowns, which rendered three of the most consequential
   choices in the studio in the operating system's own font, inside a
   panel that looks nothing like it. */
.ag-set{padding:14px 16px 6px;border-top:1px solid var(--a-line);max-height:52vh;overflow-y:auto;}
.ag-set[hidden]{display:none;}
.ag-set::-webkit-scrollbar{width:8px;}
.ag-set::-webkit-scrollbar-thumb{background:var(--a-chip-2);border-radius:99px;}

.ag-lab{
  padding:12px 2px 8px;font-size:10px;font-weight:600;
  letter-spacing:.1em;text-transform:uppercase;color:var(--a-mute);
}
.ag-lab:first-child{padding-top:2px;}

.ag-star{width:10px;height:10px;flex:none;opacity:.75;}
.ag-price{
  display:inline-flex;align-items:center;gap:4px;flex:none;
  padding:5px 10px;border:1px solid var(--a-line);border-radius:999px;
  font-size:11px;font-weight:600;font-style:normal;font-variant-numeric:tabular-nums;
  color:var(--a-ink);background:var(--a-chip);
}

/* ── the model, as an object rather than a field ──
   Two lines of text and a number inside a dark rectangle is a form
   input. The mark on the left, the house set small and wide under the
   name, the price as a token and the caret in a well of its own are
   what make it read as the thing you have chosen — which is what it is,
   and the most consequential choice in the panel.

   The light that used to cross it on hover is gone. A sweep is a casino
   tell: it decorates a control rather than responding to one. What is
   left responds — the row lifts, the mark brightens, the well fills. */
.ag-pick{
  position:relative;display:flex;align-items:center;gap:12px;width:100%;
  padding:12px 12px 12px 13px;border:1px solid var(--a-line);border-radius:16px;
  cursor:pointer;text-align:left;color:var(--a-ink);
  background:linear-gradient(180deg,var(--a-chip),transparent) var(--a-sunk);
  box-shadow:inset 0 1px 0 color-mix(in srgb,var(--a-ink) 6%,transparent);
  transition:border-color .22s cubic-bezier(.2,.8,.2,1),
             transform .22s cubic-bezier(.2,.8,.2,1),
             box-shadow .22s cubic-bezier(.2,.8,.2,1);
}
.ag-pick:hover{
  border-color:var(--a-chip-2);transform:translateY(-1px);
  box-shadow:inset 0 1px 0 color-mix(in srgb,var(--a-ink) 9%,transparent),
             0 12px 26px -20px rgba(0,0,0,.95);
}
.ag-pick:active{transform:translateY(0) scale(.994);}
.ag-pick.is-open{border-color:var(--a-chip-2);}

/* The house, in one letter. */
.ag-mark{
  display:grid;place-items:center;width:36px;height:36px;flex:none;
  border-radius:11px;
  font-size:14px;font-weight:700;letter-spacing:-.02em;
  color:var(--a-ink);background:var(--a-chip-2);
  box-shadow:inset 0 1px 0 color-mix(in srgb,var(--a-ink) 10%,transparent);
  transition:background-color .22s,transform .22s cubic-bezier(.2,.8,.2,1);
}
.ag-pick:hover .ag-mark{transform:scale(1.04);}
.ag-mark.is-sm{
  width:26px;height:26px;border-radius:8px;font-size:11px;
  color:var(--a-mute);background:var(--a-chip);
}
.ag-mrow.is-on .ag-mark.is-sm,.ag-mrow:hover .ag-mark.is-sm{color:var(--a-ink);}

/* What the catalogue already says about it, in the space that was empty. */
.ag-tag{
  display:inline-block;margin-left:7px;padding:2px 6px;border-radius:5px;
  font-style:normal;font-size:8.5px;font-weight:700;letter-spacing:.09em;
  text-transform:uppercase;
  color:var(--a-btn-ink);background:var(--a-btn);
  vertical-align:.5px;
}

/* The caret gets a well, so it is a control and not a decoration. */
.ag-caretw{
  display:grid;place-items:center;width:28px;height:28px;flex:none;
  border-radius:9px;color:var(--a-mute);background:transparent;
  transition:background-color .2s,color .2s;
}
.ag-pick:hover .ag-caretw{background:var(--a-chip);color:var(--a-ink);}
.ag-pick.is-open .ag-caretw{background:var(--a-chip-2);color:var(--a-ink);}

.ag-pick .ag-price{transition:transform .22s cubic-bezier(.2,.8,.2,1);}
.ag-pick:hover .ag-price{transform:scale(1.04);}
@media (prefers-reduced-motion:reduce){
  .ag-pick,.ag-pick .ag-price,.ag-mark,.ag-gobtn,.ag-gobtn svg{transition:none;}
  .ag-pick:hover,.ag-pick:active,.ag-gobtn:hover,.ag-gobtn:active{transform:none;}
  .ag-pick:hover .ag-mark,.ag-pick:hover .ag-price{transform:none;}
}
.ag-pick-t{flex:1;min-width:0;display:block;}
.ag-pick-t b{
  display:block;font-size:13.5px;font-weight:600;line-height:1.3;
  letter-spacing:-.012em;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.ag-pick-t em{
  display:block;padding-top:1px;font-style:normal;
  font-size:9.5px;font-weight:600;letter-spacing:.085em;text-transform:uppercase;
  color:var(--a-mute);
}
.ag-caret{width:10px;height:6px;flex:none;transition:transform .26s cubic-bezier(.2,.8,.2,1);}
.ag-pick.is-open .ag-caret{transform:rotate(180deg);}

.ag-models{
  margin-top:6px;max-height:232px;overflow-y:auto;
  border:1px solid var(--a-line);border-radius:14px;background:var(--a-sunk);
  transform-origin:top center;
  animation:ag-drop .26s cubic-bezier(.2,.9,.25,1) both;
}
@keyframes ag-drop{
  from{opacity:0;transform:translateY(-8px);max-height:0;}
  to{opacity:1;transform:none;max-height:232px;}
}
.ag-models::-webkit-scrollbar{width:8px;}
.ag-models::-webkit-scrollbar-thumb{background:var(--a-chip-2);border-radius:99px;}
.ag-mrow{
  display:flex;align-items:center;gap:10px;width:100%;
  padding:10px 13px;border:0;border-bottom:1px solid var(--a-line);cursor:pointer;
  text-align:left;color:var(--a-ink);background:transparent;
  transition:background-color .16s,padding-left .16s cubic-bezier(.2,.8,.2,1);
  /* each row a beat behind the one above it, so the list reads
     downwards rather than flashing into place all at once */
  animation:ag-rowin .26s cubic-bezier(.2,.9,.25,1) both;
  animation-delay:calc(var(--i,0) * 26ms + 40ms);
}
@keyframes ag-rowin{from{opacity:0;transform:translateY(-5px);}to{opacity:1;transform:none;}}
.ag-mrow:last-child{border-bottom:0;}
.ag-mrow:hover{background:var(--a-chip);padding-left:16px;}
.ag-mrow.is-on{background:var(--a-chip-2);}
.ag-tick{
  width:5px;height:5px;flex:none;border-radius:50%;
  background:currentColor;opacity:0;transform:scale(.4);
  transition:opacity .2s,transform .2s cubic-bezier(.2,1.6,.4,1);
}
.ag-mrow.is-on .ag-tick{opacity:1;transform:scale(1);}
@media (prefers-reduced-motion:reduce){
  .ag-models,.ag-mrow{animation:none;}
  .ag-mrow:hover{padding-left:13px;}
}
.ag-mrow-t{flex:1;min-width:0;}
.ag-mrow-t b{
  display:block;font-size:12.5px;font-weight:600;line-height:1.3;letter-spacing:-.01em;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.ag-mrow-t em{
  display:block;font-style:normal;font-size:9px;font-weight:600;
  letter-spacing:.08em;text-transform:uppercase;color:var(--a-mute);
}

/* Shapes, drawn. 9:16 and 16:9 are two words that differ by a swap and
   two pictures that could not be confused. */
/* A fixed grid of five, not a wrapping row. Pressing a shape makes its
   label bold, a bold label is a few pixels wider, and a wrapping row
   re-breaks around it — so choosing 4:3 rearranged every chip on the
   screen. Ten shapes in five columns is two tidy rows that never move,
   whichever one is lit. */
.ag-ratios{display:grid;grid-template-columns:repeat(5,1fr);gap:5px;}
.ag-ratio{
  display:inline-flex;align-items:center;justify-content:center;gap:6px;
  min-width:0;padding:6px 6px;border:1px solid var(--a-line);border-radius:11px;
  cursor:pointer;
  font-size:11px;font-variant-numeric:tabular-nums;color:var(--a-mute);
  background:transparent;
  transition:border-color .15s,color .15s,background .15s;
}
.ag-ratio span{white-space:nowrap;}
.ag-ratio i{display:grid;place-items:center;width:16px;height:15px;flex:none;}
.ag-ratio s{
  display:block;text-decoration:none;
  border:1.5px solid currentColor;border-radius:2px;opacity:.6;
}
.ag-ratio:hover{color:var(--a-ink);border-color:var(--a-chip-2);}
.ag-ratio.is-on{
  color:var(--a-btn-ink);background:var(--a-btn);border-color:transparent;font-weight:600;
}
.ag-ratio.is-on s{opacity:1;}

.ag-counts{display:flex;gap:5px;}
.ag-count{
  flex:1;padding:9px 0;border:1px solid var(--a-line);border-radius:11px;cursor:pointer;
  font-size:12px;font-weight:600;color:var(--a-mute);background:transparent;
  transition:border-color .15s,color .15s,background .15s;
}
.ag-count:hover{color:var(--a-ink);border-color:var(--a-chip-2);}
.ag-count.is-on{color:var(--a-btn-ink);background:var(--a-btn);border-color:transparent;}

.ag-sum{
  display:flex;align-items:center;justify-content:space-between;gap:10px;
  margin-top:14px;padding:11px 13px;border-radius:13px;
  font-size:12px;color:var(--a-mute);background:var(--a-chip);
}
.ag-sum b{display:inline-flex;align-items:center;gap:5px;font-size:13px;font-weight:700;color:var(--a-ink);}
.ag-sum b .ag-star{width:11px;height:11px;opacity:1;}
.ag-setnote{margin:10px 2px 8px;font-size:11px;line-height:1.45;color:var(--a-mute);}

/* ── the bar ──
   One box holds the words, what was attached to them and everything
   that acts on them, so the whole thing reads as a single field you
   are writing into rather than a stack of three controls. */
.ag-bar{padding:12px 14px 14px;border-top:1px solid var(--a-line);}
.ag-box{
  padding:12px 12px 10px;border:1px solid var(--a-line);border-radius:20px;
  background:var(--a-sunk);transition:border-color .16s;
}
.ag-box:focus-within{border-color:var(--a-chip-2);}
.ag-in{
  display:block;width:100%;max-height:150px;padding:2px 4px 6px;resize:none;
  border:0;background:transparent;
  font:inherit;font-size:13.5px;line-height:1.5;color:var(--a-ink);
}
.ag-in:focus{outline:none;}
.ag-in::placeholder{color:var(--a-mute);}
.ag-barrow{display:flex;align-items:center;gap:8px;}

.ag-refs{display:flex;flex-wrap:wrap;gap:6px;padding:2px 0 10px;}
.ag-refs[hidden]{display:none;}
.ag-ref{position:relative;display:block;width:58px;height:58px;}
.ag-ref img{
  width:100%;height:100%;object-fit:cover;display:block;
  border-radius:12px;border:1px solid var(--a-line);
}
.ag-ref button{
  position:absolute;top:-5px;right:-5px;display:grid;place-items:center;
  width:19px;height:19px;padding:0;border:0;border-radius:50%;cursor:pointer;
  color:var(--a-btn-ink);background:var(--a-btn);
  box-shadow:0 2px 8px rgba(0,0,0,.35);
}
.ag-ref button svg{width:11px;height:11px;}

.ag-round{
  display:grid;place-items:center;width:33px;height:33px;flex:none;
  border:1px solid var(--a-line);border-radius:50%;cursor:pointer;
  color:var(--a-mute);background:transparent;transition:background .15s,color .15s;
}
.ag-round svg{width:16px;height:16px;}
.ag-round:hover{background:var(--a-chip);color:var(--a-ink);}

.ag-chip{
  display:inline-flex;align-items:center;gap:7px;min-width:0;flex:1;
  padding:8px 12px;border:1px solid var(--a-line);border-radius:999px;cursor:pointer;
  font-size:11px;color:var(--a-mute);background:transparent;
  white-space:nowrap;overflow:hidden;
}
.ag-chip span{overflow:hidden;text-overflow:ellipsis;}
.ag-chip svg{width:14px;height:14px;flex:none;}
.ag-chip:hover{background:var(--a-chip);color:var(--a-ink);}

.ag-go{
  display:grid;place-items:center;width:36px;height:36px;flex:none;
  border:0;border-radius:50%;cursor:pointer;
  color:var(--a-btn-ink);background:var(--a-btn);
  transition:transform .16s cubic-bezier(.2,.8,.2,1),opacity .15s;
}
.ag-go svg{width:17px;height:17px;}
.ag-go:hover{transform:scale(1.07);}

/* ── one frame, large ── */
.ag-view{
  position:fixed;inset:0;z-index:9100;display:grid;place-items:center;gap:14px;
  grid-template-rows:1fr auto;padding:36px 24px 24px;
  background:rgba(0,0,0,.86);backdrop-filter:blur(6px);
}
.ag-view img{
  max-width:min(1100px,92vw);max-height:78vh;
  object-fit:contain;border-radius:8px;
  filter:drop-shadow(0 30px 60px rgba(0,0,0,.55));
}
.ag-vbar{display:flex;gap:8px;}
.ag-vbtn{
  padding:9px 16px;border:1px solid rgba(255,255,255,.22);border-radius:999px;cursor:pointer;
  font-size:12px;font-weight:600;text-decoration:none;
  color:#fff;background:rgba(255,255,255,.08);
}
.ag-vbtn:hover{background:rgba(255,255,255,.16);}
.ag-vclose{
  position:absolute;top:16px;right:18px;display:grid;place-items:center;
  width:36px;height:36px;border:0;border-radius:50%;cursor:pointer;
  color:#fff;background:rgba(255,255,255,.1);
}
.ag-vclose svg{width:17px;height:17px;}
.ag-vclose:hover{background:rgba(255,255,255,.2);}

/* ── on a phone it is a sheet, not a card ── */
@media (max-width:760px){
  .ag-launch{right:14px;bottom:14px;padding:10px 14px 10px 12px;}
  .ag-panel{right:8px;left:8px;bottom:8px;top:64px;width:auto;border-radius:20px;}
  .ag-navbtn span{display:none;}
}


/* ══════════════════════════════════════════════════════════════════
   CHOOSING SEVERAL

   The tick, the ring and the bar, for every grid of work in the studio:
   the Assets shelf, the wall on the Image page, and whatever comes next.
   One stylesheet block because js/picker.js is one behaviour — three
   copies of this would be three behaviours within a month.

   Deleting is the only thing here that cannot be undone: the bytes are
   in IndexedDB and nothing else holds a copy. So both bins ask twice, in
   place, rather than throwing a browser dialogue over the work — a
   confirm() box is somebody else's furniture in the middle of your page,
   and people dismiss them without reading.
   ══════════════════════════════════════════════════════════════════ */
.pk-tick{
  position:absolute;top:9px;left:9px;z-index:3;
  display:grid;place-items:center;width:23px;height:23px;
  border:1.5px solid rgba(255,255,255,.7);border-radius:50%;cursor:pointer;
  color:transparent;background:rgba(10,10,10,.42);
  backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);
  opacity:0;transform:scale(.86);
  transition:opacity .16s,transform .16s cubic-bezier(.2,1.5,.4,1),
             background-color .16s,border-color .16s,color .16s;
}
.pk-tick svg{width:12px;height:12px;}
.as-card:hover .pk-tick,
.gw-cell:hover .pk-tick,
body.is-picking .pk-tick{opacity:1;transform:none;}
.pk-tick:hover{border-color:#fff;}
.is-picked .pk-tick{
  opacity:1;transform:none;
  color:#0c0c0c;background:#fff;border-color:#fff;
}

/* The card says it is chosen: a ring, and a touch smaller, so a grid of
   forty reads at a glance. */
.as-card,.gw-cell{transition:transform .18s cubic-bezier(.2,.8,.2,1),box-shadow .18s;}
.as-card.is-picked,.gw-cell.is-picked{
  transform:scale(.972);
  box-shadow:0 0 0 2px var(--a-bg),0 0 0 4px var(--a-ink);
}
body.is-picking .as-card,
body.is-picking .gw-cell{cursor:pointer;}

/* The label in the corner is there to be read at rest; the tick is there
   to be pressed. So the label stands down whenever the tick is showing,
   rather than the two of them sitting on top of each other. */
.as-tag{transition:opacity .16s;}
.as-card:hover .as-tag,
body.is-picking .as-tag{opacity:0;}
/* The wall's own hover rail would fight the tick for the same card. */
body.is-picking .gw-rail{opacity:0;pointer-events:none;}

/* The bin on a card. Armed it turns solid and says so. */
.as-act-del:hover,.gw-act-del:hover{color:#fff;background:rgba(190,40,40,.9);}
.as-act-del.is-armed,.gw-act-del.is-armed{
  color:#fff;background:#c22b2b;
  animation:pk-arm .9s ease-in-out infinite;
}
@keyframes pk-arm{0%,100%{opacity:1;}50%{opacity:.62;}}

.pk-bar{
  position:fixed;left:0;right:0;margin-inline:auto;bottom:22px;z-index:96;
  display:flex;align-items:center;gap:8px;width:max-content;max-width:calc(100vw - 32px);
  padding:9px 10px 9px 18px;border-radius:100px;
  border:1px solid var(--a-line);
  background:color-mix(in srgb,var(--a-panel) 93%,transparent);
  backdrop-filter:blur(26px) saturate(1.4);
  -webkit-backdrop-filter:blur(26px) saturate(1.4);
  box-shadow:0 26px 60px -26px rgba(0,0,0,.85);
  animation:pk-bar-in .24s cubic-bezier(.2,.9,.25,1) both;
}
.pk-bar[hidden]{display:none;}
@keyframes pk-bar-in{from{opacity:0;transform:translateY(14px);}to{opacity:1;transform:none;}}
.pk-bar b{
  font-size:12.5px;font-weight:600;color:var(--a-ink);
  font-variant-numeric:tabular-nums;white-space:nowrap;
}
.pk-sep{width:1px;height:20px;flex:none;background:var(--a-line);}
.pk-btn{
  display:inline-flex;align-items:center;gap:7px;flex:none;
  padding:8px 14px;border:1px solid var(--a-line);border-radius:100px;cursor:pointer;
  font:inherit;font-size:12.5px;font-weight:600;line-height:1;
  color:var(--a-ink);background:transparent;white-space:nowrap;
  transition:background-color .16s,border-color .16s,color .16s,transform .16s;
}
.pk-btn svg{width:14px;height:14px;flex:none;}
.pk-btn:hover{background:var(--a-chip);border-color:var(--a-chip-2);}
.pk-btn:active{transform:scale(.97);}
.pk-btn.is-danger:hover{color:#fff;background:rgba(190,40,40,.9);border-color:transparent;}
.pk-btn.is-armed{
  color:#fff;background:#c22b2b;border-color:transparent;
  animation:pk-arm .9s ease-in-out infinite;
}
.pk-txt{
  padding:8px 10px;border:0;border-radius:100px;cursor:pointer;
  font:inherit;font-size:12px;font-weight:500;line-height:1;
  color:var(--a-mute);background:transparent;white-space:nowrap;
  transition:color .16s,background-color .16s;
}
.pk-txt:hover{color:var(--a-ink);background:var(--a-chip);}

/* The wall keeps its own floating composer down there. */
body.is-picking .gc{opacity:0;pointer-events:none;transform:translateY(14px);}

@media (prefers-reduced-motion:reduce){
  .pk-tick,.as-card,.gw-cell{transition:none;}
  .pk-bar{animation:none;}
  .as-act-del.is-armed,.gw-act-del.is-armed,.pk-btn.is-armed{animation:none;}
}

@media (max-width:760px){
  .pk-bar{left:10px;right:10px;bottom:12px;width:auto;padding:9px 10px;overflow-x:auto;}
  .pk-btn span{display:none;}
}


/* Sample work is for a first visit. Once this browser has made anything
   the class goes on <html> before the body is painted, so the shipped
   frames are never drawn — see the note above markMade in js/wall.js. */
.gw-has-work .gw-cell:not([data-gw-gen]){display:none;}
.gw-has-work [data-gw-empty]{display:none;}


/* ── UGC: the shot, written for you ──
   A field you can type in, and under it the button that fills it. The
   button is beside its own explanation rather than above the field,
   because what it does is to the field and should read that way. */
.app-shot{margin:0 auto 22px;max-width:620px;}
.app-shot-row{display:flex;align-items:center;gap:14px;flex-wrap:wrap;padding-top:12px;}
.app-autobtn{
  display:inline-flex;align-items:center;gap:9px;flex:none;
  padding:11px 18px;border:0;border-radius:100px;cursor:pointer;
  font:inherit;font-size:13.5px;font-weight:600;line-height:1;letter-spacing:-.01em;
  color:var(--a-btn-ink);background:var(--a-btn);
  transition:transform .18s cubic-bezier(.2,.8,.2,1),opacity .18s;
}
.app-autobtn svg{width:14px;height:14px;flex:none;}
.app-autobtn:hover{transform:translateY(-1px);}
.app-autobtn:active{transform:translateY(0) scale(.985);}
.app-autobtn:disabled{opacity:.55;cursor:default;transform:none;}
.app-shot-note{
  flex:1;min-width:180px;
  font-size:12px;line-height:1.5;color:var(--a-mute);
}


/* ── short screens ──
   A laptop at 768 or 800 high has about two thirds of the room a desktop
   has, and the wizard was laid out for the desktop. Nothing is removed
   here — the heading simply stops taking a fifth of the window, which is
   the difference between reading a step and scrolling to find it. */
@media (max-height:860px){
  .app-main{padding:18px 0 0;}
  .app-panel-head{margin-bottom:16px;}
  .app-panel-title{font-size:24px;letter-spacing:-.5px;}
  .app-panel-sub{font-size:13px;line-height:1.45;padding-top:6px;}
  .app-actions{padding:12px 0 14px;margin-top:18px;}
  .app-shot{margin-bottom:14px;}
  .app-shot textarea{min-height:92px;}
  .app-shot-row{padding-top:9px;}
}
@media (max-height:720px){
  .app-panel-title{font-size:21px;}
  .app-panel-sub{display:none;}
  .app-shot textarea{min-height:74px;}
}


/* ── bringing your own model ──
   A third tab beside Women and Men, and behind it a plain drop area.
   Locked, it keeps its place in the row rather than disappearing: a tab
   that is not there teaches nothing, and one that is there with a lock
   on it says what the next plan is for. */
.app-gender-tabs button.is-locked{opacity:.62;}
.app-gender-tabs button.is-locked svg{width:12px;height:12px;margin-right:6px;vertical-align:-1px;}

.app-own{max-width:560px;margin:0 auto;}
.app-own[hidden]{display:none;}
.app-own-drop{
  display:block;padding:34px 28px;border-radius:18px;cursor:pointer;text-align:center;
  border:1px dashed var(--a-chip-2,rgba(255,255,255,.18));
  background:var(--a-chip,rgba(255,255,255,.04));
  transition:border-color .18s,background-color .18s;
}
.app-own-drop:hover{border-color:var(--a-ink);background:var(--a-chip-2);}
.app-own-ic{display:block;width:40px;height:40px;margin:0 auto 12px;color:var(--a-mute);}
.app-own-ic svg{width:100%;height:100%;}
.app-own-drop b{display:block;font-size:15px;font-weight:600;color:var(--a-ink);}
.app-own-drop em{
  display:block;max-width:360px;margin:7px auto 0;
  font-style:normal;font-size:12.5px;line-height:1.5;color:var(--a-mute);
}

.app-own-have{
  display:flex;align-items:center;gap:14px;
  margin-top:14px;padding:12px 14px;border-radius:14px;
  border:1px solid var(--a-line);background:var(--a-sunk);
}
.app-own-have[hidden]{display:none;}
.app-own-have img{width:54px;height:54px;object-fit:cover;border-radius:11px;flex:none;}
.app-own-have b{display:block;font-size:13.5px;color:var(--a-ink);}
.app-own-have em{
  display:block;font-style:normal;font-size:11.5px;color:var(--a-mute);
  max-width:300px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.app-own-x{
  margin-left:auto;width:30px;height:30px;flex:none;
  border:0;border-radius:50%;cursor:pointer;font-size:19px;line-height:1;
  color:var(--a-mute);background:transparent;
}
.app-own-x:hover{color:var(--a-ink);background:var(--a-chip);}

/* Templates: the same door, locked until Starter. */
.tpl-door.is-locked{opacity:.55;}


/* ── the garment stage ──
   One garment at a time, its front beside its back. The tray of squares
   that used to live here made somebody hold the whole outfit in their
   head; this asks the small question instead — is this piece done — and
   leaves the outfit to the list at the side. */
.app-upload.is-stage{flex-direction:column;padding:16px 16px 20px;}

.fl-pick{position:relative;display:flex;justify-content:center;margin:2px 0 14px;}
.fl-pick-btn{
  display:inline-flex;align-items:center;gap:8px;
  padding:7px 8px 7px 15px;border:1px solid var(--a-line);border-radius:100px;
  background:var(--a-chip);color:var(--a-ink);cursor:pointer;
  font:inherit;font-size:13px;font-weight:600;letter-spacing:.01em;
  transition:background-color .15s,border-color .15s;
}
.fl-pick-btn:hover{border-color:var(--a-mute);}
.fl-chev{width:14px;height:14px;opacity:.6;transition:transform .2s;}
.fl-pick.is-open .fl-chev{transform:rotate(180deg);}
.fl-pick-menu{
  position:absolute;top:calc(100% + 8px);left:50%;transform:translateX(-50%);
  z-index:40;min-width:186px;padding:6px;
  border:1px solid var(--a-line);border-radius:15px;background:var(--a-panel);
  box-shadow:0 20px 46px rgba(0,0,0,.35);
}
.fl-pick-item{
  display:flex;align-items:center;gap:9px;width:100%;
  padding:8px 10px;border:0;border-radius:10px;background:transparent;
  color:var(--a-mute);cursor:pointer;font:inherit;font-size:12.5px;text-align:left;
  transition:background-color .14s,color .14s;
}
.fl-pick-item:hover{background:var(--a-chip);color:var(--a-ink);}
.fl-pick-item.is-on{color:var(--a-ink);font-weight:600;}
.fl-pick-ic{width:13px;height:13px;flex:none;display:grid;place-items:center;}
.fl-pick-ic svg{width:12px;height:12px;}
.fl-pick-t{flex:1;}
.fl-pick-dot{width:5px;height:5px;border-radius:50%;background:var(--a-ink);opacity:.45;}

.fl-stage{display:grid;grid-template-columns:1fr 1fr;gap:14px;}
.fl-pane{
  position:relative;display:grid;place-items:center;
  padding:30px 20px 40px;border-radius:20px;
  background:linear-gradient(180deg,var(--a-chip),transparent);
  box-shadow:inset 0 0 0 1px var(--a-line);
  transition:box-shadow .18s;
}
.fl-pane.is-over{box-shadow:inset 0 0 0 1.5px var(--a-ink);}
.fl-pane-tag{
  position:absolute;top:13px;left:15px;
  font-size:10px;font-weight:600;letter-spacing:.11em;text-transform:uppercase;
  color:var(--a-mute);
}
.fl-hold{position:relative;width:100%;max-width:184px;}
.fl-card{
  width:100%;aspect-ratio:3/4;border-radius:15px;overflow:hidden;
  display:grid;place-items:center;
  background:var(--a-panel);box-shadow:inset 0 0 0 1px var(--a-line);
}
.fl-card img{width:100%;height:100%;object-fit:cover;display:block;}
.fl-ghost{width:66px;height:88px;color:var(--a-ink);opacity:.15;}

/* ── accessories ──
   One panel across both columns, because a list of things has no front
   and back to set side by side. */
.fl-stage.is-many{grid-template-columns:1fr;}
.fl-pane-many{display:block;padding:34px 22px 26px;}
.fl-many{
  display:flex;flex-wrap:wrap;justify-content:center;gap:10px;
}
.fl-many-cell{
  position:relative;width:96px;aspect-ratio:1;border-radius:13px;overflow:hidden;
  background:var(--a-panel);box-shadow:inset 0 0 0 1px var(--a-line);
}
.fl-many-cell img{width:100%;height:100%;object-fit:cover;display:block;}
.fl-many-x{
  position:absolute;top:5px;right:5px;width:21px;height:21px;
  border:0;border-radius:50%;cursor:pointer;font-size:10px;line-height:1;
  color:#fff;background:rgba(10,10,10,.6);
  backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);
  opacity:0;transition:opacity .15s;
}
.fl-many-cell:hover .fl-many-x{opacity:1;}
.fl-many-add{
  display:grid;place-items:center;gap:5px;align-content:center;
  width:96px;aspect-ratio:1;border-radius:13px;cursor:pointer;
  border:1px dashed var(--a-line);background:transparent;color:var(--a-mute);
  font:inherit;font-size:11px;
  transition:color .15s,border-color .15s;
}
.fl-many-add:hover{color:var(--a-ink);border-color:var(--a-mute);}
.fl-many-add svg{width:16px;height:16px;}
.fl-many-hint{
  margin:16px 0 0;text-align:center;font-size:11.5px;color:var(--a-mute);
}

/* ── our own looks ──
   A shelf under the panels: one row, scrolled sideways, nothing on the
   page but the pictures. */
.fl-ours{margin:18px 0 0;padding-top:16px;border-top:1px solid var(--a-line);}
.fl-ours-h{text-align:center;margin-bottom:12px;}
.fl-ours-h h3{margin:0;font-size:13px;font-weight:600;color:var(--a-ink);}
.fl-ours-h p{margin:3px 0 0;font-size:11.5px;color:var(--a-mute);}
.fl-ours-row{
  display:flex;gap:9px;overflow-x:auto;padding:2px 2px 8px;
  scroll-snap-type:x proximity;scrollbar-width:thin;
}
.fl-ours-row::-webkit-scrollbar{height:6px;}
.fl-ours-row::-webkit-scrollbar-thumb{border-radius:100px;background:var(--a-line);}
.fl-ours-row::-webkit-scrollbar-track{background:transparent;}
.fl-ours-i{
  position:relative;flex:0 0 78px;aspect-ratio:3/4;scroll-snap-align:start;
  padding:0;border:0;border-radius:11px;overflow:hidden;cursor:pointer;
  background:var(--a-panel);box-shadow:inset 0 0 0 1px var(--a-line);
  transition:transform .18s,box-shadow .18s;
}
.fl-ours-i img{width:100%;height:100%;object-fit:cover;display:block;transition:opacity .18s;}
.fl-ours-i:hover{transform:translateY(-2px);}
.fl-ours-i:hover img{opacity:.78;}
.fl-ours-mark{
  position:absolute;inset:0;display:grid;place-items:center;
  color:var(--a-btn-ink,#121212);background:rgba(255,255,255,.72);
  opacity:0;transition:opacity .18s;
}
.fl-ours-mark svg{width:18px;height:18px;}
.fl-ours-i.is-on .fl-ours-mark{opacity:1;}
.fl-ours-i.is-on{box-shadow:inset 0 0 0 2px var(--a-ink);}

/* ── the shelf latch ──
   One press, directly under the stage, so the pile of old uploads is
   within reach without being on the page. */
.app-shelf{display:flex;justify-content:center;margin:0 0 14px;}
.app-shelf-btn{
  display:inline-flex;align-items:center;gap:8px;
  padding:8px 14px;border:1px solid var(--a-line);border-radius:100px;
  background:var(--a-panel);color:var(--a-mute);cursor:pointer;
  font:inherit;font-size:12px;font-weight:600;
  transition:color .15s,border-color .15s;
}
.app-shelf-btn:hover{color:var(--a-ink);border-color:var(--a-mute);}
.app-shelf-btn svg{width:14px;height:14px;flex:none;}
.app-shelf-chev{opacity:.6;transition:transform .2s;}
.app-shelf-btn.is-open .app-shelf-chev{transform:rotate(180deg);}
.app-shelf-n{
  padding:1px 7px;border-radius:100px;font-size:10.5px;
  color:var(--a-ink);background:var(--a-chip);
}
.app-shelf-n:empty{display:none;}

/* ── how it works ──
   Centred, and last: it is read once and then never again. */
.app-how{
  max-width:700px;margin:30px auto 4px;padding:32px 20px 4px;
  text-align:center;border-top:1px solid var(--a-line);
}
.how-eyebrow{
  margin:0 0 28px;font-size:10px;font-weight:600;letter-spacing:.15em;
  text-transform:uppercase;color:var(--a-mute);
}
.how-block + .how-block{margin-top:36px;}
.how-h{margin:0 0 9px;font-size:15px;font-weight:600;letter-spacing:-.1px;color:var(--a-ink);}
.how-note{margin:0 auto 20px;max-width:440px;font-size:12.5px;line-height:1.65;color:var(--a-mute);}
.how-row{display:flex;justify-content:center;gap:12px;}
.how-shot{
  position:relative;margin:0;width:104px;aspect-ratio:3/4;
  border-radius:13px;overflow:hidden;background:var(--a-chip);
}
.how-shot img{width:100%;height:100%;object-fit:cover;display:block;}
.how-mark{
  position:absolute;right:6px;bottom:6px;
  display:grid;place-items:center;width:20px;height:20px;border-radius:50%;
}
.how-mark svg{width:11px;height:11px;}
.how-mark.is-good{color:#08230f;background:#5fb07c;}
.how-mark.is-bad{color:#260c08;background:#c4705c;}
.how-bad{
  list-style:none;margin:0;padding:0;
  display:flex;flex-wrap:wrap;justify-content:center;gap:8px;
}
.how-bad li{
  display:inline-flex;align-items:center;gap:8px;
  padding:6px 13px 6px 7px;border-radius:100px;
  border:1px solid var(--a-line);
  font-size:12px;line-height:1.4;color:var(--a-mute);
}
.how-bad .how-mark{position:static;width:18px;height:18px;flex:none;}
@media (max-width:560px){
  .app-how{margin-top:24px;padding-top:26px;}
  .how-shot{width:84px;}
  .how-bad li{font-size:11.5px;}
}

.fl-pane-tag em{
  font-style:normal;margin-left:6px;padding:2px 6px;border-radius:100px;
  font-size:8.5px;font-weight:600;letter-spacing:.06em;
  color:var(--a-mute);background:var(--a-chip);
}

/* The way in sits on the edge of the card it fills, which is where the
   eye already is. */
.fl-add{
  position:absolute;left:50%;bottom:-17px;transform:translateX(-50%);
  width:34px;height:34px;border:0;border-radius:50%;cursor:pointer;
  display:grid;place-items:center;
  color:var(--a-btn-ink,#fff);background:var(--a-btn,#121212);
  box-shadow:0 8px 22px rgba(0,0,0,.4);
  transition:transform .16s;
}
.fl-add svg{width:16px;height:16px;}
.fl-add:hover{transform:translateX(-50%) scale(1.08);}
.fl-tip{
  position:absolute;bottom:calc(100% + 10px);left:50%;transform:translateX(-50%);
  padding:5px 10px;border-radius:9px;white-space:nowrap;
  font-size:11px;font-weight:600;color:var(--a-btn-ink,#fff);background:var(--a-btn,#121212);
  box-shadow:0 10px 24px rgba(0,0,0,.4);
  opacity:0;pointer-events:none;transition:opacity .15s;
}
.fl-tip::after{
  content:'';position:absolute;top:100%;left:50%;transform:translateX(-50%);
  border:5px solid transparent;border-top-color:var(--a-btn,#121212);
}
.fl-add:hover .fl-tip,.fl-add:focus-visible .fl-tip{opacity:1;}
.fl-x{
  position:absolute;top:10px;right:10px;
  width:24px;height:24px;border:0;border-radius:50%;cursor:pointer;
  color:#fff;background:rgba(10,10,10,.55);
  backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);
  font-size:11px;line-height:1;opacity:0;transition:opacity .15s;
}
.fl-pane:hover .fl-x,.fl-x:focus-visible{opacity:1;}
.fl-hint{
  margin:18px 0 0;text-align:center;
  font-size:11.5px;color:var(--a-mute);
}
@media (max-width:820px){
  .fl-pane{padding:26px 12px 34px;}
  .fl-hold{max-width:154px;}
}
@media (max-width:560px){
  .fl-stage{gap:10px;}
  .fl-pane{padding:23px 8px 30px;border-radius:16px;}
  .fl-pane-tag{top:9px;left:10px;font-size:9px;letter-spacing:.08em;}
  .fl-hold{max-width:126px;}
  .fl-card{border-radius:12px;}
  .fl-ghost{width:46px;height:46px;}
  .fl-add{width:30px;height:30px;bottom:-15px;}
  .fl-add svg{width:14px;height:14px;}
  .fl-hint{margin-top:14px;font-size:11px;}
}

.app-check{
  border:1px solid var(--a-line);border-radius:18px;padding:14px;
  background:var(--a-panel);
}
.app-check-h{
  margin:0 0 12px;font-size:10.5px;font-weight:600;
  letter-spacing:.09em;text-transform:uppercase;color:var(--a-mute);
}
.app-check-item{
  display:flex;gap:11px;padding:9px;border-radius:14px;cursor:pointer;
  border:1px solid transparent;
  transition:border-color .15s,background-color .15s;
}
.app-check-item:hover{background:var(--a-chip);}
.app-check-item.is-on{border-color:var(--a-line);background:var(--a-chip);}
.app-check-item + .app-check-item{margin-top:4px;}
.app-check-thumb{
  width:46px;height:56px;flex:none;border-radius:9px;overflow:hidden;
  background:var(--a-chip);display:grid;place-items:center;
}
.app-check-thumb img{width:100%;height:100%;object-fit:cover;}
.app-check-t{flex:1;min-width:0;}
.app-check-t b{display:block;font-size:12.5px;color:var(--a-ink);padding-bottom:5px;}
.app-check-row{
  display:flex;align-items:center;gap:7px;width:100%;
  padding:3px 0;border:0;background:transparent;cursor:pointer;
  font:inherit;font-size:11.5px;text-align:left;color:var(--a-mute);
  transition:color .15s;
}
.app-check-row:hover{color:var(--a-ink);}
.app-check-ic{
  display:grid;place-items:center;width:15px;height:15px;flex:none;
  border-radius:50%;color:var(--a-mute);background:var(--a-chip);
}
.app-check-ic svg{width:10px;height:10px;}
.app-check-row.is-on{color:var(--a-ink);}
.app-check-row.is-on .app-check-ic{
  color:var(--a-btn-ink);background:var(--a-btn);
}
.app-slot{
  border:1px solid var(--a-line);border-radius:18px;padding:13px;
  background:var(--a-panel);
}
.app-slot-h{display:flex;align-items:baseline;gap:8px;padding-bottom:10px;}
.app-slot-h b{font-size:13.5px;color:var(--a-ink);}
.app-slot-h em{font-style:normal;font-size:10.5px;color:var(--a-mute);}

.app-slot-face{
  position:relative;display:grid;place-items:center;
  aspect-ratio:3/4;border-radius:13px;cursor:pointer;overflow:hidden;
  border:1px dashed var(--a-chip-2);background:var(--a-chip);
  transition:border-color .16s,background-color .16s;
}
.app-slot-face:hover{border-color:var(--a-ink);}
.app-slot-face.is-filled{border-style:solid;border-color:var(--a-line);}
.app-slot-face img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;}
.app-slot-empty{
  display:flex;flex-direction:column;align-items:center;gap:6px;
  font-size:11.5px;color:var(--a-mute);
}
.app-slot-empty svg{width:20px;height:20px;}

.app-slot-back{
  position:relative;display:block;margin-top:8px;padding:8px;border-radius:10px;
  text-align:center;cursor:pointer;overflow:hidden;
  font-size:11px;color:var(--a-mute);background:var(--a-chip);
  transition:color .16s,background-color .16s;
}
.app-slot-back:hover{color:var(--a-ink);background:var(--a-chip-2);}
.app-slot-back.is-filled{height:52px;padding:0;}
.app-slot-back.is-filled span{display:none;}
.app-slot-back img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;}

.app-slot-hint{margin:9px 0 0;font-size:11px;line-height:1.45;color:var(--a-mute);}

/* What the run will do, in the reader's words. It is the same sentence
   the engine is sent — see outfitLine in js/app.js. */
.app-slot-says{
  max-width:640px;margin:20px auto 0;text-align:center;
  font-size:13px;line-height:1.55;color:var(--a-ink);
}

.app-check-says{
  margin:12px 0 0;padding-top:11px;border-top:1px solid var(--a-line);
  font-size:11.5px;line-height:1.5;color:var(--a-ink);
}
.app-check{margin-bottom:22px;}
.app-check-none{display:block;width:100%;height:100%;}
