// Card renderers — one per card.kind
const { useState } = React;

const FlipHint = ({ onClick, label = 'More' }) => (
  <div
    className="flip-hint"
    onPointerDown={(e) => { e.stopPropagation(); }}
    onClick={(e) => { e.stopPropagation(); e.preventDefault(); onClick && onClick(); }}
  >
    <span>{label}</span>
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5">
      <path d="M21 2v6h-6M3 12a9 9 0 0 1 15-6.7L21 8"/>
      <path d="M3 22v-6h6M21 12a9 9 0 0 1-15 6.7L3 16"/>
    </svg>
  </div>
);

const CardMeta = ({ onFlip }) => (
  <div className="card-meta">
    <span />
    {onFlip && <FlipHint onClick={onFlip} label="Flip" />}
  </div>
);

const formatCoord = (v, posSuffix, negSuffix) => {
  if (typeof v !== 'number' || !isFinite(v)) return '';
  return `${Math.abs(v).toFixed(2)}° ${v >= 0 ? posSuffix : negSuffix}`;
};

const buildLocationLabel = ({ userLoc, userPlace, fallback }) => {
  if (userLoc && typeof userLoc.lat === 'number' && typeof userLoc.lon === 'number') {
    const lat = formatCoord(userLoc.lat, 'N', 'S');
    const lon = formatCoord(userLoc.lon, 'E', 'W');
    // Prefer the reverse-geocoded place name; fall back to "your location"
    // for a real fix that hasn't resolved a city yet, or to the JSON's
    // baked-in label (Edinburgh) when geolocation is denied/unavailable.
    let name;
    if (userLoc.label === 'you') {
      name = (userPlace && userPlace !== 'your location') ? userPlace : 'your location';
    } else {
      name = userLoc.label || 'Edinburgh';
    }
    return `${lat} · ${lon} — ${name}`;
  }
  return fallback || '';
};

const HeroCard = ({ card, num, total, onFlip, userLoc, userPlace }) => {
  const roles = Array.isArray(card.roles) ? card.roles : [];
  const legend = Array.isArray(card.legend) ? card.legend : [];
  const locationLabel = buildLocationLabel({ userLoc, userPlace, fallback: card.location });
  return (
    <>
      <div
        className="hero-top"
        role={card.image ? 'img' : undefined}
        aria-label={card.image ? 'Portrait of James Varga' : undefined}
        style={card.image ? { backgroundImage: `url(${card.image})`, backgroundSize: 'cover', backgroundPosition: 'center 20%' } : undefined}
      >
        {!card.image && (
          <div className="hero-photo">
            <div className="hero-initials">jv</div>
          </div>
        )}
        {card.image && <div className="hero-scrim" />}
        {card.url && (
          <div className="hero-meta-bar">
            <span>{card.url}</span>
          </div>
        )}
        {locationLabel && <div className="hero-location">{locationLabel}</div>}
      </div>
      <div className="hero-bottom">
        {card.name && <h1 className="hero-name">{card.name}</h1>}
        {card.subtitle && <div className="hero-sub">{card.subtitle}</div>}

        {roles.length > 0 && (
          <ul className="hero-roles">
            {roles.map((r, i) => <li key={i}>{r}</li>)}
          </ul>
        )}

        {legend.length > 0 && (
          <div className="hero-legend" role="list" aria-label="Profile sections">
            {legend.map((row, i) => (
              <div key={i} className="legend-row" role="listitem">
                <span className="legend-sym" aria-hidden="true">{row.sym}</span>
                <span className="legend-val">{row.val}</span>
                <span className="legend-hint">{row.hint}</span>
              </div>
            ))}
          </div>
        )}
      </div>
    </>
  );
};

const BioCard = ({ card, num, total, onFlip }) => (
  <>
    <CardMeta onFlip={onFlip} />
    <div className="card-eyebrow">{card.eyebrow}</div>
    <h2 className="card-title">{card.title}</h2>
    <div className="card-scroll">
      <p className="card-lede">{card.lede}</p>
      <div className="stats">
        {card.stats.map((s, i) => (
          <div key={i}>
            <div className="stat-num">{s.num}</div>
            <div className="stat-label">{s.label}</div>
          </div>
        ))}
      </div>
    </div>
  </>
);

