/**
 * The album's design layer.
 *
 * frontend.css was copied whole from the WordPress plugin and is marked "do
 * not edit" for a good reason: 2,596 lines, 354 class names, and no test in
 * this repository renders a page, so a change there is only ever verified by
 * a person looking. A large part of it is not even design -- it fights a
 * WordPress theme ("full-bleed breakout from theme content column", "prevent
 * theme link styles bleeding into buttons") that has not existed since the
 * move to Cloudflare.
 *
 * So this does not rewrite it. It layers a design system over it. Every base
 * rule in frontend.css is a single class selector, so equal specificity
 * loaded afterwards wins on source order alone -- no !important, no
 * specificity war, and any rule here can be deleted to fall back to the old
 * look. frontend.css keeps doing layout, and can be retired section by
 * section as each one is confirmed by eye.
 *
 * The direction is the marketing site's, deliberately and exactly: "editorial
 * heirloom" -- warm paper, DM Serif Display for anything that speaks, Inter
 * for anything that instructs, one red. A family who bought from a page that
 * looked like an heirloom should not then be handed a control panel. Until
 * now album.africa and the album shared a product and nothing else: a
 * different red, a different scale, a different idea of a card.
 *
 * Written 04/09/2026.
 */

/* ═══ Tokens ══════════════════════════════════════════════════════════════
   The same values as worker/src/routes/landing/styles.ts. If those change,
   these change: two design systems in one product is the thing being fixed.

   On :root, not on .ap-app. Every dialog in this product -- upload, edit
   photo, new category, member invite, the tree editor -- is appended to
   <body>, OUTSIDE .ap-app. With the tokens scoped to .ap-app those dialogs
   had no card colour, no typeface and no ink: the upload form rendered as
   Times New Roman on a transparent box over the dimmed page, and its labels
   were dark text on a dark backdrop until the pointer happened to find a
   field. Found by the owner on 05/09/2026, trying to upload a photograph. */

