/* The iMessage stage: the Messages window, the photo tiles, and the
   visitor's own screenshot behind them. Everything here is
   iMessage-only. The appearance tokens live in ../shared/macos.css and
   the control panel in ../shared/shell.css. */

/* ============================================================
   LAYER A — THE STAGE. Only this is ever exported.

   Its size is set in JS, because the stage takes the shape of the
   screenshot the visitor uploads. The values here are only the
   starting shape, before anything is added.
   ============================================================ */
#stageWrap{
  position:absolute; left:50%; top:50%; transform:translate(-50%,-50%);
  border-radius:12px; box-shadow:var(--shadow-lg);
}
#stage{
  width:1440px; height:900px; transform-origin:top left;
  position:relative; overflow:hidden; border-radius:12px;
  font-family:var(--os); user-select:none;
}

/* Anything that belongs to the editor rather than the picture goes
   away for the render. One class, so nothing can be forgotten. */
#stage.exporting .deskprompt,
#stage.exporting .imsg-ghost,
#stage.exporting .imsg-rsz{display:none}

/* ---- The screen behind ----
   Their screenshot fills the whole stage, menu bar, dock and all, so
   there is no second menu bar of mine fighting theirs. */
.deskprompt{
  position:absolute; right:5%; top:50%; transform:translateY(-50%);
  width:300px; padding:26px 22px; border-radius:18px;
  display:flex; flex-direction:column; align-items:center; gap:9px; text-align:center;
  background:rgba(255,255,255,.07); border:1.5px dashed rgba(255,255,255,.34);
  color:rgba(255,255,255,.9); backdrop-filter:blur(3px);
  transition:background .16s ease, border-color .16s ease;
}
.deskprompt:hover{background:rgba(255,255,255,.13); border-color:rgba(255,255,255,.6)}
.dp-plus{
  width:44px; height:44px; border-radius:50%; display:grid; place-items:center;
  background:rgba(255,255,255,.16);
}
.dp-word{font-size:14px; font-weight:500; letter-spacing:-.01em; line-height:1.3}
.dp-sub{font-size:12px; opacity:.72}
#stage.hasShot .deskprompt{display:none}

/* ---- Dani's Messages window ----
   714x736 at 1x from the Figma component, scaled as one piece. The
   frame is a flat image: header, icons, the plus, the field, the
   waveform and the emoji button are all pixels. Resizing can only
   scale the whole thing, because every photo position in the file is
   measured against this exact size.
   ============================================================ */
.imsg{
  position:absolute; width:714px; height:736px; z-index:20;
  left:96px; top:100px;
  transform-origin:top left; transform:scale(var(--ws,1));
  border-radius:10px; box-shadow:var(--win-shadow);
  cursor:grab;
}
.imsg.dragging{cursor:grabbing}
.imsg-chrome{
  position:absolute; inset:0; width:714px; height:736px; display:block;
  border-radius:10px; pointer-events:none;
}

/* the drag handle, bottom right, the way a real window has one */
.imsg-rsz{
  position:absolute; right:0; bottom:0; width:22px; height:22px;
  cursor:nwse-resize; z-index:6; border-bottom-right-radius:10px;
}
.imsg-rsz::after{
  content:""; position:absolute; right:5px; bottom:5px; width:9px; height:9px;
  border-right:2px solid currentColor; border-bottom:2px solid currentColor;
  border-bottom-right-radius:3px; color:rgba(0,0,0,.26); opacity:0;
  transition:opacity .16s ease;
}
.imsg:hover .imsg-rsz::after{opacity:1}
#stage[data-appearance="dark"] .imsg-rsz::after{color:rgba(255,255,255,.4)}

/* The one live text layer in Dani's file: left 20, top 17, 12px.
   Rendered in the OS font rather than Inter, because every other word
   in the frame is a real macOS screenshot. */
