feat: enhance styling and layout for toolbar, map components, and editor

- Updated toolbar styles for improved layout and appearance, including padding and margin adjustments.
- Introduced new styles for scale menu and compact dropdowns.
- Enhanced map pin tooltips with better positioning and hover effects.
- Added new styles for map sheet filters, including search and date range controls.
- Improved editor styles for a more cohesive look and feel, including transport controls for video editing.
- Expanded GeoLocation interface to include additional address fields and formatted address.
- Updated MediaItem interface to include storage reference and uploadedBy fields.
- Enhanced MediaComment interface with author details for better user identification.
- Introduced GalleryUser interface to represent signed-in users in the host app.
This commit is contained in:
2026-07-23 07:34:20 +05:30
parent bc8bf2007d
commit 7673fc63ea
35 changed files with 3130 additions and 394 deletions
+658 -29
View File
@@ -292,29 +292,62 @@
background: var(--apg-bg-content);
}
/* ---- Toolbar ---- */
/* ---- Toolbar (floating rounded glass bar — matches the sidebar) ----
The toolbar stays IN FLOW as a flex item of `.apg-main` and floats via margins
on all sides. Because it remains in flow, `.apg-viewport` naturally begins below
it — the grid is never hidden behind the bar and scrolling stays inside the
viewport (no manual top-padding / overlap bookkeeping needed). `position:
relative` scopes the absolutely-centred control to the toolbar itself. */
.apg-toolbar {
position: relative;
display: flex;
align-items: center;
gap: 8px;
height: var(--apg-toolbar-h);
padding: 0 14px;
padding: 0 12px;
margin: 8px;
background: var(--apg-toolbar-bg);
backdrop-filter: saturate(180%) blur(24px);
-webkit-backdrop-filter: saturate(180%) blur(24px);
border-bottom: var(--apg-hairline) solid var(--apg-glass-border);
border: var(--apg-hairline) solid var(--apg-glass-border);
border-radius: var(--apg-radius-lg);
box-shadow: var(--apg-shadow-md);
flex-shrink: 0;
z-index: 20;
}
.apg-toolbar__spacer { flex: 1; }
.apg-toolbar__spacer { flex: 1 1 0; min-width: 0; }
/* In normal flow between two spacers: centred when there's room, squeezed (never
overlapping the right-hand zoom/filter group) when the toolbar is narrow. The old
`position:absolute; left:50%` overlapped the right group on any narrow toolbar —
and its 720px media query keyed on VIEWPORT width, so it never fired when the
toolbar was narrowed by an embedding host's sidebars. */
.apg-toolbar__center {
position: absolute;
left: 50%;
transform: translateX(-50%);
display: flex;
align-items: center;
flex: 0 1 auto;
min-width: 0;
}
@media (max-width: 720px) {
.apg-toolbar__center { position: static; transform: none; margin: 0 auto; }
/* Compact library-scale dropdown (replaces the wide 3-item segmented). */
.apg-scalemenu {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 5px 8px 5px 12px;
border: none;
border-radius: 8px;
background: var(--apg-bg-elevated);
color: var(--apg-text);
font-family: inherit;
font-size: 13px;
font-weight: 600;
cursor: default;
white-space: nowrap;
transition: background 0.12s ease;
}
.apg-scalemenu:hover { background: var(--apg-hover); }
.apg-scalemenu svg { color: var(--apg-text-secondary); }
.apg-scalemenu__label { line-height: 1; }
.apg-iconbtn {
width: 30px;
@@ -359,12 +392,12 @@
transition: background 0.15s ease;
}
.apg-segmented__item--active {
background: var(--apg-bg);
background: var(--apg-segmented-active, var(--apg-bg));
box-shadow: var(--apg-shadow-sm);
font-weight: 600;
}
.apg[data-theme='dark'] .apg-segmented__item--active {
background: #636366;
background: var(--apg-segmented-active, #636366);
}
/* Search */
@@ -395,9 +428,18 @@
.apg-search:focus-within {
box-shadow: 0 0 0 3px color-mix(in srgb, var(--apg-accent) 32%, transparent);
}
/* ONE ring, not two: the global `.apg :focus-visible` outline would otherwise
draw a second line INSIDE the wrapper's ring. The wrapper ring is the
focus indicator for this control. */
.apg-search input:focus-visible,
.apg-search input:focus {
outline: none;
}
.apg-search__recents {
position: absolute;
top: calc(100% + 6px);
/* Clears the 3px focus ring so the popover's own hairline never reads as a
second ring stacked under the field. */
top: calc(100% + 9px);
right: 0;
min-width: 220px;
z-index: 60;
@@ -515,7 +557,7 @@
position: absolute;
bottom: 6px;
right: 7px;
color: #ff3b30;
color: var(--apg-tile-fav, #ff3b30);
filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.55));
}
/* ---- Custom video player (macOS-style) ---- */
@@ -864,6 +906,20 @@
/* ---- Map thumbnail pins (macOS-style) ---- */
.apg-pin-wrap { background: none !important; border: none !important; }
/* Pins + their hover tooltip are pointer targets, never text: suppress selection so
dragging across the map never leaves a grey selection rectangle over the pin/preview. */
.apg-pin,
.apg-pin__tip {
-webkit-user-select: none;
user-select: none;
}
.apg-pin__img,
.apg-pin__tip-img,
.apg-pin__strip-cell img {
-webkit-user-drag: none;
user-select: none;
pointer-events: none;
}
.apg-pin {
position: relative;
display: block;
@@ -897,9 +953,12 @@
position: absolute;
left: 50%;
bottom: calc(100% + 10px);
transform: translateX(-50%) scale(0.9);
/* --tip-dx is set per-hover by MapView so the tooltip slides back inside the map
when a pin sits near the left/right edge (instead of overflowing + being clipped). */
transform: translateX(calc(-50% + var(--tip-dx, 0px))) scale(0.9);
transform-origin: bottom center;
width: 168px;
max-width: 70vw;
padding: 5px;
border-radius: 12px;
background: var(--apg-menu-bg, #fff);
@@ -913,7 +972,24 @@
}
.apg-pin:hover .apg-pin__tip {
opacity: 1;
transform: translateX(-50%) scale(1);
transform: translateX(calc(-50% + var(--tip-dx, 0px))) scale(1);
}
/* Pin near the TOP of the map: flip the tooltip below so it isn't clipped off-screen. */
.apg-pin__tip--below {
bottom: auto;
top: calc(100% + 10px);
transform-origin: top center;
}
.apg-pin__tip--below::after { top: auto; bottom: 100%; }
/* Invisible bridge across the 10px gap so the pointer can travel from the pin
into the tooltip (to click a thumbnail) without dropping :hover. */
.apg-pin__tip::after {
content: '';
position: absolute;
left: 0;
right: 0;
top: 100%;
height: 12px;
}
.apg-pin__tip-img {
width: 100%;
@@ -950,19 +1026,71 @@
position: absolute;
left: 3px;
bottom: 3px;
min-width: 18px;
height: 18px;
padding: 0 4px;
border-radius: 9px;
background: rgba(0, 0, 0, 0.6);
min-width: 19px;
height: 19px;
padding: 0 5px;
border-radius: 10px;
/* Opaque enough to stay legible over a bright photo, with a hairline ring so
the digits never blend into a dark one. */
background: rgba(0, 0, 0, 0.78);
box-shadow: 0 0 0 1.5px rgba(255, 255, 255, 0.9);
color: #fff;
font-size: 11px;
font-size: 11.5px;
font-weight: 700;
line-height: 18px;
font-variant-numeric: tabular-nums;
line-height: 19px;
text-align: center;
pointer-events: none;
}
/* Hover mini-slider: a strip of the cluster's thumbnails under the preview. */
.apg-pin__strip {
display: none;
gap: 3px;
align-items: center;
margin-top: 5px;
}
.apg-pin__strip:not(:empty) { display: flex; }
.apg-pin__strip-cell {
flex: 1 1 0;
min-width: 0;
padding: 0;
border: none;
border-radius: 5px;
background: none;
overflow: hidden;
line-height: 0;
cursor: pointer;
opacity: 0.62;
transition: opacity 0.12s ease, box-shadow 0.12s ease;
}
.apg-pin__strip-cell img {
width: 100%;
height: 28px;
object-fit: cover;
display: block;
border-radius: 5px;
}
.apg-pin__strip-cell:hover { opacity: 1; }
.apg-pin__strip-cell--on {
opacity: 1;
box-shadow: 0 0 0 2px var(--apg-accent);
}
.apg-pin__strip-more {
flex: 0 0 auto;
padding: 0 5px;
height: 28px;
line-height: 28px;
border-radius: 5px;
background: var(--apg-hover, rgba(0, 0, 0, 0.08));
color: var(--apg-text-secondary);
font-size: 11px;
font-weight: 700;
}
/* The tooltip is only interactive while hovered (it is pointer-events:none
otherwise), so the strip's buttons stay clickable without stealing hits. */
.apg-pin:hover .apg-pin__tip { pointer-events: auto; }
/* ---- Map location sheet (tap a pin → its photos, date-grouped) ---- */
.apg-map__sheet {
position: absolute;
@@ -1016,6 +1144,227 @@
}
.apg-map__sheet-body { flex: 1; overflow-y: auto; min-height: 0; }
/* ---- Map sheet filter bar (search + date range + object chips) ---- */
.apg-map__sheet-filters {
flex-shrink: 0;
display: flex;
flex-direction: column;
gap: 8px;
padding: 10px 16px;
background: var(--apg-bg-elevated);
border-bottom: 1px solid var(--apg-separator);
}
.apg-mapfilter__row { display: flex; align-items: center; gap: 8px; }
.apg-mapfilter__search {
position: relative;
display: flex;
align-items: center;
gap: 6px;
flex: 1;
min-width: 0;
padding: 5px 9px;
border-radius: var(--apg-radius);
background: var(--apg-bg);
border: 1px solid var(--apg-separator);
color: var(--apg-text-secondary);
transition: box-shadow 0.15s ease;
}
.apg-mapfilter__search:focus-within {
box-shadow: 0 0 0 3px color-mix(in srgb, var(--apg-accent) 32%, transparent);
}
.apg-mapfilter__search input {
flex: 1;
min-width: 0;
border: none;
background: none;
color: var(--apg-text);
font-family: inherit;
font-size: 13px;
}
/* One ring only — the wrapper owns the focus indicator. */
.apg-mapfilter__search input:focus,
.apg-mapfilter__search input:focus-visible { outline: none; }
.apg-mapfilter__search input::placeholder { color: var(--apg-text-secondary); }
/* Hide the UA's own clear affordance; ours resets the dates too. */
.apg-mapfilter__search input::-webkit-search-cancel-button { display: none; }
.apg-mapfilter__clear {
flex-shrink: 0;
display: inline-flex;
align-items: center;
justify-content: center;
width: 18px;
height: 18px;
padding: 0;
border: none;
border-radius: 50%;
background: var(--apg-separator-strong);
color: var(--apg-text);
cursor: pointer;
}
.apg-mapfilter__dates { flex-wrap: wrap; }
.apg-mapfilter__date {
display: inline-flex;
align-items: center;
gap: 6px;
font-size: 12px;
color: var(--apg-text-secondary);
}
.apg-mapfilter__date input {
padding: 4px 7px;
border-radius: var(--apg-radius-sm);
border: 1px solid var(--apg-separator);
background: var(--apg-bg);
color: var(--apg-text);
font-family: inherit;
font-size: 12px;
/* Safari sizes date inputs intrinsically; keep them from blowing out the row. */
max-width: 148px;
min-width: 0;
}
.apg-mapfilter__chips {
display: flex;
flex-wrap: wrap;
gap: 6px;
max-height: 66px;
overflow-y: auto;
}
.apg-mapfilter__chip {
display: inline-flex;
align-items: center;
gap: 5px;
padding: 3px 9px;
border-radius: 999px;
border: 1px solid var(--apg-separator);
background: var(--apg-bg);
color: var(--apg-text);
font-family: inherit;
font-size: 12px;
cursor: pointer;
text-transform: capitalize;
}
.apg-mapfilter__chip:hover { background: var(--apg-hover); }
.apg-mapfilter__chip--on {
background: var(--apg-accent);
border-color: transparent;
color: var(--apg-accent-contrast, #fff);
font-weight: 600;
}
.apg-mapfilter__chip-n {
font-size: 11px;
font-variant-numeric: tabular-nums;
opacity: 0.72;
}
.apg-mapfilter__empty {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
padding: 34px 20px;
color: var(--apg-text-secondary);
text-align: center;
}
.apg-mapfilter__empty-title { font-size: 15px; font-weight: 600; color: var(--apg-text); }
.apg-mapfilter__empty-sub { font-size: 12.5px; }
/* ---- Map filter: single date-range control (button + presets/custom popover) ---- */
.apg-daterange { position: relative; }
.apg-daterange__button {
display: inline-flex;
align-items: center;
gap: 7px;
padding: 6px 10px;
border-radius: var(--apg-radius);
border: 1px solid var(--apg-separator);
background: var(--apg-bg);
color: var(--apg-text);
font-family: inherit;
font-size: 12.5px;
font-weight: 500;
cursor: pointer;
transition: border-color 0.12s ease, background 0.12s ease;
}
.apg-daterange__button:hover { background: var(--apg-hover); }
.apg-daterange__button svg:last-child { color: var(--apg-text-secondary); }
.apg-daterange__button--active {
border-color: var(--apg-accent);
color: var(--apg-accent);
}
.apg-daterange__button--active svg { color: var(--apg-accent); }
.apg-daterange__label { line-height: 1; white-space: nowrap; }
.apg-daterange__pop {
position: absolute;
top: calc(100% + 6px);
left: 0;
z-index: 60;
min-width: 232px;
padding: 8px;
background: var(--apg-menu-bg);
border: var(--apg-hairline) solid var(--apg-glass-border);
border-radius: var(--apg-radius-menu);
box-shadow: var(--apg-shadow-md);
backdrop-filter: blur(34px) saturate(180%);
-webkit-backdrop-filter: blur(34px) saturate(180%);
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
.apg-daterange__pop { background: var(--apg-bg-elevated); }
}
.apg-daterange__presets {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 4px;
}
.apg-daterange__preset {
display: inline-flex;
align-items: center;
justify-content: space-between;
gap: 6px;
padding: 7px 10px;
border: 1px solid var(--apg-separator);
border-radius: var(--apg-radius-sm);
background: var(--apg-bg);
color: var(--apg-text);
font-family: inherit;
font-size: 12.5px;
cursor: pointer;
text-align: left;
}
.apg-daterange__preset:hover { background: var(--apg-hover); }
.apg-daterange__preset--on {
border-color: transparent;
background: var(--apg-accent);
color: var(--apg-accent-contrast, #fff);
font-weight: 600;
}
.apg-daterange__preset--on svg { color: var(--apg-accent-contrast, #fff); }
.apg-daterange__custom { margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--apg-separator); }
.apg-daterange__custom-label {
font-size: 11px;
font-weight: 600;
color: var(--apg-text-secondary);
padding: 0 2px 6px;
}
.apg-daterange__fields { display: flex; gap: 8px; }
.apg-daterange__field {
display: flex;
flex-direction: column;
gap: 3px;
flex: 1;
min-width: 0;
font-size: 11px;
color: var(--apg-text-secondary);
}
.apg-daterange__field input {
padding: 5px 7px;
border-radius: var(--apg-radius-sm);
border: 1px solid var(--apg-separator);
background: var(--apg-bg);
color: var(--apg-text);
font-family: inherit;
font-size: 12px;
min-width: 0;
}
.apg-daterange__field input:focus { outline: none; border-color: var(--apg-accent); }
/* ---- Mosaic / Memories grid (Map → Grid tab) ---- */
.apg-mosaic-wrap { padding: 4px 0 28px; }
.apg-mosaic-section { padding: 6px 16px 10px; }
@@ -1094,7 +1443,7 @@
position: fixed;
inset: 0;
z-index: 1000;
background: rgba(0, 0, 0, 0.97);
background: var(--apg-overlay-bg, rgba(0, 0, 0, 0.97));
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
display: flex;
@@ -1254,13 +1603,30 @@
.apg-modal__list-item:hover { background: var(--apg-hover); }
/* ---- Editor ---- */
.apg-editor { position: fixed; inset: 0; z-index: 1050; background: #161617; display: flex; flex-direction: column; color: #fff; }
.apg-editor { position: fixed; inset: 0; z-index: 1050; background: var(--apg-editor-bg, #161617); display: flex; flex-direction: column; color: #fff; font-family: var(--apg-font); }
.apg-editor__bar { display: flex; align-items: center; gap: 10px; padding: 12px 16px; border-bottom: 1px solid rgba(255,255,255,0.1); }
.apg-editor__bar .apg-iconbtn { color: #fff; }
.apg-editor__bar .apg-iconbtn:hover { background: rgba(255,255,255,0.12); }
.apg-editor__body { flex: 1; display: flex; min-height: 0; }
.apg-editor__canvaswrap { flex: 1; display: grid; place-items: center; padding: 18px; min-width: 0; }
.apg-editor__canvaswrap { flex: 1; display: grid; place-items: center; gap: 12px; padding: 18px; min-width: 0; }
.apg-editor__canvaswrap canvas { max-width: 100%; max-height: 100%; border-radius: 4px; box-shadow: 0 10px 40px rgba(0,0,0,0.5); }
.apg-editor__canvaswrap video { cursor: pointer; }
/* Custom video transport — sibling of the (transformable) preview, so it never
rotates/flips with the frame. */
.apg-vedit__transport {
display: flex;
align-items: center;
gap: 10px;
width: min(560px, 100%);
padding: 6px 10px;
border-radius: 999px;
background: rgba(30, 30, 32, 0.55);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
}
.apg-vedit__transport .apg-iconbtn { color: #fff; flex: none; }
.apg-vedit__scrub { flex: 1; min-width: 0; accent-color: var(--apg-accent); cursor: pointer; }
.apg-vedit__time { flex: none; font-size: 11.5px; color: rgba(255, 255, 255, 0.8); font-variant-numeric: tabular-nums; }
.apg-editor__panel { width: 300px; flex-shrink: 0; border-left: 1px solid rgba(255,255,255,0.1); padding: 16px; overflow-y: auto; }
.apg-editor__tabs { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 14px; }
.apg-editor__tab { flex: 1 1 auto; padding: 6px 8px; border-radius: 7px; background: rgba(255,255,255,0.08); border: none; color: #fff; font-size: 12px; cursor: pointer; white-space: nowrap; }
@@ -1462,7 +1828,8 @@
/* ---- Info panel ---- */
.apg-info {
position: fixed;
top: 64px;
/* A host with its own header can push the panel below it via --apg-overlay-top. */
top: var(--apg-overlay-top, 64px);
right: 14px;
z-index: 1300;
width: 300px;
@@ -1496,6 +1863,14 @@
border-radius: var(--apg-radius);
background: var(--apg-bg);
}
/* Video preview: show the whole frame (never crop) over a dark backing, and let the
native control bar sit below without forcing a fixed square. */
.apg-info__thumb--video {
height: auto;
max-height: 220px;
object-fit: contain;
background: #000;
}
.apg-info__name { font-weight: 600; font-size: 14px; margin-top: 10px; word-break: break-all; }
.apg-info__sub { color: var(--apg-text-secondary); font-size: 12px; margin-bottom: 10px; }
.apg-info__row {
@@ -1608,9 +1983,174 @@
}
.apg-version__changes { list-style: disc; margin: 0 0 8px; padding-left: 16px; font-size: 12px; color: var(--apg-text); }
.apg-version__changes li { padding: 1px 0; }
/* Version author (who created this version) — avatar + name under the timestamp. */
.apg-version__author { display: inline-flex; align-items: center; gap: 5px; margin-top: 2px; }
.apg-version__author-avatar {
width: 16px;
height: 16px;
flex-shrink: 0;
border-radius: 50%;
object-fit: cover;
background: var(--apg-bg-elevated);
}
.apg-version__author-avatar--initial {
display: inline-flex;
align-items: center;
justify-content: center;
background: var(--apg-accent);
color: #fff;
font-size: 9px;
font-weight: 700;
}
.apg-version__author-name { font-size: 11px; color: var(--apg-text-secondary); }
.apg-comments { list-style: none; margin: 0 0 10px; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.apg-comment { display: flex; gap: 8px; align-items: flex-start; }
/* ---- Info panel: "Uploaded by" identity block ---- */
.apg-info__uploader {
/* Breathing room above (from the caption/note) AND below, so the card is a
distinct block, not glued to the "Analyzing…" line or the detail rows. */
margin: 12px 0 14px;
padding: 8px 10px;
border-radius: var(--apg-radius);
background: var(--apg-bg-elevated);
border: 1px solid var(--apg-separator);
}
.apg-info__uploader-label {
display: block;
font-size: 10.5px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.03em;
color: var(--apg-text-tertiary);
margin-bottom: 6px;
}
.apg-info__uploader-row { display: flex; align-items: center; gap: 9px; }
.apg-info__uploader-avatar {
width: 30px;
height: 30px;
flex-shrink: 0;
border-radius: 50%;
object-fit: cover;
background: var(--apg-bg);
}
.apg-info__uploader-avatar--initial {
display: flex;
align-items: center;
justify-content: center;
background: var(--apg-accent);
color: #fff;
font-size: 13px;
font-weight: 700;
}
.apg-info__uploader-meta { display: flex; flex-direction: column; min-width: 0; }
.apg-info__uploader-name { font-size: 13px; font-weight: 600; color: var(--apg-text); }
.apg-info__uploader-email {
font-size: 11px;
color: var(--apg-text-secondary);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* ---- Info panel: editable caption / note ---- */
.apg-editable {
display: flex;
flex-direction: column;
gap: 3px;
width: 100%;
margin-top: 10px;
padding: 7px 9px;
text-align: left;
border: 1px solid transparent;
border-radius: var(--apg-radius);
background: var(--apg-bg-elevated);
color: var(--apg-text);
cursor: text;
font-family: inherit;
}
.apg-editable:hover { border-color: var(--apg-separator-strong); }
.apg-editable__label {
display: flex;
align-items: center;
gap: 5px;
font-size: 10.5px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.03em;
color: var(--apg-text-tertiary);
}
.apg-editable__label svg { margin-left: auto; opacity: 0.55; }
.apg-editable__edited {
text-transform: none;
letter-spacing: 0;
font-weight: 500;
font-size: 10px;
font-style: italic;
color: var(--apg-text-tertiary);
}
.apg-editable__value { font-size: 12.5px; line-height: 1.4; white-space: pre-wrap; word-break: break-word; }
.apg-editable__value--empty { color: var(--apg-text-tertiary); font-style: italic; }
.apg-editable--editing { cursor: default; }
.apg-editable__input {
width: 100%;
border: 1px solid var(--apg-accent);
background: var(--apg-bg);
color: var(--apg-text);
border-radius: var(--apg-radius-sm);
padding: 6px 8px;
font-size: 12.5px;
font-family: inherit;
line-height: 1.4;
resize: vertical;
outline: none;
}
/* ---- Info panel: full reverse-geocoded address ---- */
.apg-address { margin-top: 6px; }
.apg-address__line {
display: flex;
align-items: flex-start;
gap: 6px;
width: 100%;
text-align: left;
padding: 7px 9px;
border-radius: var(--apg-radius);
border: 1px solid var(--apg-glass-border);
background: var(--apg-bg-elevated);
color: var(--apg-text);
font-size: 12px;
line-height: 1.4;
cursor: pointer;
}
.apg-address__line svg { flex-shrink: 0; margin-top: 1px; color: var(--apg-accent); }
.apg-address__line:hover { border-color: var(--apg-accent); }
.apg-address__grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 6px;
margin: 8px 0 0;
}
.apg-address__cell { display: flex; flex-direction: column; gap: 1px; }
.apg-address__cell dt {
font-size: 10px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.03em;
color: var(--apg-text-tertiary);
}
.apg-address__cell dd { margin: 0; font-size: 12px; color: var(--apg-text); word-break: break-word; }
.apg-comments { list-style: none; margin: 0 0 14px; padding: 0; display: flex; flex-direction: column; gap: 14px; }
/* Each comment is a distinct card so consecutive comments (and the compose box
below) read as separate, not one run-on block. */
.apg-comment {
display: flex; gap: 8px; align-items: flex-start;
padding: 8px 9px;
border-radius: 10px;
background: var(--apg-bg-elevated);
border: 1px solid var(--apg-separator);
}
/* Separate the compose form from the comment list above it. */
.apg-comment-form { margin-top: 4px; padding-top: 12px; border-top: 1px solid var(--apg-separator); }
.apg-comment__avatar {
width: 26px;
height: 26px;
@@ -1624,6 +2164,22 @@
font-size: 12px;
font-weight: 700;
}
/* Real avatar image (host-provided identity) — same footprint as the initial. */
.apg-comment__avatar-img {
width: 26px;
height: 26px;
flex-shrink: 0;
border-radius: 50%;
object-fit: cover;
display: block;
background: var(--apg-bg-elevated);
}
.apg-comment-form__identity {
display: flex;
align-items: center;
gap: 8px;
padding: 2px 0 2px;
}
.apg-comment__body { flex: 1; min-width: 0; }
.apg-comment__meta { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.apg-comment__author { font-size: 12.5px; font-weight: 600; }
@@ -1675,7 +2231,7 @@
.apg-info__analyzing {
display: flex; align-items: center; gap: 8px;
font-size: 13px; font-weight: 500; color: var(--apg-accent);
padding: 8px 10px; margin: 2px 0 4px;
padding: 8px 10px; margin: 6px 0 10px;
background: color-mix(in srgb, var(--apg-accent) 10%, transparent);
border-radius: 8px;
}
@@ -1852,3 +2408,76 @@
outline-offset: 2px;
border-radius: 4px;
}
/* =========================================================================
Embedded mode — the gallery lives inside a host app's layout.
The full-screen overlays (lightbox, editor, camera, modals, context menu)
intentionally stay `position: fixed`: that is correct for a modal rendered
over a host application. Only the in-flow layout changes here.
========================================================================= */
.apg--embedded {
height: 100%;
min-height: 0;
}
.apg--embedded .apg__body {
flex: 1 1 auto;
min-height: 0;
height: 100%;
}
/* macOS uses `cursor: default` on controls; inside a web app that reads as
broken, so embedded mode restores the expected pointer affordance. */
.apg--embedded .apg-btn,
.apg--embedded .apg-iconbtn,
.apg--embedded .apg-tile,
.apg--embedded .apg-chip,
.apg--embedded .apg-menu__item,
.apg--embedded .apg-modal__list-item,
.apg--embedded .apg-sidebar__item,
.apg--embedded .apg-segmented__item,
.apg--embedded .apg-lightbox__nav,
.apg--embedded .apg-collections__action,
.apg--embedded .apg-pinned-card,
.apg--embedded .apg-editor__filter,
.apg--embedded .apg-camera__tool,
.apg--embedded .apg-scalemenu,
.apg--embedded .apg-daterange__button,
.apg--embedded .apg-daterange__preset,
.apg--embedded .apg-editable {
cursor: pointer;
}
.apg--embedded .apg-btn:disabled,
.apg--embedded .apg-iconbtn:disabled {
cursor: not-allowed;
}
/* =========================================================================
Full screen / maximise — the gallery covers the host page.
Why the SDK's own overlays need no change: the lightbox / editor / camera /
modals are `position: fixed; inset: 0`, so they resolve against the VIEWPORT
(a plain `position: fixed` ancestor is not a containing block for them — only
transform/filter/contain would be). Full screen makes `.apg` cover exactly the
viewport too, so the two coincide and the overlays land in the right place.
And because `z-index: 1400` opens a stacking context, their 1000-1300 z-indexes
now stack INSIDE it — above the gallery's content, and (via 1400) above the
host's chrome. Nothing else needs raising. `overflow: hidden` on `.apg` does
not clip them, for the same containing-block reason.
========================================================================= */
.apg--fullscreen {
position: fixed;
inset: 0;
z-index: 1400;
width: 100%;
/* Fill the viewport regardless of what height the host container had.
`dvh` (where supported) keeps mobile browser chrome from cropping it. */
height: 100%;
height: 100dvh;
max-height: none;
border-radius: 0;
}
.apg--fullscreen .apg__body {
flex: 1 1 auto;
min-height: 0;
height: auto;
}