const FeatureEyebrow = ({ eyebrow, websiteLink }) => {
  if (!websiteLink) return <div className="card-eyebrow">{eyebrow}</div>;
  const stop = (e) => e.stopPropagation();
  return (
    <div className="card-eyebrow-row">
      <a
        className="card-eyebrow card-eyebrow-link"
        href={websiteLink.href}
        target="_blank"
        rel="noopener noreferrer"
        onClick={stop}
        onPointerDown={stop}
      >
        {eyebrow}
      </a>
      <a
        className="card-domain"
        href={websiteLink.href}
        target="_blank"
        rel="noopener noreferrer"
        onClick={stop}
        onPointerDown={stop}
        title={`Open ${websiteLink.value} in a new window`}
      >
        <span>{websiteLink.value}</span>
        <svg viewBox="0 0 24 24" width="11" height="11" fill="none" stroke="currentColor" strokeWidth="1.6" aria-hidden="true">
          <path d="M14 5h5v5M19 5L10 14M5 9v10h10" />
        </svg>
      </a>
    </div>
  );
};

const FeatureCard = ({ card, num, total, onFlip }) => {
  const websiteLink = card.hideFrontLink
    ? null
    : (card.back?.links || []).find(l => l.label === 'website') || null;
  if (card.imageFullBleed && card.image) {
    return (
      <>
        <div className="card-image-fullbleed" style={{ '--card-image': `url(${card.image})` }} />
        <CardMeta onFlip={onFlip} />
        <div className="card-body-pad">
          <FeatureEyebrow eyebrow={card.eyebrow} websiteLink={websiteLink} />
          <h2 className="card-title">{card.title}</h2>
          <div className="card-scroll">
            <p className="card-lede">{card.lede}</p>
            {card.stats && (
              <div className="stats">
                {card.stats.map((s, i) => (
                  <div key={i}>
                    <div className="stat-num">{s.num}</div>
                    <div className="stat-label">{s.label}</div>
                  </div>
                ))}
              </div>
            )}
            {card.chips && (
              <div className="chips">
                {card.chips.map((c, i) => <span key={i} className={"chip" + (i===0?' accent':'')}>{c}</span>)}
              </div>
            )}
          </div>
        </div>
      </>
    );
  }
  return (
  <>
    <CardMeta onFlip={onFlip} />
    {card.image && (
      <div className="card-image" style={{ backgroundImage: `url(${card.image})` }}>
        <div className="card-image-scrim" />
      </div>
    )}
    <FeatureEyebrow eyebrow={card.eyebrow} websiteLink={websiteLink} />
    <h2 className="card-title">{card.title}</h2>
    <div className="card-scroll">
      <p className="card-lede">{card.lede}</p>
      {card.stats && (
        <div className="stats">
          {card.stats.map((s, i) => (
            <div key={i}>
              <div className="stat-num">{s.num}</div>
              <div className="stat-label">{s.label}</div>
            </div>
          ))}
        </div>
      )}
      {card.chips && (
        <div className="chips">
          {card.chips.map((c, i) => <span key={i} className={"chip" + (i===0?' accent':'')}>{c}</span>)}
        </div>
      )}
    </div>
  </>
  );
};

const NowItem = ({ it }) => (
  <div className="now-item">
    <div className={"now-marker" + (it.active === false ? ' ghost' : '')} />
    <div className="now-text">{it.text}<em>{it.sub}</em></div>
  </div>
);

const NowCard = ({ card, num, total, onFlip }) => {
  const groups = Array.isArray(card.groups) ? card.groups : null;
  const flatItems = Array.isArray(card.items) ? card.items : null;
  return (
    <>
      <CardMeta onFlip={onFlip} />
      <div className="card-eyebrow">{card.eyebrow}</div>
      <h2 className="card-title">{card.title}</h2>
      <div className="card-scroll">
        {groups
          ? groups.map((g, gi) => (
              <div key={gi} className="card-group">
                {g.label && <div className="card-group-label">{g.label}</div>}
                <div className="now-list">
                  {g.items.map((it, i) => <NowItem key={i} it={it} />)}
                </div>
              </div>
            ))
          : flatItems && (
              <div className="now-list">
                {flatItems.map((it, i) => <NowItem key={i} it={it} />)}
              </div>
            )
        }
      </div>
    </>
  );
};

