/* ============================================================================
   RevelPics — Soft Luxe (guest-facing layer)

   Layered over style.css, which owns structure. This file owns how the guest
   experience feels: soft depth, generous radii, warm ambient light.

   CRITICAL: theme.js writes --bg, --accent, --ink and friends as INLINE styles
   on <html>, so an inline style beats any stylesheet rule. Nothing here may
   redefine a colour token, or per-event theming silently breaks. Consume them.
   Only geometry and depth are overridden, and theme.js never touches those.
   ========================================================================== */

:root{
  /* geometry: theme.js does not set these, so we may own them */
  --radius:22px;
  --radius-sm:15px;
  --lux-r-lg:26px;

  /* depth. Declared twice: a plain fallback first, then color-mix so the shadow
     is derived from the ink colour and stays visible on dark themes too. */
  --lux-sh-1:0 1px 2px rgba(0,0,0,.05), 0 6px 18px rgba(0,0,0,.07);
  --lux-sh-1:0 1px 2px color-mix(in srgb, var(--ink) 5%, transparent),
             0 6px 18px color-mix(in srgb, var(--ink) 7%, transparent);
  --lux-sh-2:0 2px 6px rgba(0,0,0,.07), 0 16px 40px rgba(0,0,0,.10);
  --lux-sh-2:0 2px 6px color-mix(in srgb, var(--ink) 7%, transparent),
             0 16px 40px color-mix(in srgb, var(--ink) 10%, transparent);
  --lux-sh-3:0 24px 60px rgba(0,0,0,.18);
  --lux-sh-3:0 24px 60px color-mix(in srgb, var(--ink) 18%, transparent);

  --lux-ease:cubic-bezier(.2,.7,.3,1);
  --maxw:var(--guest-cover-max-width,760px);
}

/* ============================================================ ambience */
/* Two very soft light sources so the page has depth before any content lands.
   Both are derived from the host's own colours, so this works on any theme. */
body{
  background:
    radial-gradient(1100px 520px at 84% -10%, var(--accent-soft) 0%, transparent 58%),
    radial-gradient(880px 460px at 2% 2%, var(--bg-tint) 0%, transparent 56%),
    var(--bg);
  background-attachment:fixed;
}
@media (prefers-reduced-motion:no-preference){
  body{background-attachment:fixed}
}

/* ============================================================ header */
/* A quiet brand bar so the page reads as a product, not a bare form. */
.topbar{
  display:flex;align-items:center;gap:11px;
  padding:var(--s-4) var(--s-4) 0;
  max-width:var(--maxw);margin:0 auto;width:100%;
}
/* Brand mark and wordmark (see static/brand). Both are shipped at 2x their
   display size, so the browser never has to invent detail scaling them down. */
.topbar .mark-img{display:block;flex:none;width:30px;height:28px}
.topbar .wordmark-img{display:block;flex:none;width:143px;height:30px}
/* The mark and the wordmark together are one link home. inline-flex keeps the
   images on the bar's own baseline, and the hover is a dim rather than an
   underline, because it is a logo and not a word in a sentence. */
.topbar .brandlink{
  display:inline-flex;align-items:center;gap:11px;
  text-decoration:none;border-radius:8px;transition:opacity .18s;
}
.topbar .brandlink:hover{opacity:.72}
.topbar .brandlink:focus-visible{outline:2px solid var(--accent);outline-offset:3px}
.topbar b{font-size:.94rem;letter-spacing:-.01em;font-weight:700}
.topbar .live{
  margin-left:auto;display:inline-flex;align-items:center;gap:6px;
  font-size:.72rem;font-weight:650;color:var(--dim);
  background:var(--panel);border-radius:var(--radius-pill);
  padding:.32rem .7rem;box-shadow:var(--lux-sh-1);
}
.topbar .live i{
  width:6px;height:6px;border-radius:50%;background:var(--ok);display:block;
}

/* ============================================================ cards */
.card{
  background:var(--panel);
  border:0;                                  /* depth replaces the hairline */
  border-radius:var(--lux-r-lg);
  padding:calc(var(--s-5) + 4px);
  margin:var(--s-4) 0;
  box-shadow:var(--lux-sh-1);
}
.card.flat{box-shadow:var(--lux-sh-1)}

