/*
================================================================================
SCRIPT:   Brownstein Collection — web viewer
FILE:     styles.css
CREATED:  2026-10-30
AUTHOR:   JPG
PURPOSE:  Look of the Shared Collections viewer, transcribed from the
          approved drawings (20 DEV/Collections/docs/drawings/viewer-*.html):
          San Francisco only, the app's Theme tokens with their dark pairs
          (CollectionsTheme.swift) through prefers-color-scheme, the app's
          collection and gallery tiles, marks on the photo, the object page,
          the full-screen viewer, the phone shape (top bar + bottom tab
          bar, 16 px gutters, no horizontal page scroll), the Welcome's
          passphrase field, and the fixed slate frame of
          drawing 8 (viewer-background.html): one page background in both
          modes, a darker slate sidebar and bars, and the content on a
          rounded panel. The frame is pinned like an app window: the page
          never scrolls, only the content panel scrolls inside itself,
          under a crumb row held at its top (with the object stepper).
LICENSE:  Proprietary
DEPS:     None — fully self-contained
================================================================================
*/

/* 2026-10-30 - light values are the drawings' :root; dark values are the
   app's Theme pairs. --mark-bg has no Theme token: its dark value is
   chosen to sit on the dark page.
   2026-10-31 - --page is now the content panel's colour; the page behind
   it is --backdrop. --side, --side-edge and --select went with the gray
   sidebar.
   2026-10-31 - --open-* is the passphrase field's Open button. */
:root {
    --accent: #6B8190;
    --page: #FAFAFA;
    --surface: #FFFFFF;
    --deep: #E0E0E0;
    --t1: #333333;
    --t2: #666666;
    --t3: #999999;
    --rule: #E8E8E8;
    --glyph: #C7C7CC;
    --chip-bg: #FFFFFF;
    --chip-edge: rgba(0, 0, 0, 0.06);
    --control-edge: rgba(0, 0, 0, 0.1);
    --mark-bg: rgba(255, 255, 255, 0.92);
    --tile-shadow: 0 1px 2px rgba(0, 0, 0, 0.08), 0 3px 8px rgba(0, 0, 0, 0.06);
    --lift: drop-shadow(0 5px 12px rgba(0, 0, 0, 0.28));
    --lift-small: drop-shadow(0 4px 10px rgba(0, 0, 0, 0.25));
    --lift-stage: drop-shadow(0 10px 24px rgba(0, 0, 0, 0.3));
    /* 2026-10-31 - JG: the site mark's tile colour (favicon.svg #4A4A4A),
       in light and dark alike. */
    --open-bg: #4A4A4A;
    --open-bg-hover: #3E3E3E;
    --open-fg: #FFFFFF;
    --error-bg: #FBEAEA;
    --error-fg: #8A1C1C;
    --error-line: #F0C9C9;
    --gutter: 16px;
    --sidebar-width: 240px;
    /* 2026-10-31 - the fixed frame (drawing 8): identical in light and dark
       so nothing outside the content panel can pass for Safari's gray
       toolbars. Never redefine these under prefers-color-scheme. */
    --backdrop: #6B8190;
    --frame: #4F6271;
    --on-frame: #FFFFFF;
    --on-frame-2: rgba(255, 255, 255, 0.65);
    --on-frame-select: rgba(255, 255, 255, 0.18);
    --on-frame-rule: rgba(255, 255, 255, 0.2);
    --on-frame-status: rgba(255, 255, 255, 0.7);
    /* 2026-10-31 - the initials circle behind the person's name. */
    --on-frame-avatar: rgba(255, 255, 255, 0.3);
    --panel-radius: 12px;
    --panel-shadow: 0 2px 10px rgba(0, 0, 0, 0.18);
    --panel-inset: 14px;
    /* 2026-10-31 - the crumb row at the top of the panel; it stands where
       the panel's 28 px top padding was, plus the gap to the page title. */
    --crumb-height: 40px;
    --main-pad-x: 32px;
    --gate-width: 560px;
    --font: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text", "Helvetica Neue", sans-serif;
}

@media (prefers-color-scheme: dark) {
    :root {
        --accent: #8299A7;
        --page: #1C1C1E;
        --surface: #2C2C2E;
        --deep: #3A3A3C;
        --t1: #E8E8ED;
        --t2: #B0B0B6;
        --t3: #8A8A8F;
        --rule: #333336;
        --glyph: #636366;
        --chip-bg: #2C2C2E;
        --chip-edge: rgba(255, 255, 255, 0.08);
        --control-edge: rgba(255, 255, 255, 0.14);
        --mark-bg: rgba(44, 44, 46, 0.92);
        --tile-shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 3px 8px rgba(0, 0, 0, 0.3);
        --lift: drop-shadow(0 5px 12px rgba(0, 0, 0, 0.55));
        --lift-small: drop-shadow(0 4px 10px rgba(0, 0, 0, 0.5));
        --lift-stage: drop-shadow(0 10px 24px rgba(0, 0, 0, 0.6));
        --error-bg: #3A1F1F;
        --error-fg: #F4C7C7;
        --error-line: #5A2E2E;
    }
}