const VentureRow = ({ v }) => (
  <div className="venture-row">
    <div>
      <div className="venture-name">{v.name}</div>
      <div className="venture-desc">{v.desc}</div>
    </div>
    <div className="venture-year">{v.year}</div>
  </div>
);

const HistoryCard = ({ card, num, total, onFlip }) => {
  const groups = Array.isArray(card.groups) ? card.groups : null;
  const flatVentures = Array.isArray(card.ventures) ? card.ventures : null;
  return (
    <>
      <CardMeta onFlip={onFlip} />
      <div className="card-eyebrow">{card.eyebrow}</div>
      <h2 className="card-title">{card.title}</h2>
      {card.lede && <p className="card-lede">{card.lede}</p>}
      <div className="card-scroll">
        {groups
          ? groups.map((g, gi) => (
              <div key={gi} className="card-group">
                {g.label && <div className="card-group-label">{g.label}</div>}
                <div className="venture-list">
                  {(g.ventures || []).map((v, i) => <VentureRow key={i} v={v} />)}
                </div>
              </div>
            ))
          : flatVentures && (
              <div className="venture-list">
                {flatVentures.map((v, i) => <VentureRow key={i} v={v} />)}
              </div>
            )
        }
      </div>
    </>
  );
};

const AdvisoryCard = ({ card, num, total, onFlip }) => (
  <>
    <CardMeta onFlip={onFlip} />
    <div className="card-eyebrow">{card.eyebrow}</div>
    <h2 className="card-title">{card.title}</h2>
    {card.lede && <p className="card-lede">{card.lede}</p>}
    <div className="card-scroll">
      {Array.isArray(card.types) && card.types.length > 0 && (
        <div className="types-list">
          {card.types.map((t, i) => (
            <div key={i} className="type-row">
              <div className="type-label">{t.label}</div>
              <div className="type-desc">{t.desc}</div>
            </div>
          ))}
        </div>
      )}
      {card.pullquote && (
        <figure className="pullquote">
          <blockquote className="pullquote-text">&ldquo;{card.pullquote.text}&rdquo;</blockquote>
          <figcaption className="pullquote-attr">&mdash; {card.pullquote.attr}</figcaption>
        </figure>
      )}
      {card.brings && Array.isArray(card.brings.items) && (
        <div className="brings">
          <div className="brings-header">{card.brings.header || 'What I bring'}</div>
          <ul className="brings-list">
            {card.brings.items.map((it, i) => (
              <li key={i}>{it}</li>
            ))}
          </ul>
        </div>
      )}
      {Array.isArray(card.principles) && card.principles.length > 0 && (
        <div className="principles">
          {card.principles.map((p, i) => (
            <div key={i} className="principle">
              <div className="principle-num">0{i+1}</div>
              <div className="principle-text">{p}</div>
            </div>
          ))}
        </div>
      )}
    </div>
  </>
);

const EcosystemCard = ({ card, num, total, onFlip }) => (
  <>
    <CardMeta onFlip={onFlip} />
    <div className="card-eyebrow">{card.eyebrow}</div>
    <h2 className="card-title">{card.title}</h2>
    <p className="card-lede">{card.lede}</p>
    <div className="card-scroll">
      <div className="chips">
        {card.chips.map((c, i) => <span key={i} className="chip">{c}</span>)}
      </div>
    </div>
  </>
);

const QuoteCard = ({ card, num, total, onFlip }) => (
  <>
    <CardMeta onFlip={onFlip} />
    <div className="quote-mark">&ldquo;</div>
    <p className="quote-body">{card.body}</p>
    <div className="quote-attr">— {card.attr}</div>
  </>
);

// Gallery card: a featured set on the front; lightbox opens on click.