/* ============================================================ type */
.sub{font-size:var(--t-base)}
h2{letter-spacing:.08em}

/* ============================================================ forms */
input[type=text],input[type=email],input[type=date],input[type=password],
input[type=number],input[type=file],select{
  border:0;
  background:var(--bg-tint);
  border-radius:var(--radius-sm);
  padding:.85rem 1rem;
  box-shadow:inset 0 1px 2px rgba(0,0,0,.04);
}
input:focus,select:focus{
  border:0;
  box-shadow:0 0 0 3px var(--accent-soft), inset 0 1px 2px rgba(0,0,0,.04);
}

/* Buttons are flat rounded rectangles with centred content, not pills with an
   accent bloom. The bloom was the signature of the earlier direction; on a page
   whose point is the photography it read as decoration competing with the photo.
   The label sits beside its icon, so the box is a flex row. */
button,.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:9px;
  border-radius:12px;
  padding:.95rem var(--s-5);
  box-shadow:none;
  letter-spacing:.01em;
  transition:background .18s,transform .18s var(--lux-ease),box-shadow .18s;
}
button:hover,.btn:hover{transform:translateY(-1px)}
button:active,.btn:active{transform:translateY(0)}
.btn svg{flex:none}
.btn.ghost{
  border:1px solid var(--line);background:var(--panel);color:var(--ink);
}
.btn.ghost:hover{background:var(--panel-2);border-color:var(--dim)}
.btn.small{border-radius:10px;padding:.66rem var(--s-5);width:auto}

/* "Take a photo instead". A real alternative to handing over what is already on the
   phone, and half the point is catching the moment, so it stays. But it is text
   weight under the three choices rather than a fourth button competing with them. */
.snaprow{margin:calc(-1 * var(--s-3)) 0 var(--s-5);text-align:center}
.linkbtn{
  display:inline-flex;align-items:center;gap:7px;width:auto;
  margin:0;padding:.35rem .45rem;
  background:none;border:0;box-shadow:none;
  color:var(--dim);font:inherit;font-size:var(--t-sm);cursor:pointer;
  text-decoration:underline;text-underline-offset:3px;
  text-decoration-color:var(--line);
}
.linkbtn:hover{color:var(--ink);text-decoration-color:var(--dim)}

/* The upload surface. No card and no form in it: the progress and the tiles, and it
   does not exist at all until the guest has picked something, so the page opens as
   an album rather than as a form. */
.uploadbox{margin:0 0 var(--s-5)}
.uploadbox .upload-status{font-weight:600;line-height:1.6;margin:var(--s-3) 0}
.uploadbox .upload-actions{display:flex;flex-wrap:wrap;gap:8px;margin:var(--s-3) 0}
.uploadbox .upload-actions[hidden],.uploadbox .upload-actions [hidden],.uploadbox .upload-details[hidden]{display:none}
.uploadbox .upload-details{margin-top:var(--s-4);color:var(--dim)}
.uploadbox .upload-details summary{cursor:pointer;font-weight:600}
.uploadbox .upload-details #log{white-space:pre-wrap;overflow-wrap:anywhere;font-size:var(--t-xs)}
.uploadbox #grid .cell.failed{height:auto;min-height:150px;display:flex;flex-direction:column;justify-content:center;gap:8px;padding:12px}
.uploadbox #grid .cell.failed .badge,.uploadbox #grid .cell.failed .tilebtn{position:static;transform:none}
.uploadbox #grid .cell.failed .badge{background:none;color:var(--ink);overflow-wrap:anywhere;white-space:normal}
.uploadbox .upload-file-error{font-size:var(--t-xs);overflow-wrap:anywhere;margin:0}

/* The name, asked for UNDER the photos that are already going up rather than in
   front of them. Hidden while the guest has a name we already know. */
