/* Homes.me's image viewer: Vi.ki's wall.css, kept in step with it. --accent and --seam are the two names only Vi.ki's
   page defines. */
.viewer { --accent: var(--gold); --seam: 4px; }
.v-sift-btn, .v-rate { display: none !important; }
/* George, Nov 1, 2026: "on homes.me galleries hide the ?, settings, info icons, browse and clickless pills to keep it very simple". */
.v-help, .v-gear-btn, .v-info-btn, .v-switches { display: none !important; }
/* vi.ki: the wall and the viewer.
 *
 * Modeled on heart.photos' gallery: justified rows solved in CSS from each tile's aspect ratio,
 * and a <dialog> viewer with the picture fitted to the pane and a row of thumbnails along any of
 * its four edges. The viewer is dark on both palettes: a photograph is looked at on black.
 */

/* --- the wall ---------------------------------------------------------------------------------
   Rows are justified: each row is scaled so it fills the width exactly, the way a contact sheet
   does. Widths come from flex-grow driven by aspect ratio (--r on the tile, set by the server and
   by wall.js), so a row of wide photos and a row of tall ones both end flush without any
   measuring in JavaScript. The last row would otherwise stretch a lone photo across the whole
   width, so a huge invisible filler takes what is left of it. */
/* The row height is times THUMBNAIL SIZE (--thumb-scale, wall.js), which the viewer's row of
   thumbnails follows as well. */
/* ...never taller than most of the window, where a row stops being a row of a wall. */
.wall { --row-h: min(calc(240px * var(--thumb-scale, 1)), 85vh); --seam: 4px; display: flex; flex-wrap: wrap; gap: var(--seam); }
.wall::after { content: ""; flex-grow: 999999; }
.wall .tile {
  position: relative; display: block; overflow: hidden; min-width: 0;
  border-radius: 8px;
  /* The tile holds its place before its picture arrives; a tone between the page and the
     panel says "loading" rather than "broken". */
  background: var(--line);
  flex-grow: var(--r, 1.5); flex-basis: calc(var(--r, 1.5) * var(--row-h)); height: var(--row-h);
  /* Above 100% Thumbnail size, no more than a tenth wider than its own shape (--grow-max, wall.js):
     a row of one big photograph gave it the whole width and cut half of it away. At 100% and below
     nothing caps it and every row still ends flush. */
  max-width: calc(var(--r, 1.5) * var(--row-h) * var(--grow-max, 1000));
  margin: 0; padding: 0; border: 0; cursor: zoom-in;
  transition: transform .18s ease, box-shadow .18s ease;
}
.wall .tile:hover, .wall .tile:focus-visible { transform: translateY(-2px); box-shadow: var(--shadow); outline: none; }
.wall .tile img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Where you are on this wall: the photograph just closed in the viewer. Drawn inside the
   picture, because the wall runs to the edges and a ring hung outside would be cut in half. */
.wall .tile.current::after, .wall .tile:focus-visible::after {
  content: ""; position: absolute; inset: 0; z-index: 4; border-radius: inherit; pointer-events: none;
  box-shadow: inset 0 0 0 1px var(--accent), inset 0 0 0 2px rgba(255, 255, 255, .3);
}
.wall .tile.pending img { opacity: .5; filter: grayscale(.6); }
/* On a phone a justified row holds one photo anyway, and a fixed row height then crops every
   portrait into a landscape strip. One per row at its own shape shows the photograph instead. */
@media (max-width: 700px) {
  .wall .tile { height: auto; flex: 1 1 100%; max-width: none; }
  .wall .tile img { height: auto; aspect-ratio: var(--r, 1.5); max-height: 62vh; }
  .wall::after { content: none; }
}
@media (prefers-reduced-motion: reduce) {
  .wall .tile { transition: none; }
}

/* --- the viewer -------------------------------------------------------------------------------
   The dialog is the screen. Everything inside it is positioned against it, because a modal
   dialog lives in the top layer and fills the window whether or not the page is in fullscreen.
   dvh, not 100%: a percentage height in the top layer resolves against the viewport as it would
   be with a phone's address bar out of the way, which is taller than what can be seen. */
.viewer {
  /* Times THUMBNAIL SIZE, as the wall's rows are, and never more than two fifths of the window:
     past that the row is taking the photograph's room rather than showing it. */
  --strip-h: min(calc(150px * var(--thumb-scale, 1)), 40vh);
  --strip-w: min(calc(220px * var(--thumb-scale, 1)), 40vw);
  --seam: 3px;
  border: 0; padding: 0; margin: 0; width: 100%; height: 100%; max-width: 100%; max-height: 100%;
  background: rgb(6 6 8 / .97); color: #fff; overflow: hidden;
  display: none;
}
.viewer[open] { display: block; }
@supports (height: 100dvh) {
  .viewer[open] { height: 100dvh; max-height: 100dvh; }
}
@supports (width: 100dvw) {
  @media (pointer: coarse) and (max-width: 950px) {
    .viewer[open] { width: 100dvw; max-width: 100dvw; }
  }
}
.viewer::backdrop { background: rgb(6 6 8 / .9); }
/* While a photo is open the page behind it must not scroll. The padding replaces the width the
   scrollbar was occupying, so the wall does not jump sideways as the viewer opens and closes. */