const GalleryCard = ({ card, num, total, onFlip, onOpenLightbox }) => {
  // If fieldNotes are loaded, build the cells from featured entries.
  // Otherwise fall back to the hard-coded card.cells (placeholders).
  const notes = card.fieldNotes && card.fieldNotes.length ? card.fieldNotes : null;
  const featured = notes ? notes.filter(n => n.featured) : null;
  const cells = featured && featured.length
    ? featured.slice(0, 5).map(n => ({
        label: n.caption,
        span: n.span,
        note: n,
      }))
    : card.cells.map(c => ({ ...c, note: null }));
  // The lightbox always opens the full list when available.
  const lightboxImages = notes || (card.cells || []).map(c => ({
    url: c.image, caption: c.label, fallback: null
  }));

  const handleCellActivate = (e, cellNote, cellIndex) => {
    e.stopPropagation();
    if (!onOpenLightbox) return;
    // Find this image's position in the full list
    const idx = cellNote
      ? lightboxImages.findIndex(img => img.url === cellNote.url || img.src === cellNote.src)
      : cellIndex;
    onOpenLightbox(lightboxImages, Math.max(0, idx));
  };

  return (
    <>
      <CardMeta onFlip={onFlip} />
      <div className="card-eyebrow">{card.eyebrow}</div>
      <h2 className="card-title" style={{fontSize: 'calc(32px * var(--density))', marginBottom: '16px'}}>{card.title}</h2>
      <div className="gallery-grid">
        {cells.map((c, i) => {
          const img = c.note ? (c.note.url || c.note.fallback) : c.image;
          return (
            <div
              key={i}
              className={"gallery-cell" + (c.span === 'tall' ? ' tall' : '')}
              style={img ? { backgroundImage: `url(${img})`, backgroundSize: 'cover', backgroundPosition: 'center', cursor: 'zoom-in' } : { cursor: 'zoom-in' }}
              onClick={(e) => handleCellActivate(e, c.note, i)}
              onKeyDown={(e) => {
                if (e.key === 'Enter' || e.key === ' ') {
                  e.preventDefault();
                  handleCellActivate(e, c.note, i);
                }
              }}
              role="button"
              tabIndex={0}
              aria-label={`Open ${c.label}`}
            >
              {img && <div className="gallery-cell-scrim" />}
              <div className="gallery-cell-label">{c.label}</div>
            </div>
          );
        })}
      </div>
    </>
  );
};