*,
*::before,
*::after {
    box-sizing: border-box;
}

/* 2026-10-31 - the slate page, the same in both modes (drawing 8).
   2026-10-31 - JG: pinned like a desktop app window. The page itself never
   scrolls (nor rubber-bands); the gate and the content panel each scroll
   inside themselves. dvh so iOS Safari's toolbars cause no jumps. */
html,
body {
    margin: 0;
    height: 100%;
    overflow: hidden;
    overscroll-behavior: none;
    background: var(--backdrop);
    color: var(--t1);
    font-family: var(--font);
    -webkit-font-smoothing: antialiased;
    -webkit-text-size-adjust: 100%;
}

body {
    height: 100vh;
    height: 100dvh;
    display: flex;
    flex-direction: column;
}

a {
    color: inherit;
    text-decoration: none;
}

button {
    font: inherit;
    color: inherit;
}

[hidden] {
    display: none !important;
}

.link-button {
    background: none;
    border: none;
    padding: 0;
    color: var(--t3);
    font: inherit;
    text-decoration: underline;
    cursor: pointer;
}

.icon {
    fill: none;
    stroke: currentColor;
    stroke-linecap: round;
    stroke-linejoin: round;
}

/* MARK: - Gate (drawing 7) */

/* 2026-10-31 - fills the body under any banner and scrolls inside itself
   when its content is taller than the window (a short phone in landscape). Centred
   by .gate-center's auto margins, not align-items: center, which would cut
   off the top of content taller than the gate. */
.gate {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding: calc(40px + env(safe-area-inset-top)) var(--gutter) calc(56px + env(safe-area-inset-bottom));
}

/* 2026-10-31 - the gate sits DIRECTLY on the slate (JG: no white card
   here): white title and text, the dark-gray Open button. */
.gate-center {
    flex: 0 1 var(--gate-width);
    max-width: var(--gate-width);
    min-width: 0;
    margin: auto 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: 40px;
    gap: 14px;
}

/* 2026-10-31 - JG: the title and the line fade in TOGETHER over 4 s; the
   passphrase field snaps in the moment that ends, with only a slight
   fade. Once per load; off under reduced motion. */
@keyframes gate-fade {
    from { opacity: 0; transform: translateY(4px); }
    to   { opacity: 1; transform: none; }
}
.gate .titleline, .gate .lead { animation: gate-fade 4s ease-out both; }
.gate .pass-door, .gate .who { animation: gate-fade 0.25s ease-out 4s both; }
@media (prefers-reduced-motion: reduce) {
    .gate .titleline, .gate .lead, .gate .pass-door, .gate .who { animation: none; }
}

.gate .title { color: var(--on-frame); }
.gate .lead { color: var(--on-frame-2); }
.gate .who { color: var(--on-frame-2); }
.gate .link-button { color: var(--on-frame-2); }

.gate-body {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 14px;
}

.titleline {
    display: flex;
    align-items: center;
    gap: 14px;
}

.mark {
    width: 40px;
    height: 40px;
    border-radius: 9px;
    display: block;
    flex: none;
}

.title {
    font-weight: 600;
    font-size: 30px;
    letter-spacing: -0.4px;
    margin: 0;
}

.lead {
    color: var(--t2);
    font-size: 14px;
    margin: 0;
    max-width: 380px;
    line-height: 1.5;
}

.who {
    margin-top: 4px;
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    color: var(--t2);
}

.who .link-button {
    font-size: 12px;
}

/* MARK: - Passphrase door (2026-10-31) */

/* On the slate in both modes, so only the fixed frame tokens are used.
   The field's text is 16 px so iOS Safari does not zoom in on focus.
   Open wears the site mark's dark gray: the accent is the slate itself. */
.pass-door {
    display: flex;
    flex-direction: column;
    align-items: center;
    width: 100%;
}

.pass-form {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    width: 280px;
    max-width: 100%;
}

.pass-field {
    position: relative;
    width: 100%;
}

.pass-field input {
    width: 100%;
    height: 40px;
    padding: 0 58px 0 12px;
    border: 1px solid var(--on-frame-rule);
    border-radius: 8px;
    background: var(--on-frame-select);
    color: var(--on-frame);
    font: inherit;
    font-size: 16px;
}

.pass-field input::placeholder {
    color: var(--on-frame-2);
}

.pass-field input:focus {
    outline: 2px solid var(--on-frame);
    outline-offset: 1px;
}

.pass-field input:disabled {
    opacity: 0.6;
}

.pass-toggle {
    position: absolute;
    top: 50%;
    right: 6px;
    transform: translateY(-50%);
    height: 28px;
    padding: 0 8px;
    border: none;
    border-radius: 6px;
    background: none;
    color: var(--on-frame-2);
    font-size: 12px;
    cursor: pointer;
}