.imsg-to{
  position:absolute; left:20px; top:17px; z-index:3;
  display:flex; align-items:center; gap:4px;
  font-size:12px; line-height:normal; white-space:nowrap;
}
.imsg-to-label{color:rgba(0,0,0,.5)}
.imsg-to-name{
  color:#000; outline:none; min-width:6px;
  border-radius:3px; padding:0 2px; margin:0 -2px;
  cursor:text; -webkit-user-select:text; user-select:text;
}
.imsg-to-name:hover{background:rgba(0,0,0,.05)}
.imsg-to-name:focus{background:rgba(0,0,0,.06)}
.imsg-to-name:empty::before{content:"[name]"; color:rgba(0,0,0,.32)}
#stage[data-appearance="dark"] .imsg-to-label{color:rgba(255,255,255,.5)}
#stage[data-appearance="dark"] .imsg-to-name{color:#fff}
#stage[data-appearance="dark"] .imsg-to-name:hover{background:rgba(255,255,255,.08)}
#stage[data-appearance="dark"] .imsg-to-name:focus{background:rgba(255,255,255,.1)}
#stage[data-appearance="dark"] .imsg-to-name:empty::before{color:rgba(255,255,255,.34)}

/* ---- The thread ----
   Tile coordinates are window coordinates, straight out of Figma, so
   the numbers in the code are the numbers in the file. */
.imsg-thread{position:absolute; inset:0; z-index:2}

.imsg-tile{
  position:absolute; padding:0; overflow:hidden; background:var(--field);
  transform:translate(-50%,-50%) rotate(var(--rot,0deg));
  transition:box-shadow .16s ease;
  cursor:grab; touch-action:none;
}
.imsg-tile.panning{cursor:grabbing}
#stage.noTilt .imsg-tile{transform:translate(-50%,-50%)}
/* Panned and zoomed inside its frame, so a face never has to be lost
   to a crop. Sized to cover at zoom 1, then moved from the centre. */
.imsg-tile img{
  position:absolute; left:50%; top:50%; display:block;
  transform:translate(-50%,-50%) translate(var(--tx,0px), var(--ty,0px));
  pointer-events:none;
}
.imsg-tile.sel{box-shadow:var(--tileShadow), 0 0 0 2.5px var(--accent)}

/* The receipt under the last photo. No design exists for this in the
   Figma file, so it borrows the only grey the file states: the same
   half-strength ink as the "To:" label, a size down. */
.imsg-receipt{
  position:absolute; z-index:2; font-size:10.5px; letter-spacing:-.005em;
  color:rgba(0,0,0,.45); text-align:right; white-space:nowrap;
}
#stage[data-appearance="dark"] .imsg-receipt{color:rgba(255,255,255,.45)}

/* The empty thread. Ghosts of the real composition, so the shape of the
   result is visible before anything is uploaded and the next move needs
   no explaining. */
.imsg-ghost{
  position:absolute; border-radius:16px; background:none;
  border:1.5px dashed rgba(0,0,0,.22);
  transform:translate(-50%,-50%) rotate(var(--rot,0deg));
  display:grid; place-items:center; color:rgba(0,0,0,.28);
  transition:border-color .16s ease, color .16s ease;
}
.imsg-ghost:hover{border-color:rgba(0,0,0,.38); color:rgba(0,0,0,.5)}
#stage[data-appearance="dark"] .imsg-ghost{border-color:rgba(255,255,255,.34); color:rgba(255,255,255,.46)}
#stage[data-appearance="dark"] .imsg-ghost:hover{border-color:rgba(255,255,255,.4); color:rgba(255,255,255,.6)}
.imsg-ghost svg{display:block}

/* The plus in the composer is part of Dani's image, so this is an
   invisible hit area sitting exactly on it: centre 28, 706.5, measured
   off the export. Bigger than the drawn circle, because 24px is not a
   thumb. */
