/* Family surfaces -- the shared stylesheet for templates/family/*.
 *
 * Every colour, font and focus ring arrives from chrome.css, which this file is
 * always loaded after. Nothing here redefines a --tk- token: the first block of
 * work closed the stylesheet fork (e1b3f8a) and this tree does not reopen it.
 *
 * Reading measure is capped near 65 characters because these pages are read, not
 * operated -- the staff console's density is wrong for a page about one person.
 */

.family-body {
  margin: 0;
  background: var(--tk-bg);
  color: var(--tk-text);
  font-family: var(--font-body);
  line-height: 1.6;
}

/* Visible only once focused. Keyboard users reach the content without walking the bar. */
.family-skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 10;
  padding: 0.6rem 1rem;
  background: var(--tk-bg-panel);
  color: var(--tk-text);
}
.family-skip:focus { left: 0; }

.family-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.8rem clamp(1rem, 4vw, 2rem);
  background: var(--tk-surface-glass);
  border-bottom: 1px solid var(--tk-gallery-line);
}

.family-brand {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.05rem;
  color: var(--tk-parchment);
  text-decoration: none;
}

.family-who { color: var(--tk-gallery-muted); font-size: 0.9rem; }

.family-main {
  max-width: 44rem;
  margin: 0 auto;
  padding: clamp(1.5rem, 5vw, 3rem) clamp(1rem, 4vw, 2rem) 5rem;
}

.person-head { margin-bottom: 2rem; }

.person-name {
  font-family: var(--font-display);
  font-size: clamp(2rem, 6vw, 2.9rem);
  font-weight: 600;
  line-height: 1.15;
  margin: 0;
  text-wrap: balance;
}

.person-lifespan {
  margin: 0.35rem 0 0;
  color: var(--tk-gallery-muted);
  font-variant-numeric: tabular-nums;
}

.person-section { margin-bottom: 2.5rem; }

.person-section > h2,
.person-empty > h2 {
  font-family: var(--font-display);
  font-size: 1.3rem;
  font-weight: 600;
  margin: 0 0 1rem;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--tk-gallery-line);
}

.person-empty > p {
  /* NOT the muted token. On a page with nothing else on it this paragraph is the
     content, and rendering the only message in secondary grey made the screen read
     as broken rather than as an honest "we have not read anything yet". */
  margin: 0;
  max-width: 34rem;
  color: var(--tk-text-secondary);
}

.fact-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
}

.fact > p { margin: 0; }

.fact-date {
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--tk-parchment-deep);
  font-variant-numeric: tabular-nums;
}

.fact-label { font-size: 1.05rem; margin-top: 0.15rem !important; }

.fact-source {
  margin-top: 0.2rem !important;
  font-size: 0.87rem;
  color: var(--tk-gallery-muted);
}

.fact-evidence { margin-top: 0.5rem; font-size: 0.9rem; }
.fact-evidence > summary { cursor: pointer; color: var(--tk-gallery-muted); }

.fact-evidence blockquote {
  margin: 0.5rem 0 0;
  padding-left: 0.9rem;
  border-left: 2px solid var(--tk-parchment);
  color: var(--tk-text-secondary);
}

/* Shown only when person.js has run, so a no-JS reader is never offered a dead control. */
.evidence-toggle { display: none; }
.family-body.has-js .evidence-toggle {
  display: inline-block;
  margin-bottom: 1rem;
  font: inherit;
  font-size: 0.87rem;
  padding: 0.35rem 0.75rem;
  cursor: pointer;
  color: var(--tk-text);
  background: var(--tk-bg-card);
  border: 1px solid var(--tk-gallery-line);
  border-radius: 3px;
}

/* Links wear the palette. The first screenshot of a person page showed the spouse's
   name in the browser's default blue against navy and parchment -- the one
   interactive element on the page was the one off-brand thing on it. Underlined
   rather than coloured-only, so the link is not signalled by hue alone. */
.family-main a {
  color: var(--tk-brown-600);
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}