.pass-toggle:hover:not(:disabled) {
    color: var(--on-frame);
}

.pass-open {
    height: 36px;
    padding: 0 26px;
    border: none;
    border-radius: 8px;
    background: var(--open-bg);
    color: var(--open-fg);
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
}

.pass-open:hover:not(:disabled) {
    background: var(--open-bg-hover);
}

.pass-open:disabled {
    opacity: 0.6;
    cursor: default;
}

.pass-message {
    margin: 0;
    font-size: 13px;
    color: var(--on-frame);
}

.pass-message:empty {
    display: none;
}

@media (max-width: 760px) {
    .pass-form {
        width: 100%;
    }
}

/* MARK: - Frame (drawings 4–6) */

/* 2026-10-31 - JG: the pinned window. The body is the frame's grid, so the
   sidebar runs the full height, the panel fills the rest, and the status
   line has a row of its own under the panel that the panel can never
   overlap. #frame steps aside (display: contents) so its children share
   the grid with the banner and the status line, which sit outside it
   because the gate screens use them too. */
body.has-frame {
    display: grid;
    grid-template-columns: var(--sidebar-width) minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr) auto;
    grid-template-areas:
        "banner banner"
        "side main"
        "side status";
}

body.has-frame .frame {
    display: contents;
}

body.has-frame .banner {
    grid-area: banner;
}

body.has-frame .status-line {
    grid-area: status;
}

/* 2026-10-31 - the sidebar never scrolls as a whole: the brand and the
   viewer block (the passphrase row) stay put and only .side-list between
   them scrolls. */
.sidebar {
    grid-area: side;
    min-height: 0;
    overflow: hidden;
    /* 2026-10-31 - the sidebar sits DIRECTLY on the slate (JG: the darker
       band's hard edge against the panel was not acceptable); white text.
       The phone bars keep the darker slate (they are bands by nature). */
    background: transparent;
    color: var(--on-frame);
    /* 2026-10-31 - safe areas: a landscape iPhone wide enough for the sidebar. */
    padding: calc(20px + env(safe-area-inset-top)) 14px calc(16px + env(safe-area-inset-bottom))
        calc(14px + env(safe-area-inset-left));
    font-size: 13px;
    display: flex;
    flex-direction: column;
}

.brand {
    font-size: 15px;
    font-weight: 600;
    letter-spacing: -0.1px;
    padding: 0 10px 18px;
    flex: none;
}