// Lightbox: full-screen image viewer with prev/next + keyboard nav
const Lightbox = ({ images, index, onIndex, onClose }) => {
  const [failed, setFailed] = React.useState({});
  const current = images[index];
  const primarySrc = current && (current.url || current.fallback);
  const key = primarySrc || String(index);
  const go = React.useCallback((delta) => {
    const next = (index + delta + images.length) % images.length;
    onIndex(next);
  }, [index, images.length, onIndex]);
  React.useEffect(() => {
    const onKey = (e) => {
      if (e.key === 'Escape') onClose();
      else if (e.key === 'ArrowRight') go(1);
      else if (e.key === 'ArrowLeft') go(-1);
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [go, onClose]);
  if (!current) return null;
  const src = failed[key] && current.fallback ? current.fallback : primarySrc;
  return (
    <div className="lightbox-overlay" onClick={onClose} role="dialog" aria-modal="true" aria-label={current.caption || 'Image'}>
      <button className="lightbox-close" onClick={(e) => { e.stopPropagation(); onClose(); }} aria-label="Close">
        <svg viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" strokeWidth="1.5"><path d="M6 6l12 12M18 6L6 18"/></svg>
      </button>
      <button className="lightbox-nav prev" onClick={(e) => { e.stopPropagation(); go(-1); }} aria-label="Previous">
        <svg viewBox="0 0 24 24" width="28" height="28" fill="none" stroke="currentColor" strokeWidth="1.5"><path d="M15 6l-6 6 6 6"/></svg>
      </button>
      <div className="lightbox-stage" onClick={(e) => e.stopPropagation()}>
        <img
          className="lightbox-image"
          src={src}
          alt={current.caption || ''}
          onError={() => setFailed(f => ({ ...f, [key]: true }))}
        />
        {current.caption && (
          <div className="lightbox-caption">
            <span className="lightbox-counter">{index + 1} / {images.length}</span>
            <span className="lightbox-label">{current.caption}</span>
          </div>
        )}
      </div>
      <button className="lightbox-nav next" onClick={(e) => { e.stopPropagation(); go(1); }} aria-label="Next">
        <svg viewBox="0 0 24 24" width="28" height="28" fill="none" stroke="currentColor" strokeWidth="1.5"><path d="M9 6l6 6-6 6"/></svg>
      </button>
    </div>
  );
};

// Gallery back face: contact sheet of every image, click to open lightbox.
const GalleryBack = ({ card, num, total, onFlip, onOpenLightbox }) => {
  const notes = card.fieldNotes && card.fieldNotes.length ? card.fieldNotes : [];
  const handleActivate = (e, i) => {
    e.stopPropagation();
    if (onOpenLightbox) onOpenLightbox(notes, i);
  };
  return (
    <>
      <div className="card-meta">
        <span className="back-header">/ field-notes</span>
        {onFlip && <FlipHint onClick={onFlip} label="Flip back" />}
      </div>
      <h3 className="card-title" style={{fontSize: 'calc(26px * var(--density))', marginBottom: '14px'}}>
        The full reel.
      </h3>
      <div className="card-scroll">
        <div className="contact-sheet">
          {notes.length === 0 && (
            <p className="card-lede" style={{fontSize: 13, color: 'var(--ink-dim)'}}>
              Drop image files into <code>images/field-notes/</code> and list them in <code>manifest.json</code>.
            </p>
          )}
          {notes.map((n, i) => {
            const src = n.url || n.fallback;
            return (
              <div
                key={i}
                className="contact-sheet-cell"
                style={{ backgroundImage: `url(${src})`, cursor: 'zoom-in' }}
                onClick={(e) => handleActivate(e, i)}
                onKeyDown={(e) => {
                  if (e.key === 'Enter' || e.key === ' ') {
                    e.preventDefault();
                    handleActivate(e, i);
                  }
                }}
                role="button"
                tabIndex={0}
                aria-label={`Open ${n.caption}`}
                title={n.caption}
              >
                <div className="contact-sheet-label">{n.caption}</div>
              </div>
            );
          })}
        </div>
      </div>
      <div className="card-footer">
        <span className="card-num">{String(num).padStart(2,'0')} / {String(total).padStart(2,'0')}</span>
        <span>Back</span>
      </div>
    </>
  );
};

const ContactCard = ({ card, num, total, onFlip }) => (
  <>
    <CardMeta onFlip={onFlip} />
    <div className="card-eyebrow">{card.eyebrow}</div>
    <h2 className="card-title">{card.title}</h2>
    <div className="card-scroll">
      <div className="contact-list">
        {card.rows.map((r, i) => <ContactRow key={i} row={r} />)}
      </div>
    </div>
  </>
);

// Renders a single contact row. Anchors for http(s); a button for
// mailto: (so the OS never sees a mailto navigation that could trigger
// "Can't open this page" on iOS without a Mail handler); a plain div
// for label-only rows like "based — Edinburgh, Scotland".
const ContactRow = ({ row: r }) => {
  const href = r.href || '';
  const isMailto = /^mailto:/i.test(href);
  const isHttp = /^https?:/i.test(href);
  const stop = (e) => e.stopPropagation();
  if (isMailto) {
    const email = href.replace(/^mailto:/i, '').split('?')[0];
    return (
      <button
        type="button"
        className="contact-row contact-row-button"
        onClick={(e) => { stop(e); if (window.__copyEmail) window.__copyEmail(email); }}
        onPointerDown={stop}
      >
        <span className="contact-label">{r.label}</span>
        <span className="contact-value">{r.value}</span>
        <span className="contact-arrow" aria-hidden="true">↗</span>
      </button>
    );
  }
  if (isHttp) {
    return (
      <a
        className="contact-row"
        href={href}
        target="_blank"
        rel="noopener noreferrer"
        onClick={stop}
        onPointerDown={stop}
      >
        <span className="contact-label">{r.label}</span>
        <span className="contact-value">{r.value}</span>
        <span className="contact-arrow" aria-hidden="true">↗</span>
      </a>
    );
  }
  return (
    <div className="contact-row">
      <span className="contact-label">{r.label}</span>
      <span className="contact-value">{r.value}</span>
      <span className="contact-arrow" aria-hidden="true"></span>
    </div>
  );
};

const BackFace = ({ card, num, total, onFlip }) => (
  <>
    <div className="card-meta">
      <span className="back-header">{card.back?.header || 'More'}</span>
      {onFlip && <FlipHint onClick={onFlip} label="Flip back" />}
    </div>
    <h3 className="card-title" style={{fontSize: 'calc(28px * var(--density))', marginBottom: '16px'}}>
      {card.back?.title || card.eyebrow || 'Details'}
    </h3>
    <div className="card-scroll">
      {card.back?.lede && (
        <p className="card-lede" style={{whiteSpace: 'pre-line'}}>{card.back.lede}</p>
      )}
      {card.back?.sections && (
        <div className="bio-sections">
          {card.back.sections.map((s, i) => (
            <div key={i} className="bio-section">
              <div className="bio-section-label">{s.label}</div>
              <div className="bio-section-body">{s.body}</div>
            </div>
          ))}
        </div>
      )}
      {card.back?.links && (
        <div className="contact-list" style={{marginTop: 14}}>
          {card.back.links.map((r, i) => <ContactRow key={i} row={r} />)}
        </div>
      )}
      {card.back?.chips && (
        <div className="chips" style={{marginTop: 14}}>
          {card.back.chips.map((c, i) => <span key={i} className="chip">{c}</span>)}
        </div>
      )}
    </div>
    <div className="card-footer">
      <span className="card-num">{String(num).padStart(2,'0')} / {String(total).padStart(2,'0')}</span>
      <span>Back</span>
    </div>
  </>
);

const WritingCard = ({ card, num, total, onFlip }) => (
  <>
    <CardMeta onFlip={onFlip} />
    <div className="card-eyebrow">{card.eyebrow}</div>
    <h2 className="card-title">{card.title}</h2>
    <div className="card-scroll">
      {card.lede && <p className="card-lede">{card.lede}</p>}
      {Array.isArray(card.channels) && (
        <div className="bio-sections">
          {card.channels.map((c, i) => (
            <div key={i} className="bio-section">
              <div className="bio-section-label">{c.label}</div>
              <div className="bio-section-body">{c.body}</div>
            </div>
          ))}
        </div>
      )}
      {Array.isArray(card.stats) && card.stats.length > 0 && (
        <div className="writing-stat">
          <div className="stat-num">{card.stats[0].num}</div>
          <div className="stat-label">{card.stats[0].label}</div>
        </div>
      )}
    </div>
  </>
);

const KIND_MAP = {
  hero: HeroCard,
  bio: BioCard,
  feature: FeatureCard,
  now: NowCard,
  history: HistoryCard,
  projects: HistoryCard,
  advisory: AdvisoryCard,
  ecosystem: EcosystemCard,
  quote: QuoteCard,
  writing: WritingCard,
  gallery: GalleryCard,
  contact: ContactCard,
};

// Section colouring is keyed off the card's prefix. Hero has no prefix and
// therefore no section — it stays neutral.
const SECTION_BY_PREFIX = { '#': 'me', '@': 'companies', '/': 'projects' };

const SectionMark = ({ prefix }) => {
  if (!SECTION_BY_PREFIX[prefix]) return null;
  return (
    <div className="section-mark" aria-hidden="true">
      <span className="section-mark-glyph">{prefix}</span>
    </div>
  );
};

function Card({ card, num, total, flipped, onFlip, isHero, onOpenLightbox, userLoc, userPlace }) {
  const Renderer = KIND_MAP[card.kind] || BioCard;
  const frontClass = "card-face front"
    + (isHero ? ' hero-card' : '')
    + (card.imageFullBleed && card.image ? ' feature-fullbleed' : '');
  const useGalleryBack = card.kind === 'gallery' && card.fieldNotes && card.fieldNotes.length > 0;
  const section = SECTION_BY_PREFIX[card.prefix];
  return (
    <>
      <div className={frontClass} data-section={section || undefined}>
        <SectionMark prefix={card.prefix} />
        <Renderer card={card} num={num} total={total} onFlip={card.back ? onFlip : undefined} onOpenLightbox={onOpenLightbox} userLoc={userLoc} userPlace={userPlace} />
        {!isHero && (
          <div className="card-footer">
            <span className="card-num">{String(num).padStart(2,'0')} / {String(total).padStart(2,'0')}</span>
            <span>{card.tag}</span>
          </div>
        )}
        {isHero && (
          <div className="card-footer" style={{padding: '14px 28px', borderTop: 'none'}}>
            <span className="card-num">{String(num).padStart(2,'0')} / {String(total).padStart(2,'0')}</span>
            <span>{card.footerHint || 'Drag · ← → · tap'}</span>
          </div>
        )}
      </div>
      <div className="card-face back" data-section={section || undefined}>
        <SectionMark prefix={card.prefix} />
        {useGalleryBack
          ? <GalleryBack card={card} num={num} total={total} onFlip={onFlip} onOpenLightbox={onOpenLightbox} />
          : <BackFace card={card} num={num} total={total} onFlip={onFlip} />}
      </div>
    </>
  );
}

Object.assign(window, { Card, Lightbox });