.family-main a:hover { color: var(--tk-brown-800); }

/* The relation and the relative read as one line: "Spouse - Niels Larsen". */
.fact-label a { font-weight: 500; }

.relation-kind {
  text-transform: capitalize;
  color: var(--tk-gallery-muted);
}

/* --- Pictures -------------------------------------------------------------- */

/* Columns, not a grid of squares. Each photograph keeps its own proportions and
   the column absorbs the difference in height, so nothing is ever cropped to fit.
   `object-fit: cover` must never appear in this file -- a test enforces it. */
.gallery {
  columns: 2;
  column-gap: 1rem;
}

@media (min-width: 34rem) { .gallery { columns: 3; } }

.shot {
  margin: 0 0 1rem;
  break-inside: avoid;
}

.shot-open {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  cursor: zoom-in;
}

.shot-open img {
  display: block;
  width: 100%;
  height: auto;            /* the photograph's own shape, always */
  background: var(--tk-bg-card);
  border: 1px solid var(--tk-gallery-line);
}

.shot figcaption {
  margin-top: 0.35rem;
  font-size: 0.82rem;
  color: var(--tk-gallery-muted);
}

/* --- The shared viewer ----------------------------------------------------- */

body.viewer-open { overflow: hidden; }

/* `display: flex` below is more specific than the user agent's
   `[hidden] { display: none }`, so without this rule the dialog paints over the page
   from the first paint. Every test passed while that was true; only looking caught it. */
.viewer[hidden] { display: none; }

.viewer {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(1rem, 4vw, 3rem);
  /* Near-black, not the page ground: a photograph is judged against a neutral
     dark surround, and a pale one biases how bright and contrasty it looks. */
  background: rgba(11, 17, 32, 0.94);
}

.viewer-frame {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.75rem;
  max-width: 100%;
  max-height: 100%;
}

.viewer-image {
  max-width: 100%;
  max-height: 78vh;
  width: auto;
  height: auto;
  background: var(--tk-blue-950);
}

.viewer-caption {
  margin: 0;
  color: var(--tk-tan-soft);
  font-size: 0.9rem;
  text-align: center;
}

.viewer-close {
  position: absolute;
  top: -2.6rem;
  right: 0;
}

.viewer-close,
.viewer-step {
  font: inherit;
  font-size: 0.9rem;
  padding: 0.4rem 0.8rem;
  cursor: pointer;
  color: var(--tk-tan-soft);
  background: rgba(24, 35, 58, 0.85);
  border: 1px solid rgba(197, 165, 124, 0.4);
  border-radius: 3px;
}

/* In the flow, not over it. Absolutely positioning these against .viewer-frame
   centred them on the whole dialog -- image, slider and caption -- so they sat
   across the comparison control and clipped its labels. */
.viewer-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  max-width: 100%;
  min-height: 0;
}

.viewer-step {
  flex: 0 0 auto;
  font-size: 1.6rem;
  line-height: 1;
  padding: 0.3rem 0.7rem;
}

/* An object whose derivative has not been generated yet has no preview URL. Rather
   than an <img> with an empty src -- which re-requests the page and paints the
   browser's broken-image glyph -- the tile says so in words. */
.shot-pending {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 7rem;
  padding: 1rem;
  text-align: center;
  font-size: 0.82rem;
  color: var(--tk-gallery-muted);
  background: var(--tk-bg-card);
  border: 1px dashed var(--tk-gallery-line);
}

/* --- Before / after ---------------------------------------------------------
   A wipe rather than two images side by side: at the sizes a family reads on, a
   side-by-side pair gives two small photographs instead of one legible one. */

.viewer-stage { position: relative; display: flex; min-width: 0; }

.viewer-before {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  /* contain, never cover -- the overlay must line up with the frame beneath it
     and must not crop a face to do so. */
  object-fit: contain;
}

.viewer-compare {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  width: min(100%, 28rem);
}

.viewer-compare-label {
  font-size: 0.78rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--tk-tan-soft);
  white-space: nowrap;
}

