
/* The download screen: the moment just after someone has paid.
   It is a handover, so it is built to reassure first and act second. The
   receipt strip answers "did that work?" before the eye reaches the photos,
   and every tile is a single large target that says what it does. */
.receipt {
  /* Flex, not a fixed column count: a card order carries no reference, so the
     strip has two cells rather than three and a fixed grid left an empty panel
     hanging off the end. The cells divide whatever is there. */
  display: flex; flex-direction: column; gap: 1px;
  background: var(--color-line);
  border: 1px solid var(--color-line);
  border-radius: 12px;
  overflow: hidden;
}
@media (min-width: 560px) { .receipt { flex-direction: row; } }
.receipt__cell {
  flex: 1 1 0; min-width: 0;
  background: var(--color-surface); padding: 1rem 1.15rem;
  display: flex; flex-direction: column; gap: .3rem;
}
.receipt__k {
  font-size: .68rem; font-weight: 600; letter-spacing: .14em;
  text-transform: uppercase; color: var(--color-muted);
}
.receipt__v { font-family: var(--font-display); font-size: 1.05rem; font-weight: 600; font-variant-numeric: tabular-nums; }

.dl-grid { display: grid; gap: 1rem; grid-template-columns: repeat(2, 1fr); }
@media (min-width: 640px) { .dl-grid { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 1024px) { .dl-grid { grid-template-columns: repeat(4, 1fr); } }

.dl {
  border: 1px solid var(--color-line);
  border-radius: 10px; overflow: hidden;
  background: var(--color-surface);
}
.dl:focus-within { outline: 2px solid var(--color-accent); outline-offset: 2px; }
.dl a { display: block; color: inherit; text-decoration: none; }
.dl__frame { position: relative; display: block; aspect-ratio: 4 / 5; overflow: hidden; background: var(--color-line); }
.dl__frame img { display: block; width: 100%; height: 100%; object-fit: cover; }
/* A quiet index so a buyer working through twenty photos can keep their place.
   It is a label, not a control: the old "Download 1" made an index look like
   the name of the action. */
.dl__index {
  position: absolute; top: .4rem; left: .4rem;
  min-width: 1.35rem; height: 1.35rem; padding: 0 .3rem;
  display: grid; place-items: center;
  border-radius: 4px; font-size: .7rem; font-weight: 600;
  font-variant-numeric: tabular-nums;
  background: rgba(20, 19, 16, .72); color: var(--color-text);
  backdrop-filter: blur(4px);
}
.dl__action {
  display: flex; align-items: center; justify-content: center; gap: .4rem;
  min-height: 46px; padding: 0 .6rem;
  font-size: .88rem; font-weight: 600;
  border-top: 1px solid var(--color-line);
  color: var(--color-accent);
}
.dl__action svg { width: 15px; height: 15px; flex: none; }
.dl a:hover .dl__action { background: var(--color-accent); color: var(--color-ink); border-top-color: var(--color-accent); }

/* The remainder Tailwind cannot emit.
   Every Worker class now compiles via layouts/partials/tailwind-safelist.html,
   with one exception: bracketed arbitrary values and fractional scale steps
   (aspect-[4/5], min-h-[44px], h-1.5, tracking-[0.2em]) are present in
   hugo_stats.json but do not survive its JSON scan. Rather than leave them to
   fail silently a fourth time, they are real rules with real names. */
.photo-tile { aspect-ratio: 4 / 5; }
.wordmark { letter-spacing: .2em; }
.wordmark-dot { display: inline-block; width: .375rem; height: .375rem; background: var(--color-accent); }
.tap { display: inline-flex; align-items: center; min-height: 44px; }
.h-tight { letter-spacing: -.01em; }
.ref-code { letter-spacing: .06em; font-variant-numeric: tabular-nums; }

/* Event cards on the store index.
   Written here rather than as Tailwind utilities because this markup lives in
   the Worker, which Hugo does not scan: see the note in assets/css/main.css. */
.ecards { display: grid; gap: .75rem; grid-template-columns: 1fr; }
@media (min-width: 640px) { .ecards { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) { .ecards { grid-template-columns: repeat(3, 1fr); } }

.ecard {
  border: 1px solid var(--color-line);
  background: var(--color-surface);
  border-radius: 12px;
  overflow: hidden;
}
.ecard a { display: block; color: inherit; text-decoration: none; }
.ecard:focus-within { outline: 2px solid var(--color-accent); outline-offset: 2px; }

/* Fixed 4:3, image cropped to fill. Her library is near half landscape and half
   portrait, so honouring each frame's own shape would give a ragged grid. */
.ecard__frame { aspect-ratio: 4 / 3; overflow: hidden; background: var(--color-line); }
.ecard__frame img { display: block; width: 100%; height: 100%; object-fit: cover; }
@media (prefers-reduced-motion: no-preference) {
  .ecard__frame img { transition: transform .5s ease; }
  .ecard:hover .ecard__frame img { transform: scale(1.04); }
}

.ecard__body { padding: 1rem; }
@media (min-width: 640px) { .ecard__body { padding: 1.15rem; } }
.ecard__title { font-family: var(--font-display); font-size: 1.15rem; font-weight: 600; line-height: 1.25; }
.ecard__meta { margin-top: .25rem; font-size: .875rem; color: var(--color-muted); }

/* Selection state on a gallery tile. */
.tile label { position: relative; display: block; }
.tile input[data-pick]:checked ~ img { outline: 3px solid var(--color-accent); outline-offset: -3px; }
.tile .pick-badge {
  position: absolute; top: .5rem; right: .5rem; width: 28px; height: 28px;
  border-radius: 999px; border: 2px solid rgba(244,241,234,.7); background: rgba(20,19,16,.45);
  display: grid; place-items: center; pointer-events: none;
}
.tile input[data-pick]:checked ~ .pick-badge {
  background: var(--color-accent); border-color: var(--color-accent);
}
.tile input[data-pick]:checked ~ .pick-badge::after {
  content: ""; width: 9px; height: 15px; margin-top: -4px;
  border: solid var(--color-ink); border-width: 0 3px 3px 0; transform: rotate(45deg);
}
.tile input[data-pick]:focus-visible ~ img { outline: 3px solid var(--color-accent); outline-offset: 2px; }

/* Sticky purchase bar. */
.cartbar {
  position: fixed; inset: auto 0 0 0; z-index: 60;
  background: var(--color-surface); border-top: 1px solid var(--color-line);
  padding: .75rem 1.25rem calc(.75rem + env(safe-area-inset-bottom));
}
.cartbar__inner {
  margin: 0 auto; max-width: 72rem;
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
}
.cartbar__count { font-weight: 600; }
.cartbar__nudge {
  margin: .5rem auto 0; max-width: 72rem;
  font-size: .85rem; color: var(--color-accent); font-weight: 600;
}

/* --- Admin -------------------------------------------------------------
   Phone-first: Emma uploads from the sideline. Every control is a thumb
   target, primary actions are full-width, and 16px inputs stop iOS Safari
   zooming the page on focus. */
.afield {
  width: 100%; min-height: 48px; font-size: 1rem; border-radius: 8px;
  padding: .7rem .8rem; font-family: var(--font-body);
  background: var(--color-bg); color: var(--color-text);
  border: 1px solid var(--color-line-strong);
}
.afield:focus { outline: 2px solid var(--color-accent); outline-offset: 2px; }

.admin__body { margin: 0 auto; max-width: 46rem; padding: 0 1.25rem 6rem; }
.admin-topbar { margin: 0 auto; max-width: 46rem; padding: 1rem 1.25rem 0; }
.admin-back {
  display: inline-flex; align-items: center; min-height: 44px;
  color: var(--color-muted); font-weight: 600;
}
.admin-back:hover { color: var(--color-text); }
.admin-h2 { font-family: var(--font-display); font-size: 1.15rem; font-weight: 600; margin: 2rem 0 .75rem; }
.admin-h2--flush { margin-top: 0; }
.admin-hint { color: var(--color-muted); font-size: .9rem; margin-bottom: 1rem; line-height: 1.5; }
.admin-empty { color: var(--color-muted); padding: 1.5rem 0; }
.admin-mt { margin-top: .6rem; }
.admin-mt-lg { margin-top: 2.5rem; }
.admin-danger { border: 1px solid var(--color-accent); color: var(--color-accent); background: none; }
.admin-danger:hover { background: var(--color-accent); color: var(--color-ink); }
.admin-code { word-break: break-all; font-size: .8rem; color: var(--color-text); }

.admin-card {
  border: 1px solid var(--color-line); border-radius: 12px;
  background: var(--color-surface); padding: 1.25rem; margin-bottom: 1.25rem;
}
.admin-card__summary {
  display: flex; align-items: center; justify-content: space-between;
  min-height: 44px; cursor: pointer; font-weight: 600; list-style: none;
}
.admin-card__summary::-webkit-details-marker { display: none; }
.admin-card__chev { color: var(--color-accent); font-size: 1.5rem; line-height: 1; }
details[open] .admin-card__chev { transform: rotate(45deg); }
.admin-form { display: grid; gap: .5rem; margin-top: 1rem; }
.admin-label { font-size: .85rem; font-weight: 600; margin-top: .5rem; }
.admin-btn-wide { width: 100%; margin-top: 1rem; }
/* A disabled primary button must not look tappable, or every tap that does
   nothing reads as the page being broken. */
.btn:disabled, .btn[disabled] { opacity: .45; cursor: not-allowed; }

/* Big, obvious file picker — the main thing she taps. */
.admin-file { display: block; }
.admin-file input { position: absolute; width: 1px; height: 1px; opacity: 0; }
.admin-file__face {
  display: grid; place-items: center; min-height: 96px; cursor: pointer;
  border: 2px dashed var(--color-line-strong); border-radius: 12px;
  font-weight: 600; color: var(--color-text); text-align: center; padding: 1rem;
}
.admin-file__face:hover { border-color: var(--color-accent); }
.admin-file input:focus-visible + .admin-file__face { outline: 2px solid var(--color-accent); outline-offset: 2px; }

.admin-progress { height: 6px; border-radius: 999px; background: var(--color-line); overflow: hidden; margin-top: 1rem; }
.admin-progress > div { height: 100%; width: 0; background: var(--color-accent); transition: width .2s; }
.admin-status { margin-top: .75rem; font-size: .9rem; color: var(--color-muted); }
.admin-failures { margin-top: .5rem; display: grid; gap: .35rem; font-size: .85rem; color: var(--color-accent); }

.admin-requests {
  border: 2px solid var(--color-accent); border-radius: 12px;
  background: var(--color-surface); padding: 1.25rem; margin-bottom: 1.25rem;
}
.admin-requests__acts { display: flex; gap: .4rem; flex-wrap: wrap; }

.admin-setup {
  border: 1px solid var(--color-accent); border-radius: 12px;
  background: var(--color-surface); padding: 1.25rem; margin-bottom: 1.25rem;
}
.admin-setup__list { display: grid; gap: .75rem; margin-top: .25rem; }
.admin-setup__list li { display: grid; grid-template-columns: 1.5rem 1fr; align-items: start; gap: .5rem; }
.admin-setup__mark {
  display: grid; place-items: center; width: 1.15rem; height: 1.15rem; margin-top: .15rem;
  border-radius: 999px; border: 2px solid var(--color-line-strong); font-size: .7rem; color: var(--color-ink);
}
.admin-setup__list .is-done .admin-setup__mark { background: var(--color-accent); border-color: var(--color-accent); }
.admin-setup__list .is-done .admin-setup__label { color: var(--color-muted); }
.admin-setup__label { display: block; font-weight: 600; }
.admin-setup__hint { display: block; margin-top: .15rem; font-size: .85rem; color: var(--color-muted); }

.admin-list { display: grid; gap: .5rem; }
.admin-row {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  min-height: 64px; padding: .85rem 1rem; border-radius: 10px;
  border: 1px solid var(--color-line); background: var(--color-surface);
}
.admin-row:hover { border-color: var(--color-line-strong); }
.admin-row__main { display: grid; gap: .15rem; min-width: 0; }
.admin-row__title { font-weight: 600; color: var(--color-text); }
.admin-row__meta { font-size: .85rem; color: var(--color-muted); }
.admin-pill {
  flex: none; font-size: .7rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  padding: .3rem .6rem; border-radius: 999px;
  border: 1px solid var(--color-line-strong); color: var(--color-muted);
}
.admin-pill--live { background: var(--color-accent); border-color: var(--color-accent); color: var(--color-ink); }

.admin-alert { border-radius: 10px; padding: .85rem 1rem; font-size: .9rem; font-weight: 600; margin-bottom: 1rem; }
.admin-alert--bad { border: 2px solid var(--color-accent); color: var(--color-accent); background: var(--color-surface); }
.admin-alert--good { border: 1px solid var(--color-line-strong); color: var(--color-text); background: var(--color-surface); }
.admin-alert[hidden] { display: none; }

.admin-orders { display: grid; gap: .75rem; }
.admin-order { border: 1px solid var(--color-line); border-radius: 10px; background: var(--color-surface); padding: 1rem; }
.admin-order__top { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; }
.admin-order__who { font-weight: 600; word-break: break-all; }
.admin-order__amt { font-family: var(--font-display); font-weight: 600; flex: none; }
.admin-order__meta { margin-top: .25rem; font-size: .85rem; color: var(--color-muted); }
.admin-order__expired { color: var(--color-accent); font-weight: 600; }
.admin-order__link { display: grid; gap: .5rem; margin-top: .75rem; }
.admin-order__link input { font-size: .8rem; }

/* Copy and "New link" sit side by side and must share the row evenly.
   Copy is a bare button while "New link" is wrapped in a form, so giving
   only the form flex:1 let Copy's width:100% crush its neighbour into a
   one-letter-per-line column on a phone. Both children flex, so neither
   can starve the other. */
.admin-order__acts { display: flex; gap: .5rem; }
.admin-order__acts > * { flex: 1 1 0; min-width: 0; }
.admin-order__acts .btn { width: 100%; }

.admin-photos { display: grid; grid-template-columns: repeat(2, 1fr); gap: .6rem; }

@media (min-width: 560px) {
  .admin-order__link { grid-template-columns: 1fr auto; align-items: center; }
  .admin-order__acts > * { flex: none; }
  .admin-photos { grid-template-columns: repeat(3, 1fr); }
}
@media (min-width: 860px) {
  .admin-photos { grid-template-columns: repeat(4, 1fr); }
}
.admin-photo { position: relative; border-radius: 8px; overflow: hidden; background: var(--color-surface); }
.admin-photo img { display: block; width: 100%; height: 100%; object-fit: cover; aspect-ratio: 4/5; }
.admin-photo.is-cover { outline: 2px solid var(--color-accent); outline-offset: -2px; }
.admin-photo__cover {
  /* Top of the tile, opposite the delete button at the bottom, so the two
     cannot be confused by a thumb travelling up the grid. */
  position: absolute; top: .4rem; left: .4rem;
  display: inline-flex; align-items: center; min-height: 32px;
  padding: 0 .55rem; border-radius: 4px;
  font-size: .74rem; font-weight: 600; line-height: 1;
  border: 0; cursor: pointer;
  background: rgba(20, 19, 16, .78); color: var(--color-text);
  backdrop-filter: blur(4px);
}
.admin-photo__cover.is-cover {
  background: var(--color-accent); color: var(--color-ink); cursor: default;
}
.admin-photo__cover:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }

.admin-photo__del {
  /* 44px, the standard touch target. Safe to make this big because the
     first tap only arms it: the label becomes "Really delete?" and a
     second tap is required. */
  position: absolute; inset: auto 0 0 0; min-height: 44px;
  background: rgba(20,19,16,.82); color: var(--color-text);
  font-size: .8rem; font-weight: 600; border: 0; cursor: pointer;
}
.admin-photo__del:hover { background: var(--color-accent); color: var(--color-ink); }