.wholine{margin:var(--s-4) 0 0}
.wholine label{
  display:block;margin:0 0 6px;
  font-size:var(--t-xs);color:var(--dim);font-weight:650;
  text-transform:uppercase;letter-spacing:.07em;
}
.whorow{display:flex;align-items:center;gap:8px}
.whorow input{flex:1 1 auto;min-width:0}
.whorow .btn{flex:0 0 auto;margin-top:0}

/* ============================================================ progress */
.bar{height:8px;box-shadow:inset 0 1px 2px rgba(0,0,0,.05)}
.bar > i{background:linear-gradient(90deg,var(--accent),var(--accent-hover))}

/* ============================================================ gallery */
.grid{gap:9px}
.grid .cell{
  border:0;
  border-radius:var(--radius-sm);
  box-shadow:0 2px 8px transparent;
  box-shadow:0 2px 8px color-mix(in srgb, var(--ink) 12%, transparent);
  transition:transform .22s var(--lux-ease),box-shadow .22s var(--lux-ease);
}
.grid a.cell:hover{
  transform:translateY(-3px) scale(1.015);
  box-shadow:var(--lux-sh-2);
  z-index:2;
}
.grid .cell .badge{
  background:linear-gradient(transparent,rgba(18,12,10,.78));
  padding:.35rem .5rem;
}
.grid .cell.pending{background:var(--panel);box-shadow:var(--lux-sh-1)}

/* A tile with no usable image at all (no thumbnail, and the album is not
   unlocked). A deliberate placeholder, not a broken-image icon. */
.grid .cell.nothumb{
  background:var(--bg-tint);
  display:grid;place-items:center;
  box-shadow:inset 0 0 0 1px var(--line-soft);
}
.grid .cell .ph{
  color:var(--dim);font-size:.68rem;font-weight:650;
  letter-spacing:.06em;text-transform:uppercase;
}

/* ============================================================ hero */
#hero.hero{
  position:relative;overflow:hidden;
  border-radius:var(--radius);
  height:230px;
  box-shadow:var(--lux-sh-2);
  margin:var(--s-4) 0 0;
}
#hero.hero img{width:100%;height:100%;object-fit:cover;display:block}
#hero.hero .cap{
  position:absolute;left:0;right:0;bottom:0;
  padding:var(--s-6) var(--s-5) var(--s-4);
  background:linear-gradient(transparent,rgba(18,12,10,.72));
  color:#fff;
}
#hero.hero .cap h1{margin:0 0 .15rem;color:#fff;font-size:var(--t-3xl)}
#hero.hero .cap .sub{color:rgba(255,255,255,.9);margin:0;font-size:var(--t-sm)}

/* ============================================================ guestbook */
/* Written notes and voice messages share one list. A voice note is a real
   object in R2 like a photo, so it reuses the same moderation status.
   The .gbmsg / .bub / .voice vocabulary itself lives in features.css, which the
   dashboard loads too: it is rendered on two pages, so it cannot live in a
   stylesheet only one of them loads. */
.gb{display:flex;flex-direction:column;gap:var(--s-4);margin-top:var(--s-3)}

/* recording affordance */
.rec{
  display:inline-flex;align-items:center;gap:9px;
  padding:.62rem 1.1rem;border-radius:var(--radius-pill);
  background:var(--panel);box-shadow:var(--lux-sh-1);
  cursor:pointer;border:0;width:auto;margin-top:var(--s-2);
  font-size:var(--t-sm);font-weight:650;color:var(--ink);
}
.rec:hover{box-shadow:var(--lux-sh-2)}
.rec .dot{
  width:9px;height:9px;border-radius:50%;background:var(--danger);flex:none;
}
.rec.on .dot{animation:luxblink 1s ease-in-out infinite}
@keyframes luxblink{0%,100%{opacity:1}50%{opacity:.25}}