.viewer-compare-range { flex: 1; accent-color: var(--tk-parchment); }

/* The tile says which photographs have been restored, so the comparison is not a
   control a reader has to discover by opening every picture in turn. */
.shot-restored {
  display: inline-block;
  margin-left: 0.35rem;
  padding: 0.05rem 0.4rem;
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--tk-brown-700);
  background: var(--tk-hover-fill);
  border-radius: 2px;
}

/* --- Albums ------------------------------------------------------------------
   A card fronted by a photograph. The count is present but subordinate: "3
   photographs" is not what anyone opens an album to find out. */

.page-title {
  font-family: var(--font-display);
  font-size: clamp(1.8rem, 5vw, 2.4rem);
  font-weight: 600;
  margin: 0 0 1.75rem;
}

.crumb { margin: 0 0 0.4rem; font-size: 0.85rem; }

.album-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
  gap: 1.5rem;
}

.album {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  text-decoration: none;
  color: inherit;
}

.album img {
  width: 100%;
  height: auto;                /* the cover keeps its own shape, like every other tile */
  background: var(--tk-bg-card);
  border: 1px solid var(--tk-gallery-line);
}

.album-cover-pending {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 8rem;
  font-size: 0.82rem;
  color: var(--tk-gallery-muted);
  background: var(--tk-bg-card);
  border: 1px dashed var(--tk-gallery-line);
}

.album-name {
  font-family: var(--font-display);
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--tk-text);
}

.album:hover .album-name { text-decoration: underline; }

.album-count { font-size: 0.82rem; color: var(--tk-gallery-muted); }

.family-nav { margin-right: auto; display: flex; gap: 1rem; }

.family-nav a {
  font-size: 0.9rem;
  color: var(--tk-tan-soft);
  text-decoration: none;
}

.family-nav a:hover { text-decoration: underline; }

/* The display-mode escape hatch, styled like its siblings in the same bar.
   Without this it inherits the browser default -- #0000EE with an underline --
   which measures 1.88:1 against the bar's own rgba(16, 24, 42, .96) and is
   effectively unreadable. The tan the other bar links use measures 12.30:1.

   A base rule rather than a mobile-only one: the bar renders this link on every
   device (it reads "Mobile site" on a desktop), so a rule inside the
   [data-device="mobile"] block would leave the desktop copy unstyled. */
.family-display-mode {
  font-size: 0.9rem;
  color: var(--tk-tan-soft);
  text-decoration: none;
}

.family-display-mode:hover { text-decoration: underline; }
/* --- Sharing ------------------------------------------------------------------ */

.viewer-actions {
  position: absolute;
  top: -2.6rem;
  right: 0;
  display: flex;
  gap: 0.5rem;
}

.viewer-share {
  font: inherit;
  font-size: 0.9rem;
  padding: 0.4rem 0.8rem;
  cursor: pointer;
  color: var(--tk-blue-950);
  background: var(--tk-parchment);
  border: 1px solid var(--tk-parchment-deep);
  border-radius: 3px;
}

.share-sheet[hidden] { display: none; }

.share-sheet {
  position: fixed;
  inset: 0;
  z-index: 60;                 /* above the viewer, which it is opened from */
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  background: rgba(11, 17, 32, 0.6);
}

.share-sheet-panel {
  width: min(30rem, 100%);
  max-height: 90vh;
  overflow-y: auto;
  padding: 1.5rem;
  background: var(--tk-bg-soft);
  border: 1px solid var(--tk-gallery-line);
  border-radius: 4px;
}

.share-sheet-panel h2 {
  font-family: var(--font-display);
  font-size: 1.2rem;
  font-weight: 600;
  margin: 0 0 1rem;
}

.share-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-bottom: 1rem;
}

.share-row button,
.share-native,
.share-close {
  font: inherit;
  font-size: 0.9rem;
  padding: 0.45rem 0.85rem;
  cursor: pointer;
  color: var(--tk-text);
  background: var(--tk-bg-card);
  border: 1px solid var(--tk-gallery-line);
  border-radius: 3px;
}