:root {
  --ap-paper: #f8f3ea;
  --ap-paper-deep: #efe6d6;
  --ap-card: #fffdf9;
  --ap-ink: #18130f;
  --ap-ink-soft: #544a41;
  --ap-dim: #7a6f64;
  --ap-line: #e6dcc9;
  --ap-line-soft: #f0e9dc;

  /* --ap-red is set per family by brandStyle(); these follow from whatever
     colour the family chose, so a family in green gets a green product. */
  --ap-tint: color-mix(in srgb, var(--ap-red, #B30000) 7%, transparent);
  --ap-tint-2: color-mix(in srgb, var(--ap-red, #B30000) 13%, transparent);

  --ap-r: 18px;
  --ap-r-sm: 12px;
  --ap-r-xs: 9px;
  --ap-shadow: 0 1px 3px rgba(24,19,15,.06), 0 10px 28px rgba(24,19,15,.05);
  --ap-shadow-lg: 0 24px 64px rgba(24,19,15,.16);
  --ap-head: 'DM Serif Display', Georgia, serif;
  --ap-body: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --ap-ease: cubic-bezier(.22,1,.36,1);
}

/* The typeface and ink on <body>, so a dialog appended there inherits them
   exactly as the album does. */
body {
  font-family: var(--ap-body);
  color: var(--ap-ink);
}

/* frontend.css sets border-box on `.ap-app *` only. A dialog on <body> was
   content-box, so a 100%-wide input plus its padding overflowed the card by
   exactly that padding, on every dialog, on both desktop and phone. */
*, *::before, *::after { box-sizing: border-box; }

.ap-app {
  background: var(--ap-paper);
  color: var(--ap-ink);
  font-family: var(--ap-body);
  min-height: 100vh;
}

/* Global, not scoped to .ap-app: the dialogs live on <body>, and there they
   were getting the browser's own ring in a yellow this product never uses. */
:focus-visible {
  outline: 2px solid var(--ap-red, #B30000);
  outline-offset: 3px;
  border-radius: 4px;
}

/* ═══ Header ══════════════════════════════════════════════════════════════
   Was a heavy black bar carrying a small logo, a name and a sign-out link,
   with most of its height empty. It is the first thing anyone sees of their
   own album, so it now reads like a title page: the family's name in the
   display face, the facts beneath it, the person quietly on the right. */

.ap-header {
  background: var(--ap-card);
  border-bottom: 1px solid var(--ap-line);
  padding: 0;
  color: var(--ap-ink);
  position: relative;
}
.ap-header-inner {
  max-width: 1180px;
  margin: 0 auto;
  padding: 18px 28px;
  display: flex;
  /* Centred, not flex-start: the two sides are one line of furniture, not two
     stacked columns. At flex-start this header stood 201px tall to carry a
     name and two facts. */
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  /* frontend.css sets min-height:200px here, sized for a header that showed a
     blurred cover photograph behind the name. There is no cover photograph;
     the content needs 92px. Reducing the padding did nothing because padding
     was never what held it open -- worth measuring before assuming. */
  min-height: 0;
}
.ap-header-left { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.ap-header-brand {
  display: flex; align-items: center; gap: 9px;
  font-size: 11px; letter-spacing: .14em; text-transform: uppercase;
  font-weight: 600; color: var(--ap-red, #B30000);
}
.ap-header-logo-icon { color: var(--ap-red, #B30000); font-size: 13px; }
.ap-header-title {
  font-family: var(--ap-head);
  font-weight: 400;
  font-size: clamp(24px, 2.6vw, 31px);
  line-height: 1.12;
  letter-spacing: -.005em;
  color: var(--ap-ink);
  margin: 0;
}
.ap-header-stats {
  font-size: 13.5px; color: var(--ap-dim); margin: 0;
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
}
/* THE STATS WERE INVISIBLE. .ap-stat is rgba(255,255,255,.55) in
   frontend.css -- white, because it was written for the black bar this
   replaces. Setting a colour on the parent does nothing: the child has its
   own. Every element that carried light-on-dark text needs saying again. */
.ap-header-stats .ap-stat { color: var(--ap-dim); font-size: 13px; }
.ap-header-stats .ap-stat strong { color: var(--ap-ink); font-weight: 600; }
.ap-header-stats .ap-stat-sep, .ap-header-stats .ap-dot { color: var(--ap-line); }

/* row, not the inherited column, which dropped Sign out beneath the pill. */
.ap-header-right { display: flex; flex-direction: row; align-items: center; gap: 12px; }
.ap-header-user-pill {
  display: flex; align-items: center; gap: 11px;
  background: var(--ap-paper);
  border: 1px solid var(--ap-line);
  border-radius: 999px;
  padding: 7px 16px 7px 7px;
}
.ap-header-avatar {
  width: 34px; height: 34px; border-radius: 50%;
  background: var(--ap-red, #B30000); color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-weight: 600; font-size: 14px; flex: none;
}
.ap-header-user-info { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.ap-header-username {
  font-size: 13.5px; font-weight: 600; color: var(--ap-ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 190px;
}
.ap-role-badge {
  font-size: 10.5px; letter-spacing: .08em; text-transform: uppercase;
  font-weight: 600; color: var(--ap-dim); background: none; padding: 0;
  border: 0; border-radius: 0;
}
.ap-logout-btn {
  background: none; border: 0; padding: 8px 4px;
  color: var(--ap-dim); font-size: 13.5px; font-family: inherit; cursor: pointer;
  transition: color .16s var(--ap-ease);
}
.ap-logout-btn:hover { color: var(--ap-red, #B30000); text-decoration: underline; }

/* ═══ Tabs ════════════════════════════════════════════════════════════════
   Were file-folder tabs: grey boxes bordered on three sides, the shape
   software had in 1998. An underline row reads as navigation, and lets the
   one you are on actually stand out. */

.ap-tabs {
  background: var(--ap-card);
  border-bottom: 1px solid var(--ap-line);
  position: sticky; top: 0; z-index: 40;
  padding: 0;
}
.ap-tabs-inner {
  max-width: 1180px; margin: 0 auto; padding: 0 28px;
  display: flex; gap: 4px; overflow-x: auto; scrollbar-width: none;
}
.ap-tabs-inner::-webkit-scrollbar { display: none; }
.ap-tab {
  appearance: none; background: none; border: 0; border-radius: 0;
  padding: 15px 15px 13px;
  font-family: inherit; font-size: 14.5px; font-weight: 500;
  color: var(--ap-dim); cursor: pointer; white-space: nowrap;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  transition: color .16s var(--ap-ease), border-color .16s var(--ap-ease);
}
.ap-tab:hover { color: var(--ap-ink); }
.ap-tab.active,
.ap-tab[aria-selected="true"] {
  color: var(--ap-red, #B30000);
  border-bottom-color: var(--ap-red, #B30000);
  font-weight: 600;
  background: none;
}

/* ═══ Panels ══════════════════════════════════════════════════════════════ */

.ap-app section[role="tabpanel"] {
  max-width: 1180px; margin: 0 auto; padding: 34px 28px 80px;
}
.ap-panel-header {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 20px; margin: 0 0 24px; padding: 0; border: 0;
}
.ap-panel-title {
  font-family: var(--ap-head); font-weight: 400;
  font-size: 27px; line-height: 1.15; color: var(--ap-ink); margin: 0;
}
.ap-panel-sub, .ap-panel-desc {
  color: var(--ap-dim); font-size: 14.5px; margin: 6px 0 0; line-height: 1.55;
}

/* The one surface this app repeats, defined once. */
.ap-card, .ap-story-card, .ap-member-card, .ap-video-card, .ap-cat-row {
  background: var(--ap-card);
  border: 1px solid var(--ap-line);
  border-radius: var(--ap-r);
  box-shadow: var(--ap-shadow);
}

/* ═══ Buttons ═════════════════════════════════════════════════════════════
   Matching the marketing site exactly: same radius, same weight, same red,
   same lift on hover. */

.ap-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  padding: 12px 22px; border-radius: 11px;
  font-family: inherit; font-weight: 600; font-size: 14.5px;
  border: 1px solid transparent; cursor: pointer; text-decoration: none;
  transition: transform .16s var(--ap-ease), box-shadow .16s var(--ap-ease),
              background .16s var(--ap-ease), color .16s var(--ap-ease);
}
.ap-btn-primary {
  background: var(--ap-red, #B30000); color: #fff;
  box-shadow: 0 4px 14px rgba(179,0,0,.24);
}
.ap-btn-primary:hover {
  transform: translateY(-1px);
  box-shadow: 0 9px 22px rgba(179,0,0,.30);
  filter: brightness(.94);
}
.ap-btn-outline {
  background: var(--ap-card); color: var(--ap-ink);
  border-color: var(--ap-line);
}
.ap-btn-outline:hover { border-color: var(--ap-red, #B30000); color: var(--ap-red, #B30000); }
.ap-btn-ghost { background: none; color: var(--ap-dim); }
.ap-btn-ghost:hover { background: var(--ap-paper); color: var(--ap-ink); }
.ap-btn-sm { padding: 8px 15px; font-size: 13px; border-radius: var(--ap-r-xs); }
.ap-btn:disabled { opacity: .55; cursor: default; transform: none; box-shadow: none; }

/* ═══ Forms ═══════════════════════════════════════════════════════════════ */

.ap-label {
  font-size: 11px; letter-spacing: .1em; text-transform: uppercase;
  font-weight: 600; color: var(--ap-dim); margin: 0 0 7px; display: block;
}
.ap-label-hint { text-transform: none; letter-spacing: 0; font-weight: 400; opacity: .8; }
.ap-input, .ap-select, .ap-app textarea.ap-input {
  width: 100%; padding: 11px 14px;
  font-family: inherit; font-size: 15px; color: var(--ap-ink);
  background: var(--ap-card);
  border: 1px solid var(--ap-line); border-radius: var(--ap-r-sm);
  transition: border-color .16s var(--ap-ease), box-shadow .16s var(--ap-ease);
}
.ap-input:focus, .ap-select:focus {
  outline: none;
  border-color: var(--ap-red, #B30000);
  box-shadow: 0 0 0 4px var(--ap-tint);
}
.ap-input::placeholder { color: var(--ap-dim); }
.ap-form-hint { font-size: 13px; color: var(--ap-dim); line-height: 1.55; margin: 7px 0 0; }
.ap-alert {
  border-radius: var(--ap-r-sm); padding: 12px 16px; font-size: 14px; line-height: 1.55;
}
.ap-alert-error { background: var(--ap-tint); color: #8a0000; border: 1px solid var(--ap-tint-2); }
.ap-danger { color: #8a0000; }

/* ═══ Photos ══════════════════════════════════════════════════════════════ */

/* One line, always. The row was flex-wrap:wrap, so the moment the pills grew
   past the width "+ Create" fell to a second line on its own. A row that
   scrolls sideways is what the plugin's own comment called it ("scrollable
   pill row") and is what the old design did. The scrollbar is hidden the way
   the tab strip's is; the pills are trimmed so the usual eight fit without
   scrolling at all on a laptop. */
.ap-category-pills {
  display: flex; flex-wrap: nowrap; gap: 7px;
  overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch;
  padding-bottom: 2px;
}
.ap-category-pills::-webkit-scrollbar { display: none; }
/* The 56px of air between the tabs and the pills was my 34px panel padding
   stacked on the plugin's 22px bar margin. One of them, not both. */
.ap-category-bar { margin-top: 0; }
.ap-app section[role="tabpanel"] { padding-top: 24px; }

.ap-cat-pill {
  background: var(--ap-card); border: 1px solid var(--ap-line);
  border-radius: 999px; padding: 7px 14px; flex: none;
  font-family: inherit; font-size: 13px; color: var(--ap-ink-soft);
  cursor: pointer; white-space: nowrap;
  transition: border-color .16s var(--ap-ease), color .16s var(--ap-ease),
              background .16s var(--ap-ease);
}
.ap-cat-pill:hover { border-color: var(--ap-red, #B30000); color: var(--ap-red, #B30000); }
.ap-cat-pill.active {
  background: var(--ap-red, #B30000); border-color: var(--ap-red, #B30000);
  color: #fff; font-weight: 600;
}
.ap-photo-card {
  border-radius: var(--ap-r-sm); overflow: hidden;
  background: var(--ap-card); border: 1px solid var(--ap-line);
  box-shadow: var(--ap-shadow);
  transition: transform .18s var(--ap-ease), box-shadow .18s var(--ap-ease);
}
.ap-photo-card:hover { transform: translateY(-2px); box-shadow: 0 14px 34px rgba(24,19,15,.12); }
.ap-photo-caption { font-size: 13.5px; color: var(--ap-ink-soft); line-height: 1.5; padding: 11px 13px; }
.ap-empty, .ap-empty-state { text-align: center; padding: 64px 24px; color: var(--ap-dim); }
.ap-empty h3, .ap-empty-title {
  font-family: var(--ap-head); font-weight: 400; font-size: 22px;
  color: var(--ap-ink); margin: 0 0 8px;
}

/* ═══ Modals ══════════════════════════════════════════════════════════════ */

.ap-modal, .ap-ft-edit-modal { background: rgba(24,19,15,.52); backdrop-filter: blur(3px); }
.ap-modal-box, .ap-ft-edit-box {
  background: var(--ap-card);
  border: 1px solid var(--ap-line);
  border-radius: 22px;
  box-shadow: var(--ap-shadow-lg);
}
.ap-modal-header, .ap-ft-edit-header {
  padding: 22px 26px 16px; border-bottom: 1px solid var(--ap-line-soft);
}
.ap-modal-header h3, .ap-ft-edit-header h3, .ap-modal-title {
  font-family: var(--ap-head); font-weight: 400; font-size: 22px;
  color: var(--ap-ink); margin: 0;
}
.ap-modal-body, .ap-ft-edit-body { padding: 22px 26px; }
.ap-modal-footer, .ap-ft-edit-footer, .ap-editor-actions {
  display: flex; align-items: center; gap: 10px;
  padding: 16px 26px 22px; border-top: 1px solid var(--ap-line-soft);
}
.ap-modal-close {
  background: none; border: 0; font-size: 22px; line-height: 1;
  color: var(--ap-dim); cursor: pointer; padding: 4px 8px; border-radius: 8px;
}
.ap-modal-close:hover { background: var(--ap-paper); color: var(--ap-ink); }

/* ═══ Lightbox ════════════════════════════════════════════════════════════ */

.ap-lightbox { background: rgba(18,14,11,.94); backdrop-filter: blur(6px); }
.ap-lightbox img { border-radius: var(--ap-r-sm); box-shadow: 0 30px 80px rgba(0,0,0,.5); }
.ap-lightbox-caption { font-size: 15px; line-height: 1.6; }
.ap-lightbox-close, .ap-lightbox-prev, .ap-lightbox-next {
  background: rgba(255,255,255,.10); border: 1px solid rgba(255,255,255,.18);
  border-radius: 50%; color: #fff; backdrop-filter: blur(8px);
  transition: background .16s var(--ap-ease);
}
.ap-lightbox-close:hover, .ap-lightbox-prev:hover, .ap-lightbox-next:hover {
  background: rgba(255,255,255,.22);
}

/* ═══ Family tree ═════════════════════════════════════════════════════════ */

.ap-ft-person-card {
  background: var(--ap-card); border: 1px solid var(--ap-line);
  border-radius: var(--ap-r-sm); box-shadow: var(--ap-shadow);
}
.ap-ft-avatar { border: 3px solid var(--ap-card); box-shadow: var(--ap-shadow); }
.ap-ft-gen-label {
  font-size: 11px; letter-spacing: .12em; text-transform: uppercase;
  font-weight: 600; color: var(--ap-dim);
}
.ap-ft-drawer { background: var(--ap-card); box-shadow: var(--ap-shadow-lg); }
.ap-ft-acc-header {
  background: var(--ap-card); border: 1px solid var(--ap-line);
  border-radius: var(--ap-r-sm);
}

/* ═══ Toasts, badges, the upload button ═══════════════════════════════════ */

.ap-toast {
  background: var(--ap-ink); color: #fff;
  border-radius: var(--ap-r-sm); box-shadow: var(--ap-shadow-lg);
  font-size: 14.5px; padding: 13px 20px;
}
.ap-toast-error { background: #8a0000; }
.ap-badge, .ap-photo-count {
  background: var(--ap-tint); color: var(--ap-red, #B30000);
  border-radius: 999px; padding: 3px 10px;
  font-size: 11.5px; font-weight: 600;
}
.ap-fab, #ap-upload-btn {
  border-radius: 999px; box-shadow: 0 8px 26px rgba(179,0,0,.32); font-weight: 600;
}
.ap-fab:hover, #ap-upload-btn:hover { transform: translateY(-2px); }

/* ═══ Narrow screens ══════════════════════════════════════════════════════ */

@media (max-width: 768px) {
  .ap-header-inner { padding: 22px 18px 18px; flex-direction: column; gap: 16px; }
  .ap-header-right { width: 100%; justify-content: space-between; }
  .ap-tabs-inner { padding: 0 18px; }
  .ap-tab { padding: 13px 12px 11px; font-size: 14px; }
  .ap-app section[role="tabpanel"] { padding: 24px 18px 90px; }
  .ap-panel-header { flex-direction: column; align-items: flex-start; gap: 12px; }
  .ap-panel-title { font-size: 23px; }
}

@media (prefers-reduced-motion: reduce) {
  .ap-btn, .ap-photo-card, .ap-cat-pill, .ap-tab, .ap-fab, #ap-upload-btn { transition: none; }
  .ap-btn-primary:hover, .ap-photo-card:hover, .ap-fab:hover { transform: none; }
}

/* ── Put it on your phone ────────────────────────────────────────────────
   One quiet bar under the tabs, shown by pwa.js on any device that can act
   on it. It uses the family's tint so it reads as part of the album, not as
   an advert laid over it. */
.ap-install {
  background: var(--ap-tint);
  border-bottom: 1px solid var(--ap-line);
}
.ap-install-inner {
  max-width: 1180px; margin: 0 auto; padding: 10px 28px;
  display: flex; align-items: center; gap: 12px;
}
.ap-install-text { flex: 1; font-size: 14px; line-height: 1.4; color: var(--ap-ink-soft); }
.ap-install-add { padding: 7px 16px; font-size: 13px; flex: none; }
.ap-install-dismiss {
  appearance: none; background: none; border: 0; padding: 4px 6px; flex: none;
  font-size: 22px; line-height: 1; color: var(--ap-dim); cursor: pointer;
}
.ap-install-dismiss:hover { color: var(--ap-ink); }
@media (max-width: 768px) {
  .ap-install-inner { padding: 10px 16px; }
}

/* ── Save space, in the upload box ───────────────────────────────────── */
.ap-save-space {
  display: inline-flex; gap: 8px; align-items: center; cursor: pointer;
  margin: 14px 0 0; font-size: 14px; color: var(--ap-ink-soft);
}
.ap-save-space input { width: 17px; height: 17px; flex: none; margin: 0; accent-color: var(--ap-red, #B30000); }

/* ── Only one owner: the card on the Members tab ───────────────────────── */
.ap-second-owner {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  background: var(--ap-tint); border: 1px solid var(--ap-line); border-radius: 12px;
  padding: 16px 18px; margin: 0 0 18px;
}
.ap-second-owner p { flex: 1 1 320px; margin: 0; font-size: 14px; line-height: 1.5; color: var(--ap-ink-soft); }
.ap-second-owner .ap-btn { flex: none; }

/* ── Dialog forms: the things the owner found on 05/09/2026 ─────────────────
   Found by trying to upload a photograph, which is the one thing every
   family does. Each of these is small; together they made the dialogs feel
   unfinished next to the album around them. */

/* Fields stacked inside a dialog had no space between them: the hint under
   one ran straight into the label of the next. */
.ap-modal-body > .ap-form-field + .ap-form-field,
.ap-modal-body > .ap-form-row + .ap-form-field,
.ap-modal-body > .ap-form-field + .ap-form-row,
.ap-modal-body > .ap-multiselect-wrap + .ap-form-field { margin-top: 16px; }
.ap-modal-body .ap-form-row { margin-bottom: 0; }
.ap-modal-body .ap-form-row + .ap-form-row { margin-top: 16px; }

/* "+ New" beside the category search was given a 32px-wide box by the
   plugin, sized for a lone "+", so the word wrapped under the sign. */
.ap-add-term-btn {
  width: auto; height: auto; padding: 6px 11px;
  white-space: nowrap; flex: none;
  font-size: 12.5px; font-weight: 600; font-family: inherit;
  border: 1px solid var(--ap-line); border-radius: var(--ap-r-xs);
  background: var(--ap-card); color: var(--ap-ink-soft); cursor: pointer;
}
.ap-add-term-btn:hover { border-color: var(--ap-red); color: var(--ap-red); }

/* The Edit photo dialog builds its people field without the bordered wrap
   the upload dialog has, so its input looked like a line of stray text. */
.ap-form-field > .ap-multiselect-input-row {
  display: flex; align-items: center; gap: 8px;
  padding: 6px 8px 6px 14px; min-height: 46px;
  border: 1px solid var(--ap-line); border-radius: var(--ap-r-xs);
  background: var(--ap-card);
}
.ap-form-field > .ap-multiselect-input-row:focus-within {
  border-color: var(--ap-red); box-shadow: 0 0 0 3px var(--ap-tint);
}
.ap-form-field > .ap-multiselect-input-row .ap-multiselect-search { font-size: 15px; }

/* A button's label is one line. "Check status" broke in two on a phone. */
.ap-btn { white-space: nowrap; }

/* The tribute's prose is set in the display face on purpose; its empty
   state is an instruction, not prose, and reads as a mistake in serif. */
.ap-tribute-content .ap-empty-state,
.ap-tribute-content .ap-empty-state p { font-family: var(--ap-body); }
.ap-tribute-content .ap-empty-state h3 { font-family: var(--ap-head); font-weight: 400; }

/* The photograph at the top of Edit photo sat directly on the first label. */
.ap-edit-photo-thumb-wrap { margin-bottom: 18px; }

/* ── Choosing a person's picture ─────────────────────────────────────────
   The control existed from the start and almost nobody could use it: a star
   at opacity 0 that appeared on hover, which a phone cannot do at all. The
   owner asked, on 05/09/2026, why everyone in the tree had the same picture
   and where it could be changed. It is now simply visible. */
.ap-ft-drawer-hint {
  grid-column: 1 / -1;
  margin: 0 0 4px;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--ap-dim);
}
.ap-ft-drawer-thumb-wrap { position: relative; }
.ap-ft-set-avatar-btn {
  position: absolute; bottom: 5px; right: 5px;
  width: 30px; height: 30px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid rgba(255,255,255,.7);
  background: rgba(24,19,15,.62); color: #fff;
  font-size: 14px; line-height: 1; cursor: pointer;
  /* Visible always. A hover-only control does not exist on a phone. */
  opacity: 1;
  transition: background .15s var(--ap-ease), transform .15s var(--ap-ease);
}
.ap-ft-set-avatar-btn:hover { background: var(--ap-red); transform: scale(1.06); }
/* The one in use: filled, and no longer an invitation. */
.ap-ft-drawer-thumb-wrap.is-current .ap-ft-set-avatar-btn {
  background: var(--ap-red); border-color: #fff; cursor: default;
}
.ap-ft-drawer-thumb-wrap.is-current .ap-ft-set-avatar-btn:hover { transform: none; }
.ap-ft-drawer-thumb-wrap.is-current {
  outline: 2px solid var(--ap-red); outline-offset: 2px; border-radius: var(--ap-r-xs);
}
@media (prefers-reduced-motion: reduce) {
  .ap-ft-set-avatar-btn { transition: none; }
  .ap-ft-set-avatar-btn:hover { transform: none; }
}

/* ═══ Wishes & assets ═════════════════════════════════════════════════════ */
.ap-legacy-note {
  background: var(--ap-paper-deep); border: 1px solid var(--ap-line); border-radius: var(--ap-r-sm);
  padding: 14px 18px; color: var(--ap-ink-soft); font-size: 14px; line-height: 1.6; margin: 0 0 26px;
}
.ap-legacy-section { margin: 0 0 32px; }
.ap-legacy-section-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin: 0 0 12px; }
.ap-legacy-section-head h3 { font-family: var(--ap-head); font-weight: 400; font-size: 23px; margin: 0; color: var(--ap-ink); }
.ap-legacy-card { padding: 20px 22px; }
.ap-legacy-dl { display: grid; grid-template-columns: minmax(140px, 230px) 1fr; gap: 10px 22px; margin: 0; }
.ap-legacy-dl dt { color: var(--ap-dim); font-size: 13.5px; }
.ap-legacy-dl dd { margin: 0; color: var(--ap-ink); white-space: pre-wrap; overflow-wrap: anywhere; }
.ap-legacy-dl-tight { grid-template-columns: 96px 1fr; gap: 6px 14px; font-size: 14px; }
.ap-legacy-assets { display: grid; gap: 14px; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); }
.ap-legacy-asset h4 { margin: 10px 0 12px; font-size: 17px; color: var(--ap-ink); }
.ap-legacy-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 16px; }
.ap-legacy-access label { display: flex; align-items: center; gap: 12px; padding: 10px 0; border-bottom: 1px solid var(--ap-line-soft); cursor: pointer; }
.ap-legacy-access input { width: 18px; height: 18px; accent-color: var(--ap-red, #B30000); flex: none; }
.ap-legacy-role { margin-left: auto; text-transform: capitalize; }
.ap-legacy-dim { color: var(--ap-dim); font-size: 13px; }
.ap-legacy-intro { color: var(--ap-ink-soft); font-size: 14px; line-height: 1.55; margin: 0 0 14px; }
.ap-legacy-updated { color: var(--ap-dim); font-size: 12.5px; margin: 16px 0 0; }
.ap-legacy-empty { color: var(--ap-dim); margin: 0; }
.ap-legacy-log { list-style: none; padding: 0; margin: 0; font-size: 13.5px; }
.ap-legacy-log li { padding: 8px 0; border-bottom: 1px solid var(--ap-line-soft); color: var(--ap-ink-soft); }
.ap-legacy-log li:last-child { border-bottom: 0; }
@media (max-width: 560px) {
  .ap-legacy-dl { grid-template-columns: 1fr; gap: 2px 0; }
  .ap-legacy-dl dd { margin-bottom: 10px; }
  .ap-legacy-card { padding: 16px; }
}
.ap-legacy-docs { margin-top: 14px; padding-top: 12px; border-top: 1px dashed var(--ap-line); }
.ap-legacy-docs ul { list-style: none; padding: 0; margin: 0 0 10px; }
.ap-legacy-docs li { display: flex; align-items: center; gap: 10px; padding: 5px 0; font-size: 14px; min-width: 0; }
.ap-legacy-docs a { color: var(--ap-ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.ap-legacy-doc-del { margin-left: auto; border: 0; background: none; color: var(--ap-dim); font-size: 20px; line-height: 1;
  width: 32px; height: 32px; border-radius: 8px; cursor: pointer; flex: none; }
.ap-legacy-doc-del:hover { color: #8a0000; background: var(--ap-tint); }

/* ═══ Company documents: a company album's vault (29/09/2026) ═════════════ */
.ap-vault-list { list-style: none; padding: 0; margin: 0 0 6px; }
.ap-vault-doc { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 8px 16px; padding: 12px 0;
  border-bottom: 1px solid var(--ap-line-soft); }
.ap-vault-doc:last-child { border-bottom: 0; }
.ap-vault-doc-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1 1 260px; }
.ap-vault-doc-title { color: var(--ap-ink); font-weight: 600; font-size: 15.5px; overflow-wrap: anywhere; }
.ap-vault-doc-note { margin: 4px 0 0; color: var(--ap-ink-soft); font-size: 14px; white-space: pre-wrap; overflow-wrap: anywhere; }
.ap-vault-doc-actions { display: flex; flex-wrap: wrap; gap: 8px; flex: none; }
.ap-vault-limits { margin: 14px 0 0; }

/* ═══ Family health ═══════════════════════════════════════════════════════ */
.ap-health-people { display: grid; gap: 14px; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); }
.ap-health-people h4 { margin: 0 0 6px; font-size: 17px; color: var(--ap-ink); }
.ap-health-list { list-style: none; padding: 0; margin: 0; }
.ap-health-list li { padding: 10px 0; border-bottom: 1px solid var(--ap-line-soft); }
.ap-health-list li:last-child { border-bottom: 0; padding-bottom: 0; }
.ap-health-row { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; }
.ap-health-actions { display: flex; gap: 8px; margin-top: 8px; }
.ap-health-notes { margin: 4px 0 0; color: var(--ap-ink-soft); font-size: 14px; white-space: pre-wrap; overflow-wrap: anywhere; }
.ap-health-runs li { display: flex; flex-wrap: wrap; gap: 4px 10px; align-items: baseline; }
.ap-legacy-demo { background: var(--ap-tint); color: var(--ap-red, #B30000); border-radius: var(--ap-r-sm);
  padding: 12px 16px; font-size: 14px; font-weight: 600; line-height: 1.5; margin: 0 0 22px; }

/* ═══ Who can see this, and when (11/09/2026) ═════════════════════════════ */
.ap-form-heading { font-family: var(--ap-head); font-weight: 400; font-size: 19px; margin: 22px 0 6px; color: var(--ap-ink); }
.ap-form-heading:first-child { margin-top: 0; }
.ap-legacy-dl-head { font-size: 12px; letter-spacing: .08em; text-transform: uppercase; color: var(--ap-dim);
  margin: 18px 0 8px; font-weight: 600; }
.ap-legacy-dl-head:first-child { margin-top: 0; }
.ap-wcs-you { background: var(--ap-paper); border: 1px dashed var(--ap-line); border-radius: var(--ap-r-sm); padding: 12px 14px; margin: 0 0 16px; }
.ap-wcs-you label { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; font-weight: 600; }
.ap-wcs-group { margin: 0 0 14px; }
.ap-wcs-group h4 { font-size: 12px; letter-spacing: .08em; text-transform: uppercase; color: var(--ap-dim); margin: 14px 0 4px; font-weight: 600; }
.ap-wcs-row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; padding: 10px 0; border-bottom: 1px solid var(--ap-line-soft); }
.ap-wcs-who { display: flex; flex-direction: column; min-width: 0; flex: 1 1 200px; }
.ap-wcs-who .ap-legacy-dim { overflow: hidden; text-overflow: ellipsis; }
.ap-wcs-row .ap-select { width: auto; min-height: 40px; flex: 0 1 auto; }
.ap-wcs-wait { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 16px 0 0; color: var(--ap-ink-soft); font-size: 14px; }
.ap-wcs-wait .ap-select { width: auto; min-height: 38px; }
.ap-release-banner { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 16px; justify-content: space-between;
  background: #fff4e5; border: 1px solid #f0c98b; color: #5b3a00; border-radius: var(--ap-r-sm); padding: 14px 16px; margin: 0 0 22px; }
.ap-release-banner p { margin: 0; flex: 1 1 320px; line-height: 1.55; }
.ap-release-banner.ap-release-open { background: var(--ap-paper-deep); border-color: var(--ap-line); color: var(--ap-ink-soft); }
.ap-release-locked h3 { font-family: var(--ap-head); font-weight: 400; font-size: 22px; margin: 0 0 8px; }
.ap-release-locked p { color: var(--ap-ink-soft); line-height: 1.6; }
@media (max-width: 560px) { .ap-wcs-row .ap-select { width: 100%; } }

/* Import from Google Photos, under the drop zone in the upload box
   (upload.js). Quiet, because dragging files in is still the usual way. */
.ap-import { margin: 14px 0 4px; display: flex; flex-direction: column; align-items: flex-start; gap: 6px; }
.ap-import .ap-form-hint { margin: 0; }
/* A real button in the family's colour. It was a ghost button, which on
   this background read as a line of grey text (Harry, 25/09/2026: "I almost
   told you I don't see Import from Google Photos"). */
.ap-import-btn {
  display: inline-flex; align-items: center; gap: 9px;
  padding: 10px 18px; border-radius: 10px; cursor: pointer;
  font: inherit; font-size: 14.5px; font-weight: 600;
  color: var(--ap-red, #B30000); background: #fff;
  border: 1.5px solid var(--ap-red, #B30000);
  transition: background .15s ease, color .15s ease;
}
.ap-import-btn:hover { background: var(--ap-tint-2); }
.ap-import-btn:focus-visible { outline: 2px solid var(--ap-red, #B30000); outline-offset: 2px; }
.ap-import-btn:disabled { opacity: .55; cursor: default; }

/* ═══ Timeline, and Awards & press: a company album's (timeline.js) ═════ */
.ap-tl-tools { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.ap-tl { list-style: none; margin: 0; padding: 0 0 0 26px; position: relative; }
.ap-tl::before {
  content: ''; position: absolute; left: 7px; top: 8px; bottom: 8px;
  width: 2px; background: var(--ap-line);
}
.ap-tl-year { position: relative; margin: 0 0 22px; }
.ap-tl-year::before {
  content: ''; position: absolute; left: -25px; top: 9px; width: 14px; height: 14px;
  box-sizing: border-box; border-radius: 50%;
  background: var(--ap-card); border: 3px solid var(--ap-red, #B30000);
}
.ap-tl-year-label {
  font-family: var(--ap-head); font-weight: 400; font-size: 26px; line-height: 1.2;
  color: var(--ap-ink); margin: 0 0 10px;
}
.ap-tl-entry { display: flex; gap: 18px; align-items: flex-start; }
.ap-tl-text { flex: 1; min-width: 0; }
.ap-tl-photo { flex: none; display: block; width: 132px; border-radius: var(--ap-r-sm); overflow: hidden; }
.ap-tl-photo img { display: block; width: 100%; height: 100px; object-fit: cover; }
.ap-tl-when { font-size: 12px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; color: var(--ap-dim); }
.ap-tl-source { margin: -2px 0 8px; font-size: 13.5px; color: var(--ap-ink-soft); font-weight: 600; }
.ap-tl-body { white-space: pre-wrap; overflow-wrap: anywhere; }
.ap-tl-open { margin-top: 2px; }
.ap-tl-chosen { display: flex; align-items: center; gap: 12px; margin: 0 0 10px; }
.ap-tl-chosen img { width: 88px; height: 66px; object-fit: cover; border-radius: var(--ap-r-xs); }
.ap-tl-picker {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(84px, 1fr)); gap: 8px;
  max-height: 260px; overflow-y: auto; margin: 10px 0 6px; padding: 2px;
}
.ap-tl-pick {
  padding: 0; border: 2px solid transparent; border-radius: var(--ap-r-xs); overflow: hidden;
  background: var(--ap-paper); cursor: pointer; aspect-ratio: 4 / 3;
}
.ap-tl-pick img { width: 100%; height: 100%; object-fit: cover; display: block; }
.ap-tl-pick.is-chosen { border-color: var(--ap-red, #B30000); box-shadow: 0 0 0 3px var(--ap-tint-2); }
.ap-tl-pick:focus-visible { outline: 2px solid var(--ap-red, #B30000); outline-offset: 2px; }
@media (max-width: 560px) {
  .ap-tl-entry { flex-direction: column; }
  .ap-tl-photo { width: 100%; }
  .ap-tl-photo img { height: 180px; }
}