html.viewer-open { overflow: hidden; }
html.viewer-open body { padding-right: var(--sbw, 0px); }

/* The stage is the whole dialog less the strip's edge; the pane inside it holds the picture and
   the caption bar sits under the pane. */
.viewer .stage { position: absolute; inset: 0; display: flex; flex-direction: column; }
.viewer.strip-bottom .stage { padding-bottom: var(--strip-h); }
.viewer.strip-top .stage { padding-top: var(--strip-h); }
.viewer.strip-left .stage { padding-left: var(--strip-w); }
.viewer.strip-right .stage { padding-right: var(--strip-w); }
.viewer .pane { position: relative; flex: 1 1 auto; min-height: 0; }
/* A pinch on the picture is the picture's (wall.js), not the page's. */
.viewer[open] .pane { touch-action: none; }
/* Two layers, one over the other: the next photograph decodes in the hidden one and is brought
   up when it is ready, so the picture is never emptied and no black is seen. */
.viewer .pane .shot {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; display: block;
  padding: var(--seam); opacity: 0;
}
.viewer .pane .shot.on { opacity: 1; }
/* Zoom and pan are one transform, set on both layers so a swap mid-zoom cannot land on a
   picture that is somewhere else. A stepped zoom eases; following the pointer must not, or
   the picture is a frame behind the hand. The transition is declared here and taken away
   while tracking, because a transition only starts when the property was transitionable
   before the change. */
.viewer .pane .shot { transform-origin: 50% 50%; transition: transform .16s cubic-bezier(.2, .7, .3, 1); }
.viewer .pane.tracking .shot { transition: none; }
@media (prefers-reduced-motion: reduce) { .viewer .pane .shot { transition: none; } }
/* A picture larger than its pane is cut off at the pane, not spilled over the caption and the
   row of thumbnails below it... and a seam inside it, the gap the thumbnails keep between them, so
   a zoomed picture stands off the row as a fitted one does (George, 25 September 2026: it ran
   right up to the thumbnails). */
.viewer .pane.zoomed { overflow: hidden; clip-path: inset(var(--seam)); }
.viewer .pane .shot[src=""] { visibility: hidden; }

/* The caption bar: ONE line, the page the photograph is used on and then its caption, centered
   and never over the picture (George, 17 September 2026; the credit, source and license moved to
   Info). Cut with an ellipsis, and there even when empty, so the bar is the same height for every
   photograph and the picture does not jump along the row (George, 16 September 2026). The whole
   line is in its title, for the pointer. */