.share-row button:hover { background: var(--tk-hover-fill); }
.share-row button:disabled { opacity: 0.5; cursor: not-allowed; }

/* Says out loud which controls make a photograph public, rather than letting the
   confirmation be the first a person hears of it. */
.share-note {
  margin: 0 0 0.5rem;
  font-size: 0.82rem;
  color: var(--tk-gallery-muted);
}

.share-native-hint {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin: 0 0 1rem;
  font-size: 0.82rem;
  color: var(--tk-gallery-muted);
}

.share-native { background: var(--tk-parchment); border-color: var(--tk-parchment-deep); }

.share-confirm {
  padding: 0.9rem;
  margin-bottom: 1rem;
  background: var(--tk-hover-fill);
  border: 1px solid var(--tk-parchment-deep);
  border-radius: 3px;
}

.share-confirm p { margin: 0 0 0.6rem; }
.share-confirm label { display: block; margin-bottom: 0.8rem; font-size: 0.9rem; }
.share-confirm .share-row { margin-bottom: 0; }

.share-note-live {
  margin: 0.75rem 0 0;
  font-size: 0.87rem;
  color: var(--tk-brown-700);
}

/* --- Face tags ---------------------------------------------------------------
   Boxes sit over faces, which is exactly where somebody looking at a photograph
   wants to look -- so they are light, and there is a control to take them away. */

.tag-layer {
  position: absolute;
  inset: 0;
  pointer-events: none;      /* never in the way of the wipe underneath */
}

.tag-layer.is-hidden { display: none; }

.tag-box {
  position: absolute;
  border: 2px solid var(--tk-parchment);
  border-radius: 2px;
  box-shadow: 0 0 0 1px rgba(11, 17, 32, 0.45);
}

/* Revealed on hover, as the plan asks -- and on keyboard focus, because hover alone
   is unreachable without a mouse. Names-on pins them all, which is the only way to
   read them on a phone, where hover does not exist at all. */
.tag-name {
  position: absolute;
  left: 0;
  top: 100%;
  margin-top: 3px;
  padding: 0.1rem 0.4rem;
  font-size: 0.75rem;
  white-space: nowrap;
  color: var(--tk-blue-950);
  background: var(--tk-parchment);
  border-radius: 2px;
  opacity: 0;
  transition: opacity 120ms ease;
}

.tag-box:hover .tag-name,
.tag-box:focus-within .tag-name,
.tag-layer.names-on .tag-name { opacity: 1; }

/* The box itself stays faint until wanted: it sits over a face, which is the thing
   somebody opened the photograph to look at. */
.tag-box { opacity: 0.45; transition: opacity 120ms ease; }
.tag-box:hover,
.tag-box:focus-within,
.tag-layer.names-on .tag-box { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .tag-name, .tag-box { transition: none; }
}

.tag-toggle {
  font: inherit;
  font-size: 0.9rem;
  padding: 0.4rem 0.8rem;
  cursor: pointer;
  color: var(--tk-tan-soft);
  background: rgba(24, 35, 58, 0.85);
  border: 1px solid rgba(197, 165, 124, 0.4);
  border-radius: 3px;
}

/* --- The tree ------------------------------------------------------------------ */

.tree-key {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin: 0 0 1.5rem;
  font-size: 0.82rem;
  color: var(--tk-gallery-muted);
}

.edge-swatch {
  display: inline-block;
  width: 1.6rem;
  height: 0;
  border-top: 2px solid var(--tk-brown-600);
}

.edge-swatch.edge-uncertain { border-top-style: dashed; border-top-color: var(--tk-gallery-muted); }

.tree-people { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 1.25rem; }

.tree-person {
  padding-left: 0.9rem;
  border-left: 2px solid var(--tk-gallery-line);
}

.tree-person.is-root { border-left-color: var(--tk-parchment); }
.tree-person > a { font-family: var(--font-display); font-size: 1.1rem; font-weight: 600; }