.imsg-plus{
  position:absolute; left:6px; top:684px; width:44px; height:44px;
  border-radius:50%; z-index:4; background:none;
}
.imsg-plus:focus-visible{outline:2px solid var(--accent); outline-offset:1px}
.imsg-plus::after{
  content:""; position:absolute; inset:10px; border-radius:50%;
  background:currentColor; opacity:0; transition:opacity .16s ease;
}
.imsg-plus:hover::after{opacity:.07}

/* First visit only: the plus breathes once the page settles, so the way
   in is findable without a line of instructions. */
.imsg-plus.nudge::before{
  content:""; position:absolute; inset:8px; border-radius:50%;
  border:1.5px solid var(--accent); opacity:0;
  animation:plusRing 2.6s ease-out 3;
}
@keyframes plusRing{
  0%{transform:scale(.62); opacity:0}
  18%{opacity:.5}
  60%,100%{transform:scale(1.5); opacity:0}
}
@media (prefers-reduced-motion: reduce){ .imsg-plus.nudge::before{animation:none} }

/* ============================================================
   LAYER B — the controls
   ============================================================ */
/* two toggles rather than four, so they sit together instead of
   drifting to the far corners of the panel */
.circles.two{justify-content:flex-start; gap:34px; padding-left:6px}

/* a segmented row, in the same shape as the wallpaper swatches */
.seg{display:flex; gap:6px}
.seg button{
  flex:1; height:32px; border-radius:11px; font-size:11.5px; font-weight:500;
  letter-spacing:-.005em; color:var(--p-ink); background:var(--off);
}
.seg button[aria-checked="true"]{background:var(--on); color:var(--ink-on); box-shadow:var(--lift)}

/* The second action reads as the quieter one, so the main path stays
   obvious: add photos, then download. */
.go.alt{background:var(--p-card); box-shadow:none; color:var(--p-ink)}
.go.alt:hover{opacity:1; background:var(--off)}

/* The way into the controls. There is no fake menu bar to hang a
   sparkle in any more, because the visitor's screenshot brings its own,
   so it lives in the corner of the page instead. Outside #chrome, so it
   still works when the controls are hidden. */
#opener{
  position:fixed; left:20px; top:20px; z-index:600;
  width:36px; height:36px; border-radius:50%; display:grid; place-items:center;
  background:var(--panel); border:1px solid var(--panel-line); color:var(--panel-ink-dim);
  box-shadow:0 6px 18px rgba(20,16,24,.2); transition:color .2s, transform .2s;
}
#opener svg{width:17px; height:17px; display:block}
#opener:hover{color:var(--panel-ink)}
#opener.attract svg{animation:openerNudge 2.8s ease-in-out infinite}
#opener.attract::after{
  content:""; position:absolute; inset:-5px; border-radius:50%;
  border:1.5px solid currentColor; opacity:0; pointer-events:none;
  animation:openerRing 2.8s ease-out infinite;
}
@keyframes openerNudge{
  0%,55%,100%{transform:scale(1) rotate(0)}
  62%{transform:scale(1.2) rotate(-9deg)}
  70%{transform:scale(1) rotate(0)}
  77%{transform:scale(1.1) rotate(7deg)}
  85%{transform:scale(1) rotate(0)}
}
@keyframes openerRing{
  0%,54%{transform:scale(.6); opacity:0}
  63%{opacity:.4}
  100%{transform:scale(1.5); opacity:0}
}
#opener.spin svg{animation:openerSpin .62s cubic-bezier(.34,.75,.28,1)}
@keyframes openerSpin{
  0%{transform:rotate(0) scale(1)}
  55%{transform:rotate(200deg) scale(1.3)}
  100%{transform:rotate(360deg) scale(1)}
}
@media (prefers-reduced-motion: reduce){
  #opener.attract svg, #opener.attract::after, #opener.spin svg{animation:none}
}

#hint{left:auto; right:16px; top:16px; transform:none}

/* ---- The phone action bar ----
   Only the two things the main path needs. Hidden while the panel is
   open, so the two never stack up on a small screen. */