.viewer .caption-bar {
  flex: none; padding: .45rem 4.5rem .55rem; text-align: center; font-size: .9rem; line-height: 1.4;
  color: #d8d8de;
}
.viewer .cap-text {
  height: 1.4em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* BESIDE the thumbnails (George, Oct 17, 2026: "move the description line currently below the big
   image to be just below the thumbnails when the thumbnails are at the top or left and just above the
   thumbnails when they are at the bottom"): above the picture with them along the top or down a side
   (the right is treated as the left), under it with them along the foot. From 25 September 2026 to
   then it was on the side away from them. */
.viewer .caption-bar { order: -1; }
.viewer.strip-bottom .caption-bar { order: 0; }
.viewer .cap-text { color: #fff; }
.viewer .cap-text a { color: #cfd6ff; font-weight: 600; }
.viewer .cap-text .sep { margin: 0 .45rem; opacity: .6; }
.viewer .cap-pending { color: var(--moment, #ffb057); }

/* The three answers, in the row across the top of the picture beside Browse, Clickless and 100%
   (George, 18 September 2026): that row is where every control that acts on the photograph on
   screen lives, and the caption under it is for the words about it. Liked, no opinion, disliked,
   each with how many people said it; the one this reader chose is lit, and the keys + - and 0 say
   the same thing and walk the whole scale of nine. */
.viewer .v-rate {
  display: inline-flex; align-items: center; gap: 0; height: 2.1rem; padding: 0 .15rem;
  border-radius: 999px; background: rgb(0 0 0 / .45); max-width: 100%;
}
.viewer .v-rate[hidden] { display: none; }
.viewer .v-rate-btn {
  display: inline-flex; align-items: center; gap: .3rem; height: 1.8rem; padding: 0 .5rem; margin: 0 .1rem;
  border: 0; border-radius: 999px; cursor: pointer; font: inherit; font-size: .82rem; line-height: 1;
  color: #e7e9ec; background: none; transition: background .15s ease, color .15s ease;
}
.viewer .v-rate-btn:hover, .viewer .v-rate-btn:focus-visible { background: rgb(255 255 255 / .18); outline: none; }
.viewer .v-rate-btn.on { background: #e8eaf6; color: #17181c; }
.viewer .v-rate-btn svg { display: block; }
.viewer .v-rate-n { font-variant-numeric: tabular-nums; }
.viewer .v-rate-said { font-size: .8rem; color: #c8cad2; padding: 0 .35rem 0 .15rem; }
/* The one line that will not fit in a row of pills: what a press did, for somebody it is not being
   kept for. Under the row, where the row is. */
.viewer .v-rate-note {
  position: absolute; z-index: 3; top: 3.1rem; left: 50%; transform: translateX(-50%);
  max-width: min(90%, 28rem); text-align: center;
  font-size: .8rem; color: #e7e9ec; background: rgb(0 0 0 / .55);
  border-radius: 999px; padding: .2rem .7rem;
}
.viewer .v-rate-note[hidden], .viewer .v-rate-note:empty { display: none; }
.viewer .v-rate-note a { color: #cfd6ff; font-weight: 600; }

.viewer .v-info-raters { list-style: none; margin: 0; padding: 0; }

/* The round buttons: close, then the gear, then Info, then the counter, along the top left, and the two
   arrows at the sides of the pane. Translucent on the picture, brighter under the hand.
   The way out is the first thing on the bar and at the corner the eye starts from, rather
   than across the picture from everything else (George, 16 September 2026). */
.viewer .v-btn {
  position: absolute; z-index: 3; width: 2.5rem; height: 2.5rem; padding: 0;
  border: 0; border-radius: 999px; cursor: pointer; font: inherit; font-size: 1.3rem; line-height: 1;
  background: rgb(0 0 0 / .45); color: #fff; display: grid; place-items: center;
  transition: background .15s ease, opacity .15s ease;
}
.viewer .v-btn:hover, .viewer .v-btn:focus-visible { background: rgb(0 0 0 / .75); outline: none; }
.viewer .v-btn:focus-visible { box-shadow: 0 0 0 2px #fff; }
.viewer .v-btn svg { display: block; }
/* ...and they all sit in ONE bar across the top, read left to right (George, 18 September 2026):
   the way out, what you think of the photograph, which one of how many with an arrow either side,
   the switches, then settings and info at the far edge. The arrows used to stand at the sides of
   the picture, over it; they belong with the counter, which is the thing they change. */
.viewer .v-bar {
  position: absolute; z-index: 3; top: .6rem; left: .6rem; right: .6rem;
  display: flex; align-items: flex-start; gap: .5rem; pointer-events: none;
}
.viewer .v-bar-group { display: flex; align-items: center; gap: .4rem; pointer-events: auto; }
.viewer .v-bar-group.mid { flex: 1 1 auto; justify-content: center; min-width: 0; flex-wrap: wrap; row-gap: .4rem; }
.viewer .v-bar-group.right { flex-wrap: wrap; justify-content: flex-end; row-gap: .4rem; }
/* GROUPED BUTTONS, a setting, off unless turned on (George, 26 September 2026): the three groups
   side by side in the middle, in the order they read, rather than the way out at the left edge
   and settings and info at the right. */
.viewer.bar-grouped .v-bar { justify-content: center; }
.viewer.bar-grouped .v-bar-group.mid { flex: 0 1 auto; }
.viewer .v-btn { position: static; flex: none; }
/* Info open: the same dark round as every other button, the mark in the theme's color, as the
   filter's is when it is on. A pale round with a white mark vanished over a bright photograph
   (George, 25 September 2026). */
.viewer .v-info-btn.on { color: var(--accent, #ff6b57); }
/* The counter and its two arrows, one thing: "‹ 3 of 60 ›". */
.viewer .v-nav {
  display: inline-flex; align-items: center; gap: .1rem; height: 2.1rem; padding: 0 .35rem;
  border-radius: 999px; background: rgb(0 0 0 / .45); color: #e7e9ec;
}
/* .v-nav sets its own display, which beats the browser's rule for [hidden]. */
.viewer .v-nav[hidden] { display: none; }
.viewer .v-nav .v-btn { width: 1.9rem; height: 1.9rem; background: none; }
/* .v-btn sets display: grid, which BEATS the browser's own rule for [hidden] -- the trap this
   file warns about three times and fell into anyway (George, 23 September 2026: "toggling
   Next/prev buttons does nothing"). The arrows are the setting; the number between them is not,
   so it is the arrows that have to be able to go.

   They GO, room and all (George, 23 September 2026: "don't reserve space for the next/prev
   buttons, just insert them when the setting is on and remove them when off"). They kept their
   room for an hour, which held the number still and left two blanks in the bar; a setting that
   shows nothing and takes the space anyway is furniture. */
.viewer .v-nav .v-btn[hidden] { display: none; }
.viewer .v-nav .v-btn:hover, .viewer .v-nav .v-btn:focus-visible { background: rgb(255 255 255 / .18); }
.viewer .v-count {
  color: #e7e9ec; font-variant-numeric: tabular-nums;
  padding: 0 .35rem; white-space: nowrap;
  /* ...and the same line box as the tally, or the number sits four tenths of a pixel lower with
     the arrows on than without them, which rounds to a visible flinch in a number that has not
     changed (George, 20 September 2026; measured on the live page, 139.16 against 138.76). Both
     are centered in a pill of the same height; what differed was the leading around the text. */
  line-height: 1;
}
/* ONE size for the count, wherever it happens to be standing. The same number moves between the
   two as the arrows are turned on and off, and a size that changed with it was a visible flinch
   in a number that had not changed (George, 20 September 2026). */
.viewer .v-count, .viewer .v-tally { font-size: .82rem; }
.viewer .v-count:empty { display: none; }
/* With Clickless pan off, a zoomed picture is taken hold of and moved, so the pointer says so:
   open while it can be taken, closed while it is being moved. With the setting ON the picture
   follows a bare pointer and there is nothing to take hold of. */
.viewer .pane.zoomed.can-drag { cursor: grab; }
.viewer .pane.dragging { cursor: grabbing; }
/* The always-on copy, beside the ratings: dressed as the switches are, because it stands in that
   row and a bare number among pills reads as something that fell off one. Tabular figures, so the
   width does not shift as the number climbs. */
/* The number itself, inside the arrows' own pill. ONE dark ground, not two: it carried a pill of
   its own while it lived out past the switches, and nested inside this one that reads as a blob
   with a blob in it (George, 23 September 2026). The pill is the group's, and it is there whether
   or not the arrows are. */
.viewer .v-tally {
  display: inline-flex; align-items: center; padding: 0 .35rem;
  color: #e7e9ec; line-height: 1; font-variant-numeric: tabular-nums; white-space: nowrap;
}
/* The gear's menu: where the thumbnails go. Four choices, one checked, and the key for a
   setting at the right end of its line. */
/* Heart Photos' gear menu's ground, edge and shadow (George, Oct 17, 2026: "on all vi.ki sites use the same background color for the settings dropdown as we use on heart.photos and use "Reset defaults" as the phrase everywhere not "Restore defaults""). */
.viewer .v-menu {
  position: absolute; z-index: 4; top: 3.4rem; right: .6rem; min-width: 13rem;
  background: rgb(36 36 44 / .98); border: 1px solid rgb(255 255 255 / .26); border-radius: 12px; padding: .35rem;
  box-shadow: 0 14px 40px rgb(0 0 0 / .7);
}
.viewer .v-menu[hidden] { display: none; }
/* The funnel's menu hangs from a button in the MIDDLE of the row rather than at its end, so it is
   centered on its own button instead of pinned to the row's right edge. */
.viewer .v-menu.v-sift { right: auto; left: 50%; transform: translateX(-50%); }
/* Six answers to Show and three to Order are taller than a phone held sideways, so the menu scrolls
   inside itself rather than running off the bottom of the screen. */
/* ...and every menu, the settings above all, scrolls inside itself when it is taller than the
   picture's room below the bar (George, 25 September 2026): the settings ran off the foot of the
   window with no way to reach the last of them. The menus hang in the pane, so 100% is its height. */
.viewer .v-menu { max-height: calc(100% - 4rem); overflow-y: auto; overscroll-behavior: contain; }
/* What a sift came to, when it came to nothing. */
.viewer .v-menu .v-sift-note { text-transform: none; letter-spacing: 0; color: #cfd4dc; padding-top: .5rem; }
.viewer .v-menu .v-sift-note[hidden] { display: none; }
/* THE HEIGHT OF THE ROW. .v-btn is 2.5rem, which is the size of the round buttons that float over
   the picture at its corners; in the bar everything else is 2.1rem, and the funnel's circle stood
   proud of the rest at top and bottom (George, 23 September 2026). */
.viewer .v-bar .v-sift-btn { width: 2.1rem; height: 2.1rem; }
/* Lit while the wall, or a page's photographs, are narrowed or sorted: a reader who left a sort on
   deserves to see why the list is not the list they remember. It is on every viewer, a page's as
   well as the wall's, so nothing here hides it. */
.viewer .v-sift-btn.on { color: var(--accent, #ff6b57); }
.viewer .v-menu button:disabled { opacity: .45; cursor: default; }
.viewer .v-menu p {
  display: flex; align-items: center; justify-content: space-between; gap: .6rem;
  margin: 0; padding: .3rem .6rem .15rem; font-size: .72rem; text-transform: uppercase; letter-spacing: .06em; color: #a2a9b3;
}
.viewer .v-menu button {
  display: flex; width: 100%; gap: .45rem; align-items: baseline; text-align: left;
  padding: .4rem .6rem; border: 0; border-radius: 6px; background: none; font: inherit; font-size: .9rem;
  color: #fff; cursor: pointer;
}
.viewer .v-menu button:hover, .viewer .v-menu button:focus-visible { background: rgb(255 255 255 / .1); outline: none; }
/* A display of its own beats the browser's own rule for [hidden], and Browse leaves the menu on a
   viki whose thumbnails all fit, just as it leaves the row of switches (wall.js). */
.viewer .v-menu button[hidden] { display: none; }
/* The key, at the right end: dressed as a key everywhere else on the site dresses one, so it reads
   as something to press rather than as a letter left over from the name. */
.viewer .v-menu .v-key {
  margin-left: auto; flex: none; font: inherit; font-size: .72rem; line-height: 1;
  padding: .18rem .38rem; border: 1px solid rgb(255 255 255 / .22); border-bottom-width: 2px;
  border-radius: 4px; background: rgb(255 255 255 / .08); color: #cfd4dc;
}
/* Reset defaults: above the settings, with a line under it, and no tick column, because it is
   the way back rather than one more thing to turn on. */
/* Everything back the way it came, at the foot of the menu: CENTERED, and dressed as the button it
   is -- the same violet pill Heart Photos' private-photo page offers "All photos" with (George,
   21 September 2026). Every row above answers a question and is the width of the menu; this one
   acts, so it is the width of its own words.
   Disabled rather than taken away when there is nothing to put back: a button that comes and goes
   moves everything under it and leaves a reader hunting for it. */
.viewer .v-menu .v-reset {
  display: flex; align-items: center; justify-content: center; width: fit-content;
  margin: .5rem auto .2rem; padding: .35rem 1rem;
  border: 1px solid rgb(138 125 255 / .7); border-radius: 999px;
  background: rgb(138 125 255 / .3); font-size: .82rem; color: #e3e3e3;
}
.viewer .v-menu .v-reset:hover:not(:disabled), .viewer .v-menu .v-reset:focus-visible:not(:disabled) {
  background: rgb(138 125 255 / .42); border-color: rgb(138 125 255 / .9); color: #fff;
}
.viewer .v-menu .v-reset:disabled { opacity: .38; cursor: default; }
.viewer .v-menu button .tick { flex: none; width: .9rem; color: var(--accent, #ff6b57); }
/* Thumbnail size: its name, the slider taking the rest of the line, and the per-cent. The name
   starts where the ticked lines' words do. */
.viewer .v-menu .v-size { display: flex; align-items: center; gap: .6rem; padding: .4rem .6rem .4rem 1.95rem; font-size: .9rem; }
.viewer .v-menu .v-size-name { flex: none; white-space: nowrap; }
.viewer .v-menu .v-size input { flex: 1 1 auto; min-width: 5rem; }
.viewer .v-menu .v-size-val { flex: none; min-width: 2.4rem; text-align: right; font-size: .75rem; color: #cfd4dc; font-variant-numeric: tabular-nums; }
/* ...and the wall's own, beside its heading. Not on a phone, where the wall is one photograph to
   a line at its own shape and there is no row height to change. */
.wall-head { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; flex-wrap: wrap; }
.wall-size { display: flex; align-items: center; gap: .6rem; font-size: .85rem; color: var(--muted); }
.wall-size[hidden] { display: none; }
.wall-size input { width: 9rem; }
.wall-size output { min-width: 2.6rem; text-align: right; font-variant-numeric: tabular-nums; }
@media (max-width: 700px) { .wall-size { display: none; } }
.viewer .v-menu button[aria-checked="false"] .tick { visibility: hidden; }

/* --- Info ------------------------------------------------------------------------------------
   A sidebar at the right edge with everything known about the photograph: the caption in full,
   the credit, the source, the license, where it is used, its description, size and address
   (George, 17 September 2026). The stage makes room for it, so nothing of the picture is under
   it; it starts below a row of thumbnails along the top, ends above one along the bottom, and
   stands inside one down the right. */
.viewer { --info-w: 20rem; }
.viewer .v-info {
  position: absolute; z-index: 4; top: 0; bottom: 0; right: 0; width: var(--info-w);
  display: flex; flex-direction: column;
  background: #111116; border-left: 1px solid rgb(255 255 255 / .1); color: #d8d8de;
}
.viewer .v-info[hidden] { display: none; }
.viewer.strip-top .v-info { top: var(--strip-h); }
.viewer.strip-bottom .v-info { bottom: var(--strip-h); }
/* EXTEND SIDEBAR (George, 25 September 2026; off unless turned on): Info the whole height of the window
   beside a row along the top or the foot, and the ROW stopping at its edge, with its arrow, so
   nothing in it is under Info. Not on a phone, where Info lies over the picture. */
@media (min-width: 701px) {
  .viewer.info-extend.strip-top .v-info { top: 0; }
  .viewer.info-extend.strip-bottom .v-info { bottom: 0; }
  .viewer.info-extend.info-open.strip-top .strip,
  .viewer.info-extend.info-open.strip-bottom .strip { right: var(--info-w); }
  .viewer.info-extend.info-open.strip-top .strip-page.next,
  .viewer.info-extend.info-open.strip-bottom .strip-page.next { right: var(--info-w); }
}
.viewer.strip-right .v-info { right: var(--strip-w); }
.viewer.info-open .stage { padding-right: var(--info-w); }
.viewer.info-open.strip-right .stage { padding-right: calc(var(--strip-w) + var(--info-w)); }
.viewer .v-info-head {
  flex: none; display: flex; align-items: center; justify-content: space-between;
  padding: .55rem .55rem .35rem 1.1rem;
}
.viewer .v-info-head h2 {
  margin: 0; min-width: 0; font-size: 1rem; font-weight: 600; color: #fff;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.viewer .v-info-head h2.untitled { color: #8b93a0; font-weight: 400; }
.viewer .v-info .v-btn { position: static; width: 2.25rem; height: 2.25rem; background: none; }
.viewer .v-info .v-btn:hover, .viewer .v-info .v-btn:focus-visible { background: rgb(255 255 255 / .1); }
.viewer .v-info-body {
  flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
  padding: .1rem 1.1rem 1.4rem; font-size: .88rem; line-height: 1.5;
}
.viewer .v-info-caption { margin: 0 0 .9rem; color: #fff; font-size: .95rem; }
/* What it shows, and then its size and when it was added: no labels, and no lines between any of
   the panel's parts (George, 24 September 2026); the space is enough. */
.viewer .v-info-desc { margin: 0 0 .9rem; color: #d7dbe2; }
.viewer .v-info-meta { margin: 0 0 .6rem; display: flex; flex-direction: column; gap: .15rem; color: #aab1bc; font-variant-numeric: tabular-nums; }
.viewer .v-info dl { margin: 0; }
.viewer .v-info dl > div { padding: .45rem 0; }
/* A heading in the Info panel: in the theme's own color, in sentence case as it is written, the
   size of the words under it and a weight heavier (George, 25 September 2026, as on Heart Photos).
   It was small gray capitals, which did not stand out from what they head. */
.viewer .v-info dt { margin: 0 0 .1rem; font-size: inherit; font-weight: 600; color: var(--accent, #ff6b57); }
.viewer .v-info dd { margin: 0; overflow-wrap: anywhere; }
.viewer .v-info a { color: #cfd6ff; }

/* --- the strip -------------------------------------------------------------------------------
   A row of every loaded photo along one edge of the viewer, so moving to a particular one does
   not mean arrowing past everything between. Along the top or the bottom it is a row; down the
   left or the right it is the same row stood on its end, --strip-w across. The current one is
   marked from the inside, so the mark takes no room from the row. No scrollbar drawn: the row
   already says where it is by the current thumbnail being in the middle. */
.viewer .strip {
  position: absolute; z-index: 2; left: 0; right: 0; bottom: 0; height: var(--strip-h);
  display: flex; gap: var(--seam); padding: 0; align-items: flex-start; justify-content: safe center;
  overflow-x: auto; overflow-y: hidden; scrollbar-width: none;
  background: linear-gradient(to bottom, rgb(0 0 0 / .78), rgb(0 0 0 / 0));
}
.viewer .strip::-webkit-scrollbar { display: none; }
.viewer.strip-top .strip { top: 0; bottom: auto; }
.viewer.strip-left .strip, .viewer.strip-right .strip {
  top: 0; bottom: 0; height: auto; width: var(--strip-w); flex-direction: column;
  overflow-x: hidden; overflow-y: auto;
  background: linear-gradient(to right, rgb(0 0 0 / .78), rgb(0 0 0 / 0));
}
.viewer.strip-left .strip { left: 0; right: auto; }
.viewer.strip-right .strip { right: 0; left: auto; background: linear-gradient(to left, rgb(0 0 0 / .78), rgb(0 0 0 / 0)); }
.viewer .strip-thumb {
  position: relative; flex: 0 0 auto; width: var(--strip-w); height: var(--strip-h); padding: 0;
  border: 0; border-radius: 0; background: #1a1a20; cursor: pointer; overflow: hidden;
}
/* Down a side the thumbnails are the same size as along the top (George, 24 September 2026), so
   the column is --strip-w across and each thumbnail the box it is in a row: no rule of their own. */
.viewer .strip-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* The last place in the row, away from the wall: the rest of the photographs on this viki. */
.viewer .strip-more {
  display: flex; align-items: center; justify-content: center; gap: .35rem;
  color: #fff; font: inherit; font-size: 1.64rem; line-height: 1; letter-spacing: .01em;
  background: #23232b;
}
.viewer .strip-more svg { width: 1.64rem; height: 1.64rem; flex: none; transition: transform .15s ease; }
.viewer .strip-more:hover svg { transform: translateX(3px); }
.viewer.strip-left .strip-more svg, .viewer.strip-right .strip-more svg { transform: rotate(90deg); }
.viewer.strip-left .strip-more:hover svg, .viewer.strip-right .strip-more:hover svg { transform: rotate(90deg) translateX(3px); }
.viewer .strip-more:disabled { color: #a2a9b3; }
.viewer .strip-thumb::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  box-shadow: inset 0 0 0 0 transparent; transition: box-shadow .15s ease;
}
.viewer .strip-thumb:hover::after { box-shadow: inset 0 0 0 2px rgb(255 255 255 / .7); }
.viewer .strip-thumb:focus-visible { outline: none; }
.viewer .strip-thumb:focus-visible::after { box-shadow: inset 0 0 0 1px #fff; }
.viewer .strip-thumb.on::after { box-shadow: inset 0 0 0 2px var(--accent, #ff6b57); }
/* WHERE THE ZOOM IS, on the photograph's own thumbnail: a white hairline box with a dark one
   either side of it, so it is legible over a light picture and over a dark one (wall.js). The same
   mark Heart Photos draws. */
.viewer .strip-zoom {
  position: absolute; z-index: 1; pointer-events: none; box-sizing: border-box;
  border: 1.5px solid #fff; border-radius: 1px;
  box-shadow: 0 0 0 1px rgb(0 0 0 / .55), inset 0 0 0 1px rgb(0 0 0 / .35);
}
/* The strip is one thumbnail thick across its axis, so a finger on it pans the row only. */
.viewer .strip-thumb { touch-action: pan-x; }
.viewer.strip-left .strip-thumb, .viewer.strip-right .strip-thumb { touch-action: pan-y; }

/* Browse and Clickless, as heart.photos draws them: a word and a pill whose knob sits left for off
   and right for on, the track lit when on. Centered at the top of the picture, just under the row
   when the row is along the top, which is where the hand that sweeps it already is. */
.viewer .v-switches { display: flex; gap: .35rem; align-items: center; flex-wrap: wrap; justify-content: flex-end; }
/* A narrow picture (a phone, or a window with Info open) has no room for the switches between
   the buttons on the left: they take a row of their own under the buttons. */
.viewer .pane { container: viewer-pane / inline-size; }
@container viewer-pane (max-width: 44rem) {
  /* No room for one row across a narrow picture: the groups stack, and the middle keeps its own
     line so the ratings are never squeezed between two sets of controls. */
  .viewer .v-bar { flex-wrap: wrap; }
  .viewer .v-bar-group.mid { order: 3; flex-basis: 100%; justify-content: flex-start; }
  /* ...and grouped, the way out and settings and info share the first line in the middle, and the
     middle's own line is centered under them. */
  .viewer.bar-grouped .v-bar-group.mid { flex-basis: 100%; justify-content: center; }
  .viewer .v-rate-note { top: 6.2rem; left: .6rem; transform: none; text-align: left; }
}
.viewer .v-switch {
  display: inline-flex; align-items: center; gap: 7px; height: 2.1rem; padding: 0 .7rem;
  border: 0; border-radius: 999px; cursor: pointer; font: inherit; font-size: .82rem; line-height: 1;
  color: #e7e9ec; background: rgb(0 0 0 / .45); transition: background .15s ease;
}
.viewer .v-switch[hidden] { display: none; }
.viewer .v-switch:hover, .viewer .v-switch:focus-visible { background: rgb(0 0 0 / .75); outline: none; }
.viewer .v-switch:focus-visible { box-shadow: 0 0 0 2px #fff; }
.viewer .v-pill {
  flex: 0 0 auto; display: inline-flex; align-items: center; pointer-events: none;
  width: 34px; height: 19px; padding: 2px; border-radius: 999px;
  background: rgb(255 255 255 / .16); transition: background .15s ease;
}
.viewer .v-knob {
  width: 15px; height: 15px; border-radius: 50%; background: rgb(255 255 255 / .6);
  transition: transform .15s ease, background .15s ease;
}
.viewer .v-switch.on .v-pill { background: var(--accent, #ff6b57); }
.viewer .v-switch.on .v-knob { transform: translateX(15px); background: #fff; }
@media (prefers-reduced-motion: reduce) {
  .viewer .v-pill, .viewer .v-knob { transition: none; }
}
/* The row's own arrows, at its two ends: a screenful at a time while the row holds still, the
   next fifty while browsing. A disc under the chevron so it reads as a button, on a fade so the
   thumbnail under it is still a picture. */
.viewer .strip-page {
  position: absolute; z-index: 3; bottom: 0; width: 58px; height: var(--strip-h);
  border: 0; padding: 0; cursor: pointer; color: #fff; display: grid; place-items: center;
  background: linear-gradient(to right, rgb(0 0 0 / .75), rgb(0 0 0 / 0));
  opacity: .92; transition: opacity .15s ease;
}
.viewer .strip-page::before {
  content: ""; position: absolute; z-index: -1; width: 34px; height: 34px; border-radius: 999px;
  background: rgb(18 18 22 / .82); border: 1px solid rgb(255 255 255 / .22);
}
.viewer .strip-page svg { position: relative; }
.viewer .strip-page:hover::before { background: rgb(30 30 36 / .92); border-color: rgb(255 255 255 / .5); }
.viewer .strip-page:hover, .viewer .strip-page:focus-visible { opacity: 1; outline: none; }
.viewer .strip-page:focus-visible { box-shadow: inset 0 0 0 1px #fff; }
.viewer .strip-page.prev { left: 0; }
.viewer .strip-page.next { right: 0; background: linear-gradient(to left, rgb(0 0 0 / .72), rgb(0 0 0 / 0)); }
.viewer .strip-page[hidden] { display: none; }
.viewer.strip-top .strip-page { top: 0; bottom: auto; }
.viewer.strip-left .strip-page, .viewer.strip-right .strip-page {
  width: var(--strip-w); height: 58px;
  background: linear-gradient(to bottom, rgb(0 0 0 / .75), rgb(0 0 0 / 0));
}
.viewer.strip-left .strip-page { left: 0; right: auto; }
.viewer.strip-right .strip-page { right: 0; left: auto; }
.viewer.strip-left .strip-page.prev, .viewer.strip-right .strip-page.prev { top: 0; bottom: auto; }
.viewer.strip-left .strip-page.next, .viewer.strip-right .strip-page.next {
  top: auto; bottom: 0; background: linear-gradient(to top, rgb(0 0 0 / .72), rgb(0 0 0 / 0));
}
.viewer.strip-left .strip-page svg, .viewer.strip-right .strip-page svg { transform: rotate(90deg); }
/* Browsing hands the row to the pointer: no smooth scrolling to lag behind the hand. */
.viewer.paginating .strip { scroll-behavior: smooth; }
.viewer.can-hover:not(.paginating) .strip { scroll-behavior: auto; }

/* A phone: smaller thumbnails, and a column narrower still. */
@media (max-width: 700px) {
  .viewer {
    --strip-h: min(calc(96px * var(--thumb-scale, 1)), 40vh);
    --strip-w: min(calc(140px * var(--thumb-scale, 1)), 40vw);
  }
  /* The bar's own buttons hold the arrows now, so the caption has the width to itself. */
  .viewer .caption-bar { padding: .4rem .8rem .5rem; font-size: .84rem; }
  /* No room to make on a phone: Info lies over the picture. */
  .viewer { --info-w: min(20rem, 88vw); }
  .viewer.info-open .stage { padding-right: 0; }
  .viewer.info-open.strip-right .stage { padding-right: var(--strip-w); }
}

/* Z: everything out of the way (wall.js, setZen). The thumbnails and the button bar go, and their
   room goes to the picture: the stage's padding is the row's size, so the row's size is nought. */
.viewer.zen { --strip-h: 0px; --strip-w: 0px; }
.viewer.zen .strip, .viewer.zen .strip-page, .viewer.zen .v-bar { display: none; }
/* B and T: the button bar away, and the thumbnails away (George, Oct 14, 2026, Heart Photos' keys). */
.viewer.no-bar .v-bar { display: none; }
.viewer.no-thumbs { --strip-h: 0px; --strip-w: 0px; }
.viewer.no-thumbs .strip, .viewer.no-thumbs .strip-page { display: none; }


/* The thumbnail size sliders as thin as the volume's line (George, Oct 10, 2026: "use the same thickness
   for sliders like zoom on both sites", then "use the same thickness as the volume slider for all the
   other sliders except the video seek slider"): a 2px line, the accent as far as the knob and faint
   after it, and a 12px knob. The line is the knob's border-image reaching out across the slider, which
   hides what passes its ends, so it follows the knob wherever it is put, with no script to keep it. */
.viewer .v-menu .v-size input,
.wall-size input {
  --line: var(--accent, #ff6b57); --rest: rgba(128, 128, 128, .5);
  height: 12px; margin: 0; padding: 0; background: none; overflow: hidden; cursor: pointer;
  -webkit-appearance: none; appearance: none;
}
.viewer .v-menu .v-size input::-webkit-slider-thumb,
.wall-size input::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none; width: 12px; height: 12px; border-radius: 50%; background: var(--line);
  border-image: linear-gradient(90deg, var(--line) 50%, var(--rest) 0) 0 1 / calc(50% - 1px) 100vw / 0 100vw;
}
.viewer .v-menu .v-size input::-moz-range-thumb,
.wall-size input::-moz-range-thumb {
  width: 12px; height: 12px; border: none; border-radius: 50%; background: var(--line);
  border-image: linear-gradient(90deg, var(--line) 50%, var(--rest) 0) 0 1 / calc(50% - 1px) 100vw / 0 100vw;
}
.viewer .v-menu .v-size input::-moz-range-track,
.wall-size input::-moz-range-track,
.viewer .v-menu .v-size input::-moz-range-progress,
.wall-size input::-moz-range-progress { background: none; }

/* --- the hub's most liked photos (vi.ki/photos, liked.go) --------------------------------------
   The same justified rows as a viki's wall, without the viewer: each tile is a link to the photo's
   page on its viki, and says over its picture what it is, where, and how many liked it. */
.liked-lead { color: var(--muted); margin: .2rem 0 1rem; }
.liked-wall .tile { cursor: pointer; }
.liked-meta {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 2; display: flex; flex-wrap: wrap; align-items: baseline;
  gap: .1rem .5rem; padding: 1.6rem .6rem .45rem; color: #fff; font-size: .82rem; line-height: 1.25;
  background: linear-gradient(to top, rgba(0, 0, 0, .78), rgba(0, 0, 0, 0));
  pointer-events: none;
}
.liked-title { flex: 1 1 100%; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.liked-viki { opacity: .85; }
.liked-count { margin-left: auto; font-weight: 600; white-space: nowrap; }
.liked-count::before { content: "\2665"; color: #ff6b6b; margin-right: .3em; }


/* Homes.me: with the other controls hidden, Close and the count fit one line at any width. Vi.ki's narrow layout gives
   the middle group a row of its own, which here left the count alone on a second line (George, Nov 1, 2026). */
.viewer .v-bar { flex-wrap: nowrap; align-items: center; }
.viewer .v-bar-group.mid { order: 0; flex: 1 1 auto; flex-basis: auto; justify-content: center; }
/* Fixed-width digits read as a typewriter's in the hot pages' font. */
.viewer .v-tally { font-variant-numeric: normal; }