.tree-edges { list-style: none; margin: 0.3rem 0 0; padding: 0; display: flex; flex-direction: column; gap: 0.2rem; }

.tree-edge { font-size: 0.9rem; color: var(--tk-gallery-muted); }

/* A dashed rule carries the doubt for anyone who does not read the words. */
.tree-edge.edge-uncertain { border-bottom: 1px dashed var(--tk-gallery-line); padding-bottom: 0.2rem; }

.edge-doubt {
  margin-left: 0.4rem;
  font-size: 0.72rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--tk-brown-400);
}

/* --- Remembered ---------------------------------------------------------------
   The recording leads and the transcript follows: the voice is what a grandchild
   came for, the words are what make it findable. */

.story-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 1.5rem; }

.story-audio { width: 100%; max-width: 26rem; margin-bottom: 0.5rem; }

.story blockquote {
  margin: 0;
  padding-left: 0.9rem;
  border-left: 2px solid var(--tk-parchment);
  color: var(--tk-text);
}

.story-teller { margin: 0.3rem 0 0; font-size: 0.85rem; color: var(--tk-gallery-muted); }

.story-record, .story-save {
  font: inherit;
  font-size: 0.9rem;
  padding: 0.45rem 0.9rem;
  cursor: pointer;
  color: var(--tk-blue-950);
  background: var(--tk-parchment);
  border: 1px solid var(--tk-parchment-deep);
  border-radius: 3px;
}

.story-status { margin: 0.5rem 0 0; font-size: 0.85rem; color: var(--tk-gallery-muted); }

.story-words {
  display: block;
  width: 100%;
  margin-top: 0.6rem;
  padding: 0.5rem;
  font: inherit;
  color: var(--tk-text);
  background: var(--tk-bg-card);
  border: 1px solid var(--tk-gallery-line);
  border-radius: 3px;
}

.story-save { margin-top: 0.6rem; }

.kin-actions { margin-left: 0.6rem; display: inline-flex; gap: 0.35rem; }

.kin-action {
  font: inherit;
  font-size: 0.75rem;
  padding: 0.15rem 0.45rem;
  cursor: pointer;
  color: var(--tk-gallery-muted);
  background: transparent;
  border: 1px solid var(--tk-gallery-line);
  border-radius: 2px;
}

.kin-action:hover { color: var(--tk-text); background: var(--tk-hover-fill); }

/* --- Joining, and getting back in --------------------------------------------- */