/* 2026-10-31 - "Shared with Jane Smith" under the brand (site b21). */
.brand small {
    display: block;
    font-size: 11px;
    font-weight: 400;
    color: var(--on-frame-2);
    margin-top: 2px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.side-list {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    margin: 0 -14px;
    padding: 0 14px 12px;
}

.sec {
    font-size: 11px;
    font-weight: 600;
    color: var(--on-frame-2);
    padding: 12px 10px 6px;
}

.row {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 6px 10px;
    border-radius: 6px;
    min-width: 0;
}

.row:hover {
    background: var(--on-frame-select);
}

.row.sel {
    background: var(--on-frame-select);
}

.row .label {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.row svg {
    width: 16px;
    height: 16px;
    color: var(--on-frame);
    stroke-width: 1.6;
    flex: none;
}

.row .n {
    margin-left: auto;
    color: var(--on-frame-2);
    font-size: 12px;
    flex: none;
}

.you {
    flex: none;
    margin-top: auto;
    border-top: 1px solid var(--on-frame-rule);
    padding-top: 12px;
    display: flex;
    align-items: center;
    gap: 10px;
    padding-left: 6px;
    min-width: 0;
}

/* 2026-10-31 - the site mark, where an account's avatar was. */
.avatar {
    width: 28px;
    height: 28px;
    border-radius: 7px;
    overflow: hidden;
    display: block;
    flex: none;
}

.avatar.small {
    width: 24px;
    height: 24px;
    border-radius: 6px;
}

.avatar img {
    width: 100%;
    height: 100%;
    display: block;
}

/* 2026-10-31 - the person's initials when the copy names them (site b21). */
.avatar.initials {
    border-radius: 50%;
    background: var(--on-frame-avatar);
    color: var(--on-frame);
    font-size: 11px;
    font-weight: 600;
    display: grid;
    place-items: center;
}

.avatar.initials.small {
    font-size: 10px;
}

.you .who-name {
    line-height: 1.25;
    min-width: 0;
}

.you .who-name a {
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.you .who-name small {
    display: block;
    color: var(--on-frame-2);
    font-size: 11px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.you .link-button {
    font-size: 11px;
    text-decoration: none;
    color: inherit;
}

.you .link-button:hover {
    text-decoration: underline;
}

/* 2026-10-31 - the content panel, inset from the slate on top and right
   (the status line's row is the slate below it); it keeps the content
   tokens, dark pairs included.
   2026-10-31 - the only part of the opened page that scrolls. app.js
   moves focus here on every page change (tabindex="-1") so Space, the
   arrows and Page Down scroll it without a click first.
   2026-10-31 - no top padding: the crumb row (.crumbs) is the panel's
   first row and holds that space itself. */
.main {
    grid-area: main;
    padding: 0 var(--main-pad-x) 40px;
    min-width: 0;
    min-height: 0;
    overflow: auto;
    overscroll-behavior: contain;
    /* 2026-10-31 - the panel floats with the SAME inset on all four sides. */
    margin: calc(var(--panel-inset) + env(safe-area-inset-top)) calc(var(--panel-inset) + env(safe-area-inset-right)) 0 var(--panel-inset);
    background: var(--page);
    border-radius: var(--panel-radius);
    box-shadow: var(--panel-shadow);
}

/* 2026-10-31 - the focus is there only for keyboard scrolling; a ring
   round the whole panel would say nothing. */
.main:focus {
    outline: none;
}

/* Phone-only chrome, hidden on wide screens. */
.phone-bar,
.tab-bar {
    display: none;
}

/* MARK: - Page headers and shelves */

.hello {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 4px 14px;
    margin-bottom: 22px;
}

.hello h1 {
    margin: 0;
    font-size: 28px;
    font-weight: 600;
    letter-spacing: -0.3px;
    overflow-wrap: anywhere;
}

.hello span {
    color: var(--t2);
    font-size: 13px;
}

/* MARK: - Crumb row (2026-10-31) */

/* 2026-10-31 - JG: one line at the top of the panel on every page in the
   frame, held at the top while the panel scrolls. It spans the panel's
   side padding so content scrolling under it is covered edge to edge; the
   hairline shows only once the panel has scrolled (app.js markScrolled).
   z-index lifts it over the tiles' positioned marks. */
.crumbs {
    position: sticky;
    top: 0;
    z-index: 3;
    height: var(--crumb-height);
    margin: 0 calc(-1 * var(--main-pad-x));
    padding: 0 var(--main-pad-x);
    display: flex;
    align-items: center;
    gap: 16px;
    background: var(--page);
    font-size: 13px;
    color: var(--t2);
}

.main.is-scrolled .crumbs {
    box-shadow: 0 1px 0 var(--rule);
}

.crumb-trail {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    align-items: center;
}

/* A part and the separator before it, so they leave together. */
.crumb-step {
    flex: 0 1 auto;
    min-width: 0;
    display: flex;
    align-items: center;
}

.crumb-sep,
.crumb-more {
    flex: none;
    color: var(--t3);
}

.crumb-sep {
    margin: 0 7px;
}

.crumb-part {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

a.crumb-part:hover {
    color: var(--t1);
    text-decoration: underline;
}

.crumb-part.current {
    color: var(--t1);
    font-weight: 500;
}

/* Phone only: stands in for the parts before the last two. */
.crumb-more {
    display: none;
}

/* The object stepper: ‹ 3 of 7 › at the row's right end. */
.stepper {
    flex: none;
    display: flex;
    align-items: center;
    gap: 2px;
}

.stepper .step {
    width: 26px;
    height: 26px;
    padding: 0 0 2px;
    border: none;
    border-radius: 6px;
    background: none;
    color: var(--t2);
    font-size: 19px;
    line-height: 1;
    display: grid;
    place-items: center;
    cursor: pointer;
}

.stepper .step:hover:not(:disabled) {
    background: var(--chip-edge);
    color: var(--t1);
}

.stepper .step:disabled {
    opacity: 0.4;
    cursor: default;
}

.step-count {
    min-width: 52px;
    text-align: center;
    font-size: 12px;
    color: var(--t2);
    font-variant-numeric: tabular-nums;
}

.shelf-h {
    font-size: 20px;
    font-weight: 600;
    margin: 26px 0 14px;
    display: flex;
    align-items: baseline;
    gap: 12px;
}

.shelf-h:first-of-type {
    margin-top: 0;
}

.shelf-h small {
    font-size: 12px;
    font-weight: 400;
    color: var(--t3);
}

.shelf {
    display: grid;
    grid-template-columns: repeat(auto-fill, 232px);
    gap: 16px;
    align-items: start;
}

.shelf.objects {
    grid-template-columns: repeat(auto-fill, 170px);
}

.message {
    color: var(--t2);
    font-size: 14px;
    text-align: center;
    padding: 48px 0;
    margin: 0;
}

/* The app's collection tile: card surface, 4:3 cover. */
.tile {
    background: var(--surface);
    border-radius: 5px;
    box-shadow: var(--tile-shadow);
    padding: 20px 16px 16px;
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-width: 0;
}

.tile .cover {
    aspect-ratio: 4 / 3;
    background: var(--deep);
    overflow: hidden;
    display: grid;
    place-items: center;
}

/* The ONE crop on the viewer side: the 4:3 collection cover (rule 8). */
.tile .cover img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.tile .cover svg {
    width: 40px;
    height: 40px;
    color: var(--glyph);
    stroke-width: 1.2;
}

.tile .cover.bm svg {
    color: var(--accent);
}

.tile .title {
    font-size: 13px;
    font-weight: 500;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.tile .sub {
    font-size: 11px;
    color: var(--t2);
}

/* MARK: - Gallery tiles (drawing 5) and shelf tiles (drawing 4) */

.grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
    gap: 20px 16px;
}

.gtile {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-width: 0;
}

.well {
    position: relative;
    aspect-ratio: 1;
}

/* A square box inside the well's padding; the picture fits inside it. */
.fit {
    position: absolute;
    inset: 14px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.otile .fit {
    inset: 10px;
}

/* .pic hugs the drawn image so the marks sit on the photo's own corner
   (rule 7). app.js sets its aspect ratio from the loaded image and which
   side fills the square box. */
.pic {
    position: relative;
    flex: none;
    width: 100%;
    height: 100%;
    max-width: 100%;
    max-height: 100%;
}

.pic.is-fitted.fit-width {
    height: auto;
}

.pic.is-fitted.fit-height {
    width: auto;
}

.pic > a,
.pic > .pic-image {
    display: block;
    width: 100%;
    height: 100%;
}

.pic img {
    display: block;
    width: 100%;
    height: 100%;
    filter: var(--lift);
}

.otile .pic img {
    filter: var(--lift-small);
}

.pic:not(.is-fitted) img,
.pic:not(.is-fitted):not(.is-missing) .marks {
    visibility: hidden;
}

.pic.is-missing {
    width: 70%;
    height: 70%;
}

.pic.is-missing > a,
.pic.is-missing > .pic-image {
    background: var(--deep);
    border-radius: 2px;
    display: grid;
    place-items: center;
}

.pic.is-missing svg.placeholder {
    width: 36%;
    height: 36%;
    color: var(--glyph);
    stroke-width: 1.2;
}

.marks {
    position: absolute;
    top: -8px;
    right: -8px;
    display: flex;
    gap: 4px;
}

.marks .mark-dot {
    width: 22px;
    height: 22px;
    border-radius: 50%;
    border: none;
    padding: 0;
    background: var(--mark-bg);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.22);
    display: grid;
    place-items: center;
}

.marks svg {
    width: 13px;
    height: 13px;
    stroke-width: 1.9;
}

.marks .bm {
    color: var(--accent);
    fill: var(--accent);
}

.cap {
    text-align: center;
    font-size: 13px;
    font-weight: 500;
    min-width: 0;
}

.cap > * {
    display: block;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.cap small {
    font-size: 11px;
    font-weight: 400;
    color: var(--t2);
    margin-top: 2px;
}

.cap small.creator,
.cap a.creator {
    color: var(--accent);
    font-size: 11px;
    font-weight: 400;
    margin-top: 2px;
}

.cap a:hover {
    text-decoration: underline;
}

/* MARK: - Chips (drawing 5) */

.chips {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin: 0 0 20px;
    align-items: center;
}

.chip {
    height: 32px;
    padding: 0 14px;
    border: none;
    border-radius: 16px;
    display: flex;
    align-items: center;
    gap: 4px;
    font-size: 13px;
    color: var(--t2);
    background: var(--chip-bg);
    box-shadow: inset 0 0 0 1px var(--chip-edge), 0 1px 3px rgba(0, 0, 0, 0.08);
    cursor: pointer;
    white-space: nowrap;
}

.chip i {
    font-style: normal;
    color: var(--t3);
}

.chip.tog {
    margin-left: auto;
}

.chip.tog svg {
    width: 13px;
    height: 13px;
    stroke-width: 1.8;
}

.chip.tog .bm-icon {
    color: var(--accent);
}

.chip.tog.on {
    background: var(--accent);
    color: #FFFFFF;
    box-shadow: none;
}

.chip.tog.on svg {
    color: #FFFFFF;
}

/* MARK: - Object page (drawing 6) */

.obj {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 380px;
    gap: 40px;
    align-items: start;
}

/* 2026-10-31 - position: relative anchors the page dots (.dots). */
.stage {
    position: relative;
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.big {
    position: relative;
    aspect-ratio: 4 / 3;
    cursor: zoom-in;
}

.big-fit {
    position: absolute;
    inset: 16px;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* Fills the box with object-fit: contain (fitted, never cropped) so the
   small copy and the display copy line up when one replaces the other; the
   drop shadow follows the drawn picture's edge, not the box. */
.big-fit img {
    width: 100%;
    height: 100%;
    object-fit: contain;
    display: block;
    filter: var(--lift-stage);
}

.big-fit .placeholder {
    width: 60px;
    height: 60px;
    color: var(--glyph);
    stroke-width: 1.2;
}

/* 2026-10-31 - JG: the desktop's photo page dots (Capture's ObjectPageView
   photoPageDots) in place of the thumbnail strip: a column centred on the
   photo, 7 px dots 9 px apart, the current photo's dot a 7 x 20 pill, all
   in --t1 with the others at 30 %. No transition: the pill moves in step
   with the photo. Fixed in the gutter between the photo and the text
   column, 22 px off the text column (the 40 px gap less 22, less the
   7 px dot), so no photo shape ever sits under them. */
.dots {
    position: absolute;
    top: 50%;
    right: -18px;
    transform: translateY(-50%);
    display: flex;
    flex-direction: column;
    gap: 9px;
}

.dots button {
    position: relative;
    width: 7px;
    height: 7px;
    padding: 0;
    border: none;
    border-radius: 3.5px;
    background: var(--t1);
    opacity: 0.3;
    cursor: pointer;
}

.dots button.cur {
    height: 20px;
    opacity: 1;
}

/* A larger target than the 7 px dot, drawn nowhere. */
.dots button::before {
    content: "";
    position: absolute;
    inset: -4px -8px;
}

.panel {
    padding-top: 6px;
    min-width: 0;
}

.otitle {
    font-weight: 300;
    font-size: 34px;
    letter-spacing: -0.4px;
    margin: 0 0 8px;
    line-height: 1.1;
    overflow-wrap: anywhere;
}

.osub {
    font-size: 15px;
    font-style: italic;
    color: var(--t2);
    margin: 0 0 8px;
}

.byline {
    display: inline-block;
    font-size: 15px;
    color: var(--accent);
    margin-bottom: 4px;
}

a.byline:hover {
    text-decoration: underline;
}

.num {
    font-size: 13px;
    color: var(--t2);
}

.bmline {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-top: 12px;
    font-size: 12px;
    color: var(--accent);
}

.bmline svg {
    width: 13px;
    height: 13px;
    fill: var(--accent);
    stroke-width: 1.5;
}

/* 2026-10-31 - 14 px (was 18), and 6 px attribute rows (was 7): the
   tighter rhythm that lets a typical object fit an 800 px panel. */
.rule {
    height: 1px;
    background: var(--rule);
    margin: 14px 0;
}

.attrs {
    width: 100%;
    border-collapse: collapse;
    font-size: 12px;
}

.attrs th {
    text-align: left;
    font-weight: 600;
    color: var(--t3);
    letter-spacing: 0.5px;
    padding: 6px 12px 6px 0;
    width: 42%;
    vertical-align: top;
    text-transform: uppercase;
    font-size: 11px;
}

.attrs td {
    padding: 6px 0;
    color: var(--t1);
    border-bottom: 1px solid var(--rule);
    overflow-wrap: anywhere;
}

.attrs tr:last-child td {
    border-bottom: none;
}

.description h3 {
    font-size: 11px;
    font-weight: 600;
    color: var(--t3);
    letter-spacing: 0.5px;
    margin: 0 0 8px;
    display: flex;
    justify-content: space-between;
    text-transform: uppercase;
}

.description p {
    font-size: 13px;
    line-height: 1.5;
    margin: 0;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

/* 2026-10-31 - four lines until More is chosen (app.js descriptionBlock). */
.description p.clamped {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 4;
    line-clamp: 4;
    overflow: hidden;
}

/* 2026-10-31 - sits on the right of the Description heading. */
.description h3 {
    align-items: baseline;
}

.more {
    padding: 0;
    border: none;
    background: none;
    font-size: 12px;
    font-weight: 500;
    letter-spacing: 0;
    text-transform: none;
    color: var(--accent);
    cursor: pointer;
}

.more:hover {
    text-decoration: underline;
}

.description a {
    color: var(--accent);
    text-decoration: underline;
}

.actions {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin-top: 4px;
}

.act {
    height: 32px;
    padding: 0 14px;
    border: none;
    border-radius: 9px;
    display: flex;
    align-items: center;
    gap: 7px;
    font-size: 13px;
    font-weight: 500;
    background: var(--surface);
    color: var(--t1);
    box-shadow: inset 0 0 0 1px var(--control-edge);
    cursor: pointer;
}

.act svg {
    width: 14px;
    height: 14px;
    stroke-width: 1.9;
}

/* MARK: - Creators */

.creator-list {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
    gap: 12px 16px;
}

.creator-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 12px;
    border-radius: 5px;
    background: var(--surface);
    box-shadow: var(--tile-shadow);
    min-width: 0;
}

.creator-row:hover .creator-name {
    text-decoration: underline;
}

.portrait-small {
    width: 48px;
    height: 48px;
    flex: none;
    display: grid;
    place-items: center;
}

.portrait-small img {
    max-width: 48px;
    max-height: 48px;
    display: block;
}

.portrait-placeholder {
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: var(--deep);
    color: var(--t3);
    display: grid;
    place-items: center;
    font-size: 13px;
    font-weight: 600;
}

.creator-text {
    min-width: 0;
    line-height: 1.3;
}

.creator-name {
    font-size: 13px;
    font-weight: 500;
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.creator-text small {
    display: block;
    font-size: 11px;
    color: var(--t2);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.creator-head {
    display: flex;
    gap: 24px;
    align-items: flex-start;
    margin-bottom: 28px;
}

.portrait {
    width: 160px;
    flex: none;
    display: grid;
    place-items: center;
}

.portrait img {
    max-width: 160px;
    max-height: 200px;
    display: block;
    filter: var(--lift-small);
}

.creator-head .hello {
    margin-bottom: 6px;
}

.creator-facts {
    font-size: 13px;
    color: var(--t2);
    margin: 0 0 12px;
}

.bio {
    font-size: 13px;
    line-height: 1.55;
    margin: 0;
    max-width: 640px;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

/* MARK: - You */

/* 2026-10-31 - the keyboard line, above Sign out. */
.you-page .lead {
    margin-bottom: 20px;
}

.you-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
}

.quiet-button {
    height: 32px;
    padding: 0 14px;
    border: none;
    border-radius: 9px;
    background: var(--surface);
    box-shadow: inset 0 0 0 1px var(--control-edge);
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
}

/* MARK: - Full-screen viewer (drawing 6b) */

.viewer {
    position: fixed;
    inset: 0;
    z-index: 50;
    background: #0E0E10;
    overflow: hidden;
    touch-action: none;
    user-select: none;
    -webkit-user-select: none;
}

.viewer-stage {
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    cursor: grab;
}

.viewer-stage.dragging {
    cursor: grabbing;
}

/* Fills 94 % of the screen with object-fit: contain — fitted, never
   cropped — so the scaled small copy and the display copy line up and the
   swap does not jump. */
.viewer-stage img {
    width: 94vw;
    height: 94vh;
    object-fit: contain;
    display: block;
    transform-origin: 50% 50%;
    will-change: transform;
    -webkit-user-drag: none;
    pointer-events: none;
}

.viewer-close,
.viewer-prev,
.viewer-next {
    position: absolute;
    border: none;
    border-radius: 50%;
    color: #FFFFFF;
    display: grid;
    place-items: center;
    cursor: pointer;
    padding: 0;
}

.viewer-close {
    top: 16px;
    right: 16px;
    width: 32px;
    height: 32px;
    background: rgba(255, 255, 255, 0.14);
    font-size: 16px;
    -webkit-backdrop-filter: blur(10px);
    backdrop-filter: blur(10px);
}

.viewer-prev,
.viewer-next {
    top: 50%;
    transform: translateY(-50%);
    width: 36px;
    height: 36px;
    background: rgba(255, 255, 255, 0.12);
    font-size: 18px;
}

.viewer-prev {
    left: 14px;
}

.viewer-next {
    right: 14px;
}

.viewer-title {
    position: absolute;
    top: 22px;
    left: 20px;
    right: 64px;
    color: rgba(255, 255, 255, 0.7);
    font-size: 13px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.viewer-hint {
    position: absolute;
    bottom: 18px;
    left: 50%;
    transform: translateX(-50%);
    color: rgba(255, 255, 255, 0.55);
    font-size: 12px;
    white-space: nowrap;
}

body.viewer-open {
    overflow: hidden;
}

/* MARK: - Errors (Apple's text, verbatim) and the status line */

.banner {
    position: sticky;
    top: 0;
    z-index: 40;
    background: var(--error-bg);
    color: var(--error-fg);
    border-bottom: 1px solid var(--error-line);
    padding: 10px var(--gutter);
    display: flex;
    gap: 12px;
    align-items: flex-start;
}

.banner-list {
    flex: 1;
    min-width: 0;
    margin: 0;
    padding: 0;
    list-style: none;
    font-family: ui-monospace, Menlo, monospace;
    font-size: 11px;
    overflow-wrap: anywhere;
    max-height: 30vh;
    overflow-y: auto;
}

.banner-list li + li {
    margin-top: 6px;
    padding-top: 6px;
    border-top: 1px solid var(--error-line);
}

.banner-dismiss {
    color: var(--error-fg);
    flex-shrink: 0;
    font-size: 12px;
}

/* 2026-10-31 - in the frame, its own grid row under the panel. */
.status-line {
    padding: 8px var(--gutter) calc(8px + env(safe-area-inset-bottom));
    text-align: center;
    color: var(--on-frame-status);
    font-size: 11px;
    display: flex;
    justify-content: center;
    flex-wrap: wrap;
    gap: 4px 12px;
}

.status-line .link-button {
    color: inherit;
}

body:not(.has-frame) .status-line {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    padding-bottom: calc(16px + env(safe-area-inset-bottom));
}

/* MARK: - Wide windows: the object page fits the panel */

/* 2026-10-31 - JG: at a normal window (a panel about 800 px tall) the
   object page fits without scrolling. It fills the panel's content box;
   the photo takes the full height, fitted and never cropped (no
   thumbnail strip beneath it since 2026-10-31). Too much text scrolls
   the text column on its own while the photo stays put. Only under min-height (a panel under about 630 px)
   does the panel itself scroll. Narrower windows keep the stacked page
   below, which scrolls with the panel as before. */
/* 2026-10-31 - the page now shares the panel's content box with the crumb
   row above it, so it takes the height left under the row; min-height 550
   keeps the panel scrolling only under about 630 px (550 + 40 + 40). */
@media (width > 1000px) {
    .obj {
        height: calc(100% - var(--crumb-height));
        min-height: 550px;
        grid-template-rows: minmax(0, 1fr);
        align-items: stretch;
        container: obj / size;
    }

    .stage {
        min-height: 0;
    }

    .big {
        flex: 1 1 0;
        min-height: 0;
        aspect-ratio: auto;
    }

    /* The 4 px side padding, taken back by the margin, keeps the buttons'
       edges and focus rings inside the scrolling box. */
    .panel {
        min-height: 0;
        overflow-y: auto;
        overscroll-behavior: contain;
        margin: 0 -4px;
        padding: 6px 4px 4px;
    }

    /* A panel under 860 px tall: the 40 px crumb row and 40 px bottom
       padding leave the page under 780 px (2026-10-31, was 792 with the
       old 28 px top padding). */
    @container obj (height < 780px) {
        .otitle {
            font-size: 30px;
        }
    }
}

/* MARK: - Narrower windows: the object page stacks */

@media (max-width: 1000px) {
    .obj {
        grid-template-columns: minmax(0, 1fr);
        gap: 24px;
    }

    /* 2026-10-31 - stacked, the text is below, so the dots keep a gutter
       of their own at the photo's right instead. */
    .stage.has-dots {
        padding-right: 16px;
    }

    .dots {
        right: 0;
    }
}

/* MARK: - Phone: top bar + bottom tab bar (Collections · Creators · Views) */

@media (max-width: 760px) {
    .gate-center {
        padding: 28px 24px;
        gap: 12px;
    }

    .titleline {
        gap: 12px;
    }

    .mark {
        width: 62px;
        height: 62px;
        border-radius: 14px;
    }

    .title {
        font-size: 28px;
        text-align: left;
        line-height: 1.1;
        max-width: 7em;
    }

    .lead {
        font-size: 13px;
    }

    .gate-body {
        align-self: stretch;
    }

    /* 2026-10-31 - one column: the top bar and the tab bar hold still at the
       top and bottom, the panel between them scrolls, and the status line
       is a thin slate row just above the tab bar. */
    body.has-frame {
        grid-template-columns: minmax(0, 1fr);
        grid-template-rows: auto auto minmax(0, 1fr) auto auto;
        grid-template-areas:
            "bar"
            "banner"
            "main"
            "status"
            "tabs";
    }

    .sidebar {
        display: none;
    }

    .phone-bar {
        grid-area: bar;
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        gap: 12px;
        padding: calc(10px + env(safe-area-inset-top)) calc(var(--gutter) + env(safe-area-inset-right)) 10px
            calc(var(--gutter) + env(safe-area-inset-left));
        background: var(--frame);
        color: var(--on-frame);
    }

    .phone-bar .brand {
        padding: 0;
        flex: 1;
        min-width: 0;
        font-size: 15px;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }

    .tab-bar {
        grid-area: tabs;
        display: flex;
        background: var(--frame);
        padding: 0 env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
    }

    .tab-bar a {
        flex: 1;
        display: flex;
        flex-direction: column;
        align-items: center;
        gap: 3px;
        padding: 8px 0 6px;
        font-size: 10px;
        font-weight: 500;
        color: var(--on-frame-2);
    }

    .tab-bar a svg {
        width: 22px;
        height: 22px;
        stroke-width: 1.6;
    }

    .tab-bar a.sel {
        color: var(--on-frame);
    }

    /* 2026-10-31 - full width on the phone, rounded only at the top.
       2026-10-31 - the crumb row holds the top space (was 20 px padding). */
    :root {
        --crumb-height: 36px;
        --main-pad-x: var(--gutter);
    }

    .main {
        margin: 0;
        border-radius: var(--panel-radius) var(--panel-radius) 0 0;
        padding: 0 var(--main-pad-x) 24px;
    }

    /* 2026-10-31 - only the last two parts fit: "… › Parent › Current". */
    .crumb-early {
        display: none;
    }

    .crumb-more {
        display: block;
    }

    /* 2026-10-31 - the tab bar below carries the bottom safe area. */
    body.has-frame .status-line {
        padding: 6px var(--gutter);
    }

    .hello h1 {
        font-size: 24px;
    }

    .shelf {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 12px;
    }

    .shelf.objects {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .tile {
        padding: 14px 12px 12px;
    }

    .grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 16px 12px;
    }

    .chip {
        height: 30px;
        padding: 0 12px;
    }

    .otitle {
        font-size: 28px;
    }

    .creator-head {
        flex-direction: column;
        gap: 16px;
    }

    .viewer-hint {
        display: none;
    }
}