/* ============================================================ likes */
.like{
  display:inline-flex;align-items:center;gap:6px;
  background:var(--panel);border:0;border-radius:var(--radius-pill);
  padding:.34rem .74rem;font-size:.72rem;font-weight:650;color:var(--dim);
  cursor:pointer;width:auto;margin:0;box-shadow:var(--lux-sh-1);
  transition:transform .16s var(--lux-ease),color .16s;
}
.like:hover{transform:translateY(-1px);color:var(--accent-text)}
.like[aria-pressed="true"]{color:var(--accent-text);background:var(--accent-soft)}
.like[aria-pressed="true"] .h{transform:scale(1.12)}
.like .h{display:block;transition:transform .16s var(--lux-ease)}

/* ============================================================ misc */
.pill{
  background:var(--accent-soft);color:var(--accent-text);
  font-weight:700;border-radius:var(--radius-pill);
  padding:.14rem .5rem;font-size:.72rem;
}
/* No padding-bottom:80px any more. It was there to clear the floating "Add photos"
   bar that followed a guest down the page, and that bar is gone. It applied to
   EVERY .foot on every page that loads this file - the landing page, the start
   page and the guest album - so it left 80px of empty space under the last line of
   all three footers. .wrap already ends with --s-7. */
.foot{color:var(--dim);font-size:var(--t-sm);text-align:center}
.log{background:var(--bg-tint);border-radius:var(--radius-sm);border:0}
.qr{border-radius:var(--radius-sm)}

/* ======================================================= guest album page
   upload.html only. Scoped to .guestpage so the storefront and the start page,
   which also load this file and still have a header, are untouched. */

/* No top bar on the guest page: the cover runs to the top edge and to the full
   width of the column, so the photograph is the first thing a guest sees. */
body.guestpage .wrap{padding-top:0}
body.guestpage #hero.hero{
  margin:0 calc(-1 * var(--s-4));
  border-radius:0;
  box-shadow:none;
}

/* The header block is centred, which is what makes the page read as an
   invitation rather than a form heading. */
body.guestpage #head{text-align:center;margin:var(--s-5) 0 var(--s-5)}
#head .sub{margin:0}

/* The page's own three choices, stacked and centred on the page rather than boxed
   inside a form. Same button geometry as the form's, one column. */
.guestacts{display:grid;gap:10px;margin:0 0 var(--s-5)}
.guestacts .btn{margin-top:0}
.guest-opening-note summary{list-style:none;cursor:pointer}
.guest-opening-note summary::-webkit-details-marker{display:none}
.guest-opening-note p{margin:10px 0 0;color:var(--dim);font-size:var(--t-sm)}

/* Taller than wide. It is what makes the album read as a set of photographs rather
   than a contact sheet, and both grids on the page share the shape so the upload
   queue and the album do not change tile size under the guest. */
#grid .cell,#ggrid .cell{aspect-ratio:1/1.18}

/* Two larger tiles per row on a phone instead of three small ones. Scoped to the
   guest page's two grids (#grid is the upload queue, #ggrid the album) so the
   host's dashboard keeps its own density. */
#grid,#ggrid{grid-template-columns:repeat(auto-fill,minmax(150px,1fr))}

/* An album's sections are titles, not field labels, so the card headings are the
   display serif rather than tracked micro-caps. */
body.guestpage #gallerycard h2,body.guestpage #gbcard h2{
  font-family:var(--font-display);font-size:var(--t-2xl);font-weight:400;
  text-transform:none;letter-spacing:.005em;color:var(--ink);
  margin:0 0 var(--s-3);line-height:1.2;
}

/* The brand lockup at the foot of the page is part of the SHARED footer now, so
   its rules live in style.css with the rest of that block. Only the storefront and
   the guest album load this file, and the pages that needed the way home most - the
   dashboard, "Your albums" - never did, so a rule here was a logo everywhere for
   them but nowhere. */

@media(max-width:520px){
  :root{--radius:19px;--lux-r-lg:22px;--maxw:100%}
  .card{padding:var(--s-5)}
  #hero.hero{height:200px}
  .grid{grid-template-columns:repeat(auto-fill,minmax(88px,1fr));gap:7px}
  /* The ids beat this file's own .grid rule above, so the guest page keeps two
     larger tiles per row even at the narrow breakpoint. */
  #grid,#ggrid{grid-template-columns:repeat(auto-fill,minmax(134px,1fr));gap:10px}
}