.join { max-width: 28rem; }
.join-note { margin: 0 0 1rem; color: var(--tk-text-secondary); }
.join-error {
  margin: 0 0 1rem;
  padding: 0.6rem 0.8rem;
  color: var(--tk-brown-800);
  background: var(--tk-hover-fill);
  border-left: 2px solid var(--danger, #B4442F);
}

.join-form { display: flex; flex-direction: column; gap: 0.9rem; margin-top: 1.25rem; }
.join-form label { display: flex; flex-direction: column; gap: 0.3rem; font-size: 0.9rem; }

.join-form input {
  font: inherit;
  padding: 0.5rem 0.6rem;
  color: var(--tk-text);
  background: var(--tk-bg-card);
  border: 1px solid var(--tk-gallery-line);
  border-radius: 3px;
}

.join-form button {
  align-self: flex-start;
  font: inherit;
  padding: 0.5rem 1rem;
  cursor: pointer;
  color: var(--tk-blue-950);
  background: var(--tk-parchment);
  border: 1px solid var(--tk-parchment-deep);
  border-radius: 3px;
}

/* --- Adding photographs, and deciding on them --------------------------------- */

.add-picker {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.9rem 1.1rem;
  cursor: pointer;
  background: var(--tk-bg-card);
  border: 1px dashed var(--tk-parchment-deep);
  border-radius: 4px;
}

/* The native input is hidden but still focusable: the surrounding label IS the
   control, and showing both meant the page offered the same button twice, one of
   them unstyled. clip-path rather than display:none, which would take the only
   control on the page out of the keyboard tab order. */
.add-picker input[type="file"] {
  position: absolute;
  width: 1px;
  height: 1px;
  clip-path: inset(50%);
  overflow: hidden;
}

.add-picker span { font-weight: 500; }

.add-picker:focus-within {
  outline: 2px solid var(--tk-brown-600);
  outline-offset: 2px;
}

.add-queue { list-style: none; margin: 1.25rem 0 0; padding: 0; display: flex; flex-direction: column; gap: 0.5rem; }

.add-row {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.5rem 0.7rem;
  font-size: 0.9rem;
  background: var(--tk-bg-card);
  border: 1px solid var(--tk-gallery-line);
  border-radius: 3px;
}

.add-state { color: var(--tk-gallery-muted); }
.add-state.add-failed { color: var(--tk-brown-800); font-weight: 500; }

.review-queue { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 1.5rem; }

.review-item {
  display: flex;
  gap: 1rem;
  align-items: flex-start;
  padding-bottom: 1.5rem;
  border-bottom: 1px solid var(--tk-gallery-line);
}

/* A fixed width, not a fixed box: the photograph keeps its shape here too. */
.review-item img {
  width: 9rem;
  height: auto;
  background: var(--tk-bg-card);
  border: 1px solid var(--tk-gallery-line);
}

.review-detail { flex: 1 1 auto; min-width: 0; }
.review-caption { margin: 0 0 0.2rem; font-size: 1.02rem; }
.review-actions { display: flex; gap: 0.5rem; margin-top: 0.8rem; }

.review-actions button {
  font: inherit;
  font-size: 0.9rem;
  padding: 0.4rem 0.9rem;
  cursor: pointer;
  border-radius: 3px;
  border: 1px solid var(--tk-gallery-line);
  background: var(--tk-bg-card);
  color: var(--tk-text);
}

.review-actions button[data-accept] {
  color: var(--tk-blue-950);
  background: var(--tk-parchment);
  border-color: var(--tk-parchment-deep);
}

.review-actions button:disabled { opacity: 0.5; cursor: not-allowed; }

/* ---------------------------------------------------------------------------
   The phone layout, keyed on the DEVICE rather than the window. The attribute
   is stamped server-side in family/base.html from the tk_device cookie, so a
   narrowed desktop window keeps the desktop arrangement and a phone does not
   merely get a squeezed one.
   --------------------------------------------------------------------------- */
[data-device="mobile"] .family-bar {
  flex-wrap: wrap;
  gap: 6px;
  padding: 8px 12px;
}

[data-device="mobile"] .family-nav {
  order: 3;
  width: 100%;
  gap: 2px;
  /* A row of links becomes a column. Side by side on a 390px screen they were
     4-5 characters wide each. */
  display: flex;
  flex-direction: column;
}

[data-device="mobile"] .family-nav a {
  display: flex;
  align-items: center;
  min-height: 44px;
  padding: 0 4px;
}

[data-device="mobile"] .family-display-mode {
  display: flex;
  align-items: center;
  min-height: 44px;
}

[data-device="mobile"] .family-who {
  font-size: 0.8rem;
}

[data-device="mobile"] .family-main {
  padding: 12px;
}

[data-device="mobile"] .gallery {
  /* .gallery is CSS multi-column (columns: 2, then 3 above 34rem), not a grid --
     it already renders 2 real columns on a 390px phone with no rule of ours. A
     grid-template-columns override here would be inert. column-gap (not the
     `gap` shorthand, which would misleadingly suggest a grid) just tightens the
     gutter so the images get a little more of the width. */
  column-gap: 6px;
}

[data-device="mobile"] .shot-open {
  min-height: 44px;
}

[data-device="mobile"] .album-grid {
  /* repeat(2, minmax(0, 1fr)) rather than the desktop's auto-fill with a 13rem
     floor: at 390px that floor resolves to a single 208px column and discards
     ~180px of width. A rem floor cannot express "two, whatever the width". */
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.75rem;
}