#phonebar{display:none}
#chrome:not(.hidden) ~ #phonebar{display:none !important}
.pb-main, .pb-save{
  height:52px; border-radius:26px; background:var(--panel);
  border:1px solid var(--panel-line); box-shadow:0 10px 26px rgba(20,16,24,.22);
  color:var(--panel-ink); font-size:14px; font-weight:500; letter-spacing:-.005em;
}
.pb-main{flex:1}
.pb-save{width:52px; display:grid; place-items:center; color:var(--panel-ink-dim)}
.pb-save:hover{color:var(--panel-ink)}
.pb-main:active, .pb-save:active{transform:scale(.98)}

/* ---- Tile actions ----
   Editing happens on the photo, not in a sidebar. Fixed rather than
   placed inside the stage, for two reasons: the buttons keep their real
   size however far the stage is scaled down on a phone, and nothing
   that belongs to the editor can ever land in the exported picture. */
.tileacts{
  position:fixed; z-index:700; display:none; gap:6px; padding:5px;
  border-radius:15px; background:rgba(28,26,32,.86);
  backdrop-filter:blur(14px); -webkit-backdrop-filter:blur(14px);
  box-shadow:0 10px 26px rgba(0,0,0,.3);
  transform:translate(-50%,-50%);
}
.tileacts.on{display:flex}
.tileacts button{
  width:34px; height:34px; border-radius:50%; display:grid; place-items:center;
  color:#fff; background:rgba(255,255,255,.14);
}
.tileacts button:hover{background:rgba(255,255,255,.26)}
.tileacts button[disabled]{opacity:.3}
/* the class sets display, so the hidden attribute needs saying twice */
.tileacts button[hidden]{display:none}
.tileacts svg{display:block}
.tileacts .sep{width:1px; height:24px; align-self:center; background:rgba(255,255,255,.18)}

/* ---- Toast ---- */
#toast{
  position:fixed; left:50%; bottom:22px; transform:translate(-50%, 14px);
  z-index:750; padding:9px 15px; border-radius:11px;
  background:var(--panel); border:1px solid var(--panel-line); color:var(--panel-ink);
  box-shadow:0 12px 30px rgba(20,16,24,.2); font-size:12.5px;
  opacity:0; pointer-events:none; transition:opacity .2s ease, transform .2s ease;
}
#toast.on{opacity:1; transform:translate(-50%,0)}

/* ---- Phone ----
   Most visitors arrive from TikTok or Instagram, so this is the case
   the layout is designed for rather than one it degrades into. */
@media (max-width: 900px){
  /* A whole desktop shrunk into a phone screen is unusable: the photos
     come out about 47px wide. So the phone view zooms to the Messages
     window and lets the screenshot bleed off the edges, which reads as
     being zoomed into a screenshot and quietly shows there is more
     around it. The download is still the whole screen. */
  #stageWrap{
    top:14px; left:50%; transform:translate(-50%,0);
    box-shadow:none; border-radius:14px; overflow:hidden;
  }
  #stage{border-radius:0}
  /* top right on a phone: the top left is where the name sits */
  #opener{left:auto; right:12px; top:12px}
  #phonebar{
    display:flex; gap:10px; align-items:center;
    position:fixed; left:12px; right:12px; bottom:12px; z-index:520;
  }
  #hint{display:none}
  .imsg-plus{left:-4px; top:674px; width:64px; height:64px}
  .imsg-rsz{width:34px; height:34px}
  .imsg-rsz::after{opacity:1}
  .deskprompt{right:auto; left:50%; transform:translate(-50%,-50%); width:270px}
  /* the actions become a bar in reach of a thumb, just above the panel */
  .tileacts.bar{transform:translate(-50%,-100%); border-radius:19px; padding:6px}
  .tileacts button{width:42px; height:42px}
  #toast{bottom:auto; top:16px; transform:translate(-50%,-14px)}
  #toast.on{transform:translate(-50%,0)}
}
