/* ==========================================================================
   Canvasy — design tokens
   Palette drawn from real pigment names: paper, ink, cadmium, phthalo,
   alizarin, sap green. Fraunces for display type (has real personality
   without being a generic "AI serif"), Work Sans for UI/body.
   ========================================================================== */

/* Self-hosted Google Fonts (Fraunces, Work Sans), variable weight 400-700, latin + latin-ext, font-display: swap. */

@font-face {
  font-family: 'Fraunces';
  font-style: italic;
  font-weight: 400 700;
  font-display: swap;
  src: url('/assets/fonts/fraunces-500-italic-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Fraunces';
  font-style: italic;
  font-weight: 400 700;
  font-display: swap;
  src: url('/assets/fonts/fraunces-500-italic-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/assets/fonts/fraunces-400-normal-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/assets/fonts/fraunces-400-normal-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Work Sans';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/assets/fonts/work-sans-400-normal-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Work Sans';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/assets/fonts/work-sans-400-normal-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
    --paper: #FAF6EE;
    --paper-dim: #F1EADA;
    --ink: #211C15;
    --ink-soft: #57503F;
    --cadmium: #F2A93B;
    --cadmium-deep: #D98A1F;
    --phthalo: #1C5D6B;
    --phthalo-deep: #133F49;
    --alizarin: #B23A48;
    --sap: #5C7A4A;
    --line: rgba(33, 28, 21, 0.14);
    --shadow: rgba(33, 28, 21, 0.18);
    --notice-bg: #FCEFD9;
    --notice-text: #5A3E0F;
    --error-bg: #FBE4E4;
    --error-text: #7A2530;
    --success-bg: #E7EFE1;
    --success-text: #37502B;
    --surface: #FFFFFF;
    /* Pop-up menus (.more-menu-panel): set apart from the page. */
    --popover-bg: #FFFFFF;
    --popover-border: rgba(33, 28, 21, 0.22);
    --popover-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
    --popover-hover: #F1EADA;

    --font-display: 'Fraunces', Georgia, serif;
    --font-body: 'Work Sans', -apple-system, Segoe UI, sans-serif;

    --radius: 6px;
    --max-width: 1180px;
}

/* ---------- Dark theme ----------
   Two ways in: the system/browser preference (when the person hasn't
   picked an explicit theme — data-theme is absent or "auto"), or an
   explicit choice saved via the theme switcher. Same warm pigment
   identity, inverted: dark paper, light ink, and slightly brightened
   accents so cadmium/phthalo/alizarin/sap still pop against a dark
   background instead of going muddy. */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        --paper: #1B1712;
        --paper-dim: #262019;
        --ink: #F0E9DD;
        --ink-soft: #B3A692;
        --cadmium: #F5B754;
        --cadmium-deep: #FFCB73;
        --phthalo: #4E9FB3;
        --phthalo-deep: #6FBBCF;
        --alizarin: #D9505F;
        --sap: #83A96A;
        --line: rgba(240, 233, 221, 0.14);
        --shadow: rgba(0, 0, 0, 0.4);
        --notice-bg: #3D2F13;
        --notice-text: #F0D9A6;
        --error-bg: #3D1B1E;
        --error-text: #F5B8BE;
        --success-bg: #1E2E17;
        --success-text: #B7D9A0;
        --surface: #262019;
        --popover-bg: #2E2720;
        --popover-border: rgba(240, 233, 221, 0.3);
        --popover-shadow: 0 10px 30px rgba(0, 0, 0, 0.6);
        --popover-hover: #3A3229;
    }
}
:root[data-theme="dark"] {
    --paper: #1B1712;
    --paper-dim: #262019;
    --ink: #F0E9DD;
    --ink-soft: #B3A692;
    --cadmium: #F5B754;
    --cadmium-deep: #FFCB73;
    --phthalo: #4E9FB3;
    --phthalo-deep: #6FBBCF;
    --alizarin: #D9505F;
    --sap: #83A96A;
    --line: rgba(240, 233, 221, 0.14);
    --shadow: rgba(0, 0, 0, 0.4);
    --notice-bg: #3D2F13;
    --notice-text: #F0D9A6;
    --error-bg: #3D1B1E;
    --error-text: #F5B8BE;
    --success-bg: #1E2E17;
    --success-text: #B7D9A0;
    --surface: #262019;
    --popover-bg: #2E2720;
    --popover-border: rgba(240, 233, 221, 0.3);
    --popover-shadow: 0 10px 30px rgba(0, 0, 0, 0.6);
    --popover-hover: #3A3229;
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }

/* The hidden attribute always hides, even on elements whose class sets a
   display (.btn, .field, ...) — otherwise class display rules win and a
   "hidden" button shows up. Scripts toggle .hidden; nothing shows a hidden
   element by setting style.display. */
[hidden] { display: none !important; }

body {
    margin: 0;
    background: var(--paper);
    color: var(--ink);
    font-family: var(--font-body);
    font-size: 16px;
    line-height: 1.55;
    -webkit-font-smoothing: antialiased;
    transition: background-color 0.2s ease, color 0.2s ease;
}

.site-header, .panel, .art-card, .group-card, .site-footer,
input, textarea, select {
    transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease;
}

img { max-width: 100%; display: block; }

a { color: var(--phthalo); text-decoration: none; }
a:hover { color: var(--phthalo-deep); text-decoration: underline; }

:focus-visible {
    outline: 3px solid var(--cadmium-deep);
    outline-offset: 2px;
}

h1, h2, h3, h4 {
    font-family: var(--font-display);
    font-weight: 600;
    line-height: 1.15;
    margin: 0 0 0.5em;
    color: var(--ink);
}

h1 { font-size: clamp(2.2rem, 5vw, 3.6rem); font-weight: 700; }
h2 { font-size: clamp(1.5rem, 3vw, 2.1rem); }
h3 { font-size: 1.25rem; }

p { margin: 0 0 1em; color: var(--ink-soft); }

.container {
    max-width: var(--max-width);
    margin: 0 auto;
    padding: 0 24px;
}

/* ---------- Buttons & form controls ---------- */

.btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-family: var(--font-body);
    font-weight: 600;
    font-size: 0.95rem;
    padding: 11px 22px;
    border-radius: var(--radius);
    border: 2px solid var(--ink);
    background: transparent;
    color: var(--ink);
    cursor: pointer;
    text-decoration: none;
    transition: transform 0.12s ease, background 0.12s ease, color 0.12s ease;
}
.btn:hover { background: var(--ink); color: var(--paper); text-decoration: none; transform: translateY(-1px); }

.btn-primary {
    /* Fixed color, not var(--alizarin) — :hover below already uses a fixed
       darker red for exactly this reason, but the base state was left on
       the theme variable, which flips to a lighter red in dark mode and
       drops white-text contrast to ~4:1, under WCAG AA's 4.5:1 minimum.
       This keeps light mode's exact existing look (same value) and just
       stops dark mode from using the lighter flipped variant. */
    background: #B23A48;
    border-color: #B23A48;
    color: #fff;
}
.btn-primary:hover { background: #94222f; border-color: #94222f; color: #fff; }

.btn-ghost {
    border-color: var(--line);
    color: var(--ink-soft);
}
.btn-ghost:hover { background: var(--ink-soft); border-color: var(--ink-soft); }

.btn-small { padding: 7px 14px; font-size: 0.85rem; }

input[type=text], input[type=email], input[type=password], input[type=search],
textarea, select {
    width: 100%;
    font-family: var(--font-body);
    font-size: 1rem;
    padding: 12px 14px;
    border: 2px solid var(--line);
    border-radius: var(--radius);
    background: var(--surface);
    color: var(--ink);
}
input:focus, textarea:focus, select:focus {
    border-color: var(--phthalo);
    outline: none;
}
label {
    display: block;
    font-weight: 600;
    font-size: 0.9rem;
    margin: 0 0 6px;
    color: var(--ink);
}
.field { margin-bottom: 18px; }
.help-text { font-size: 0.85rem; color: var(--ink-soft); margin-top: 4px; }
/* "1850 / 2000" under a [data-max-chars] box (site.js), from 90% of the limit. */
.char-count { text-align: right; margin: 4px 0 0; font-variant-numeric: tabular-nums; }
.char-count-over { color: var(--alizarin); font-weight: 600; }

/* ---------- Site header ---------- */
/* Anchor targets (#stats, #comments, ...) stop below the sticky header, not
   under it. assets/js/site.js keeps the variable at the header's real
   height; these are the fallbacks for one row (desktop) and two (phones). */
:root { --sticky-header-height: 77px; }
@media (max-width: 760px) { :root { --sticky-header-height: 55px; } }
/* :target only, not every [id]: scripts that scroll ordinary elements into
   view (e.g. the search suggestions list) mustn't get this margin. */
:target { scroll-margin-top: calc(var(--sticky-header-height) + 12px); }


.site-header {
    border-bottom: 3px solid var(--ink);
    background: var(--paper);
    position: sticky;
    top: 0;
    z-index: 20;
}
.site-header .container {
    display: flex;
    align-items: center;
    justify-content: space-between;
    height: 74px;
    gap: 20px;
    /* Containing block for .nav-account-menu below — see the comment there
       for why it can't stay anchored to .nav-account itself. */
    position: relative;
}
.brand {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 1.6rem;
    color: var(--ink);
    display: flex;
    align-items: baseline;
    gap: 2px;
    letter-spacing: -0.01em;
}
.brand:hover { text-decoration: none; }
.brand .dot { color: var(--alizarin); font-size: 1.3rem; }

.nav-links {
    display: flex;
    align-items: center;
    gap: 22px;
    font-weight: 500;
    /* Logged-in nav now has enough links (Groups, Collections, Upload,
       Notifications, Messages, Security, admin, account, log out) that it
       can outgrow the header on real desktop widths. Each link already
       refuses to shrink (flex-shrink: 0 below), which — without this —
       forced the browser to take the space from .search-form instead,
       squeezing the search box down to nearly nothing. min-width: 0
       overrides the flex default of min-width: auto (which floors a flex
       item at its content's natural size), so this can actually shrink
       and scroll horizontally instead of fighting its sibling for room.
       Scrollbar is hidden (still scrollable by trackpad/swipe/arrow keys) —
       a visible one doesn't fit inside the header's fixed 74px height
       without looking clipped; the mobile breakpoint below already does
       the same thing for the same reason.
       overflow-y: visible is required here, not just cosmetic — a browser
       that sees overflow-x set to anything but visible, with no explicit
       overflow-y, silently computes overflow-y to auto too (CSS spec
       behavior, not a bug), which clips anything taller than the row
       itself. The unread-count badges (span.badge, padding: 2px 8px) are
       taller than plain link text, so without this line their top/bottom
       gets sliced off — the exact "cut off" look this comment is here to
       prevent regressing again. */
    min-width: 0;
    overflow-x: auto;
    overflow-y: visible;
    scrollbar-width: none;
    -ms-overflow-style: none;
    -webkit-overflow-scrolling: touch;
}
.nav-links::-webkit-scrollbar { display: none; }
/* padding (not just line-height) gets the actual tap target to ~44px tall,
   not just the text — a phone finger needs the padding area too, margin
   compensates so the visible row height and spacing don't change.
   > (direct child), not a bare descendant selector — this used to be
   `.nav-links a`, which also matched every link inside .nav-account-menu
   (a descendant of .nav-links further down the DOM, even though it's
   repositioned elsewhere on screen via position:absolute — that doesn't
   change what a CSS descendant selector matches). The -10px vertical
   margin meant to compensate THIS row's padding was instead pulling each
   stacked menu item ~18px into its neighbours, so a hovered item's
   highlight got cut off by the items above/below it. Confirmed live in
   both themes. Upload/Notifications/Messages are still direct children of
   .nav-links, so they're unaffected by the narrower selector. */
.nav-links > a { color: var(--ink); flex-shrink: 0; padding: 10px 2px; margin: -10px -2px; }
.nav-links > a:hover { color: var(--alizarin); text-decoration: none; }

/* ---------- Account menu (avatar dropdown) ---------- */
/* Everything besides Upload/Notifications/Messages lives here instead of
   as its own top-level nav link — see the comment in header.php for why. */
/* static, not relative — .nav-links (its parent) has overflow-x: auto for
   the horizontal-scroll safety net, and per the CSS overflow spec, setting
   overflow-x to anything but visible forces the COMPUTED value of
   overflow-y to auto too, even though it's explicitly declared visible
   below — there's no way to opt out of that. That makes .nav-links a
   clipping container for everything painted inside it, including an
   absolutely-positioned dropdown whose containing block is a descendant
   of it (confirmed live: the menu was computing display:flex and
   opacity:1 but still invisible, clipped by this ancestor). Removing
   .nav-account's own `position: relative` here stops it from being that
   containing block, so .nav-account-menu below escapes to .site-header
   .container instead (the nearest ancestor OUTSIDE .nav-links that is
   positioned) and paints outside the clip entirely. */
.nav-account { position: static; flex-shrink: 0; }
.nav-account summary {
    /* display is deliberately left alone here (no flex/block override) —
       changing a <summary> element's own display value is a known way to
       break native click-to-toggle in some browsers (confirmed: it did,
       in Firefox). The flex layout lives on .nav-account-trigger inside
       it instead; summary only gets the bits that are safe to touch. */
    cursor: pointer;
    list-style: none;
    color: var(--ink);
}
.nav-account summary::-webkit-details-marker { display: none; }
/* padding here, not on <summary> itself — same reasoning as above: touching
   properties on <summary> beyond cursor/list-style risks breaking its
   native click behavior again, so the tap-target padding goes on this
   inner wrapper instead. */
.nav-account-trigger { display: flex; align-items: center; gap: 6px; padding: 10px 2px; margin: -10px -2px; }
.nav-account-trigger::after { content: '\25BE'; font-size: 0.65em; margin-left: 1px; flex-shrink: 0; }
.nav-account[open] .nav-account-trigger::after { content: '\25B4'; }
.nav-account-name {
    max-width: 110px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.nav-account-menu {
    position: absolute;
    /* Positioned against .site-header .container now (100% = its 74px
       height), not .nav-account anymore — see the comment on .nav-account
       above. */
    top: calc(100% - 4px);
    right: 0;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: 10px;
    min-width: 220px;
    max-width: calc(100vw - 32px);
    display: flex;
    flex-direction: column;
    gap: 2px;
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.18);
    z-index: 30;
}
.nav-account-menu a {
    padding: 8px 10px;
    border-radius: 6px;
    color: var(--ink);
    flex-shrink: 1;
}
/* "Log out" is a form button (a plain link let any other site log you out
   by embedding it) — made to look exactly like the menu links around it. */
.nav-account-menu-button {
    display: block;
    width: 100%;
    padding: 8px 10px;
    border: 0;
    border-radius: 6px;
    background: none;
    color: var(--ink);
    font: inherit;
    text-align: left;
    cursor: pointer;
}
/* Not --paper-dim: in dark mode it's literally the same hex as --surface
   (both #262019), which this menu uses as its own background — the hover
   highlight was invisible. color-mix() against --ink (always high-contrast
   against --surface in every theme, by design — same invariant the earlier
   WCAG contrast pass relies on everywhere else) can't collide the same way
   no matter what the theme's exact colors are. The rgba() line first is a
   plain fallback for a browser old enough not to support color-mix() — such
   a browser fails to parse the next line and keeps this one instead. */
.nav-account-menu a:hover,
.nav-account-menu a:focus-visible,
.nav-account-menu-button:hover,
.nav-account-menu-button:focus-visible {
    background: rgba(128, 128, 128, 0.16);
    background: color-mix(in srgb, var(--ink) 9%, transparent);
    color: var(--ink);
    text-decoration: none;
}
.nav-account-menu-profile { display: flex; align-items: center; gap: 10px; }
.nav-account-menu hr { border: none; border-top: 1px solid var(--line); margin: 6px 2px; }
.nav-account-theme {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 4px 10px;
}
.nav-account-theme select { width: auto; padding: 5px 8px; font-size: 0.85rem; }

/* ---------- Avatars ---------- */

.avatar-img {
    border-radius: 50%;
    object-fit: cover;
    border: 2px solid var(--ink);
    display: inline-block;
    vertical-align: middle;
}
.avatar-placeholder {
    border-radius: 50%;
    border: 2px solid var(--ink);
    /* Fixed color, not var(--phthalo) — same dark-mode flip problem as the
       badges: phthalo lightens in dark mode, dropping white-text contrast
       to ~3:1. Keeps light mode's exact existing look. */
    background: #1C5D6B;
    color: #fff;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-family: var(--font-display);
    font-weight: 600;
    vertical-align: middle;
}
.avatar-nav { width: 30px; height: 30px; font-size: 0.9rem; }
.avatar-profile { width: 96px; height: 96px; font-size: 2.2rem; }

.search-form { flex: 1; max-width: 360px; min-width: 140px; }
.search-form input { padding: 9px 14px; }

/* ---------- Header icons (phones only; the sprite is in includes/header.php) ---------- */
.icon-sprite { position: absolute; width: 0; height: 0; overflow: hidden; }
.icon { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; flex-shrink: 0; }
.nav-icon {
    display: inline-flex; align-items: center; justify-content: center;
    width: 44px; height: 44px; padding: 0; margin: 0; border: 0; border-radius: 10px;
    background: none; color: var(--ink); cursor: pointer; flex-shrink: 0;
}
.nav-icon:hover { color: var(--alizarin); }
.nav-icon:focus-visible, .nav-item:focus-visible, .nav-account summary:focus-visible { outline: 3px solid var(--alizarin); outline-offset: 2px; border-radius: 10px; }
/* Desktop: exactly as before, so everything phone-only stays out of sight. */
.search-toggle, .search-close, .nav-item .icon, .brand-short, .footer-theme { display: none; }
/* The logo's text and dot sit in these wrappers now; same 2px gap as before. */
.brand-full, .brand-short { align-items: baseline; gap: 2px; }
.brand-full { display: inline-flex; }
.header-theme { width: auto; padding: 6px 8px; font-size: 0.85rem; flex-shrink: 0; }

/* ---------- Compact phone header ---------- */
/* One 56px row: logo, then 44x44 icon buttons (Search, Upload,
   Notifications and Messages with their counts, the account menu). The
   search box opens in a row underneath from the Search button (not on
   search.php, which has its own box). While scrolling down the header
   slides up out of view, and comes back on scrolling up (site.js); it moves
   with transform, so nothing below it jumps. */
@media (max-width: 760px) {
    .site-header { transition: transform 0.2s ease; }
    .site-header.header-hidden { transform: translateY(-100%); }
    .site-header .container { flex-wrap: wrap; height: auto; min-height: 52px; padding: 4px 8px 4px 16px; gap: 0 2px; }
    .brand { order: 1; margin-right: auto; font-size: 1.35rem; line-height: 1; padding: 0; position: relative; }
    /* An invisible 44px-tall tap area around the logo (at least 44px wide:
       the "C." alone is only ~23px), without changing how it looks. */
    .brand::after { content: ''; position: absolute; left: 50%; top: 50%; width: max(100%, 44px); height: 44px; transform: translate(-50%, -50%); }
    /* The Search button needs site.js (html.js); without it the box simply
       stays visible as its own row (below). */
    .js .search-toggle { display: inline-flex; order: 2; }
    .no-phone-search .search-toggle { display: none; }
    .nav-links { order: 3; gap: 2px; overflow: visible; font-size: 0.9rem; white-space: nowrap; }
    .nav-links > a { margin: 0; }
    .nav-links > a.nav-item { position: relative; display: inline-flex; align-items: center; justify-content: center; width: 44px; height: 44px; padding: 0; border-radius: 10px; }
    .nav-item .icon { display: block; }
    .nav-label, .nav-account-name { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }
    /* Top right of the icon, from just left of its middle, so the icon stays
       visible and even "99+" (the most shown) stays inside its own 44px
       button, clear of the next one; taps go to whatever is underneath.
       (.site-header for specificity: the general .badge rule comes later.) */
    .site-header .nav-badge { position: absolute; top: 4px; left: 17px; margin: 0; min-width: 16px; height: 16px; padding: 0 4px; line-height: 16px; font-size: 0.6rem; text-align: center; pointer-events: none; }
    .nav-account-trigger { width: 44px; height: 44px; justify-content: center; padding: 0; margin: 0; }
    .nav-account-trigger::after { display: none; }
    /* Logged out: "Log in" as a 44px-tall text link, "Join free" as is. */
    .nav-links > a[href="/login.php"] { display: inline-flex; align-items: center; min-height: 44px; padding: 0 8px; }
    .header-theme { display: none; }
    .footer-theme { display: inline-flex; align-items: center; gap: 8px; }
    .footer-theme select { width: auto; padding: 6px 8px; font-size: 0.85rem; }
    /* The search row. */
    .js .search-form { display: none; }
    .no-phone-search .search-form { display: none; }
    .search-form, .js .search-open .search-form { display: flex; align-items: center; gap: 4px; order: 10; flex: 1 1 100%; max-width: 100%; min-width: 0; padding: 4px 0 6px; }
    .search-form input { flex: 1; min-width: 0; min-height: 44px; }
    .js .search-close { display: inline-flex; }
}
@media (max-width: 760px) and (prefers-reduced-motion: reduce) {
    .site-header { transition: none; }
}
/* Too narrow for the full name next to five buttons: the "C." mark. */
@media (max-width: 359px) {
    .brand-full { display: none; }
    .brand-short { display: inline-flex; }
}
@media (max-width: 420px) {
    .container { padding: 0 16px; }
}
/* Several pages put padding:<top> 0 <bottom> inline on their container,
   which also zeroed its sides, so on phones the text touched the screen
   edges. Phones only (desktop unchanged): the usual side padding wins. */
@media (max-width: 760px) {
    main .container, main.container, .site-footer .container { padding-left: 24px !important; padding-right: 24px !important; }
}
@media (max-width: 420px) {
    main .container, main.container, .site-footer .container { padding-left: 16px !important; padding-right: 16px !important; }
}

/* ---------- Hero ---------- */

.hero {
    padding: 64px 0 48px;
    border-bottom: 1px solid var(--line);
}
.hero-swatches {
    display: flex;
    gap: 8px;
    margin-bottom: 22px;
}
.swatch {
    width: 34px; height: 34px; border-radius: 50%;
    border: 2px solid var(--ink);
}
.hero h1 { max-width: 14ch; }
.hero .lede {
    font-size: 1.15rem;
    max-width: 46ch;
    color: var(--ink-soft);
}
.hero-actions { display: flex; gap: 14px; margin-top: 26px; flex-wrap: wrap; }

/* ---------- Gallery grid (masonry via CSS columns) ---------- */

.gallery {
    columns: 4 260px;
    column-gap: 18px;
    padding: 40px 0 60px;
}
@media (max-width: 700px) { .gallery { columns: 2 160px; } }
@media (max-width: 420px) { .gallery { columns: 1; } }

.art-card {
    break-inside: avoid;
    margin-bottom: 18px;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    overflow: hidden;
    background: var(--surface);
    transition: box-shadow 0.15s ease;
}
.art-card:hover { box-shadow: 0 6px 18px var(--shadow); }
.art-card img { width: 100%; height: auto; display: block; }
.art-card .meta {
    padding: 10px 12px 12px;
}
.art-card .art-title {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 1rem;
    margin: 0 0 4px;
}
.art-card .art-by {
    font-size: 0.85rem;
    color: var(--ink-soft);
}
.badge {
    display: inline-block;
    font-size: 0.7rem;
    font-weight: 600;
    padding: 2px 8px;
    border-radius: 999px;
    margin-left: 6px;
}
/* Fixed color, not var(--alizarin) — that flips to a lighter red in dark
   mode (white text drops to ~4:1, under WCAG AA's 4.5:1 minimum there),
   and even its light-mode value only hits ~5.85:1, which reads as weak at
   this badge's small size/weight. This fixed darker red holds ~9:1 against
   white in both themes, with comfortable margin either way. */
.badge-private { background: #862533; color: #fff; }
/* --ink/--paper (not --phthalo) because --phthalo flips to a lighter teal
   in dark mode, which drops white text to ~3:1 contrast — under WCAG AA's
   4.5:1 minimum. --ink/--paper are already a theme-matched, guaranteed-
   contrast pair (same ones .btn:hover uses) in both themes. */
.badge-group { background: var(--ink); color: var(--paper); }
/* Hidden by moderators. Fixed colours for the same reason as .badge-private:
   white on this dark ochre is ~9:1 in both themes. */
.badge-hidden { background: #5A4317; color: #fff; }

/* ---------- Sections / cards generic ---------- */

.section-title-row {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    padding-top: 40px;
}

.panel {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: 28px;
}

.auth-wrap {
    max-width: 420px;
    margin: 60px auto;
}
.auth-wrap .panel { padding: 34px; }

.flash {
    padding: 12px 16px;
    border-radius: var(--radius);
    margin-bottom: 20px;
    font-weight: 500;
}
.flash-error { background: var(--error-bg); color: var(--error-text); border: 1px solid var(--alizarin); }
.flash-success { background: var(--success-bg); color: var(--success-text); border: 1px solid var(--sap); }
.flash-notice { background: var(--notice-bg); color: var(--notice-text); border: 1px solid var(--cadmium-deep); }

/* ---------- Artwork detail page ---------- */

.art-detail {
    display: grid;
    grid-template-columns: 1.6fr 1fr;
    gap: 40px;
    padding: 40px 0 60px;
}
@media (max-width: 800px) { .art-detail { grid-template-columns: 1fr; } }
.art-detail img { border-radius: var(--radius); border: 1px solid var(--line); width: 100%; height: auto; display: block; }
.tag-list { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 14px; }
.tag {
    font-size: 0.8rem;
    padding: 4px 10px;
    border: 1px solid var(--line);
    border-radius: 999px;
    color: var(--ink-soft);
}

/* ---------- Groups ---------- */

.group-card {
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: 20px;
    background: var(--surface);
    margin-bottom: 14px;
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: center;
    gap: 16px;
}

/* Two-column layout used for side-by-side forms/panels (create/join group,
   admin dashboard summary panels) — stacks to one column on narrower
   screens rather than squeezing both columns down to an unreadable width. */
.two-col-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 24px;
}
@media (max-width: 700px) {
    .two-col-grid { grid-template-columns: 1fr; }
}

/* ---------- Footer ---------- */

.site-footer {
    border-top: 3px solid var(--ink);
    padding: 32px 0;
    margin-top: 40px;
    font-size: 0.9rem;
    color: var(--ink-soft);
    display: flex;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 12px;
}
.site-footer a { color: var(--ink-soft); }

.empty-state {
    text-align: center;
    padding: 60px 20px;
    color: var(--ink-soft);
}

.upload-dropzone {
    border: 2px dashed var(--line);
    border-radius: var(--radius);
    padding: 40px 20px;
    text-align: center;
    background: var(--surface);
    color: var(--ink-soft);
    margin-bottom: 20px;
}

/* ---------- Art book (artbook.php) ---------- */
.artbook-page {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: 28px;
    margin-bottom: 24px;
    text-align: center;
}
.artbook-page img { max-width: 100%; max-height: 70vh; object-fit: contain; }
.artbook-page h2 { margin: 18px 0 4px; }
.artbook-date { color: var(--ink-soft); margin: 0 0 10px; }
.artbook-cover { padding: 120px 28px; }
.artbook-cover h1 { font-size: 2.6rem; margin-bottom: 10px; }

/* Printing any page: drop the site chrome. For the art book this turns the
   preview into the book itself — a cover, then one piece per page. */
@media print {
    .site-header, .site-footer, .no-print, .flash { display: none !important; }
    body { background: #fff !important; color: #000 !important; }
    .artbook { max-width: none !important; padding: 0 !important; }
    .artbook-page {
        border: 0; border-radius: 0; margin: 0; padding: 0;
        background: #fff; color: #000;
        break-after: page; page-break-after: always;
        display: flex; flex-direction: column; justify-content: center; min-height: 95vh;
    }
    .artbook-page:last-child { break-after: auto; page-break-after: auto; }
    .artbook-page img { max-height: 78vh; }
    .artbook-date { color: #444; }
}

/* "In their words" quote (artwork page, art book, share page) */
.kid-quote {
    margin: 14px 0;
    padding: 10px 16px;
    border-left: 4px solid var(--cadmium);
    background: var(--paper-dim);
    border-radius: 0 var(--radius) var(--radius) 0;
    font-size: 1.05rem;
    font-style: italic;
}
.kid-quote footer { margin-top: 6px; font-size: 0.9rem; font-style: normal; color: var(--ink-soft); }
@media print { .kid-quote { background: none; border-left-color: #999; } }

/* ---------- Image adjustments (edit-artwork.php "Adjust images") ---------- */
.img-adjust { display: flex; gap: 14px; align-items: center; padding: 12px 0; border-top: 1px solid var(--line); }
.img-adjust:first-of-type { border-top: 0; padding-top: 0; }
.img-adjust-preview { width: 120px; height: 120px; object-fit: contain; background: var(--paper-dim); border-radius: var(--radius); flex-shrink: 0; }
.img-adjust-buttons { display: flex; flex-wrap: wrap; gap: 8px; }
.img-adjust-buttons .btn { min-height: 44px; min-width: 44px; padding: 8px 12px; justify-content: center; font-size: 1.05rem; }
.img-adjust-buttons .btn[value="enhance"], .img-adjust-buttons .btn[value="reset"] { font-size: 0.9rem; }
.img-adjust-buttons .btn[aria-pressed="true"] { background: var(--cadmium); border-color: var(--cadmium-deep); color: #211C15; }
@media (max-width: 480px) {
    .img-adjust { flex-direction: column; align-items: flex-start; }
}

/* ---------- Display frames (artworks.frame; CSS only, image untouched) ----------
   Colours are fixed rather than themed: they imitate real mats and frames,
   which look the same whatever the page theme. */
.art-frame img { display: block; max-width: 100%; height: auto; border: 0 !important; border-radius: 0 !important; }
.art-detail .art-frame img { width: 100%; }
.frame-mat {
    background: #FBFAF6;
    padding: clamp(14px, 6%, 48px);
    border: 1px solid #D9D3C4;
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.16);
}
.frame-mat img { box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.18), inset 0 0 0 1px rgba(0, 0, 0, 0.1); }
.frame-wood {
    background: #FBFAF6;
    padding: clamp(10px, 4%, 32px);
    border: clamp(10px, 2.4vw, 20px) solid #7A4B22;
    border-image: linear-gradient(135deg, #A86F38, #6E4220 30%, #9A6331 55%, #5B3518 80%, #8C5A2C) 1;
    box-shadow: 0 10px 24px rgba(0, 0, 0, 0.28), inset 0 0 0 1px rgba(0, 0, 0, 0.2);
}
.frame-wood img { box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.15); }
.frame-fridge {
    position: relative;
    background: #fff;
    padding: 6px;
    margin: 18px 8px 10px;
    transform: rotate(-1.2deg);
    box-shadow: 0 10px 20px rgba(0, 0, 0, 0.22);
}
.frame-fridge:nth-of-type(even) { transform: rotate(1deg); }
.frame-fridge::before {
    content: "";
    position: absolute;
    top: -13px;
    left: 50%;
    width: 30px;
    height: 30px;
    margin-left: -15px;
    border-radius: 50%;
    background: radial-gradient(circle at 35% 30%, #FF8A80, #D32F2F 60%, #8E1B1B);
    box-shadow: 0 3px 5px rgba(0, 0, 0, 0.35);
    z-index: 1;
}
.frame-fridge:nth-of-type(3n+2)::before { background: radial-gradient(circle at 35% 30%, #90CAF9, #1E73C8 60%, #0D3F78); }
.frame-fridge:nth-of-type(3n)::before { background: radial-gradient(circle at 35% 30%, #FFF59D, #F2B300 60%, #9A6B00); }
.artbook-page .art-frame { display: inline-block; max-width: 100%; }
.artbook-page .art-frame img { max-height: 62vh; width: auto; }

/* Frame picker on the edit page */
.frame-picker { border: 0; padding: 0; margin: 0 0 18px; }
.frame-picker legend { font-weight: 600; margin-bottom: 8px; padding: 0; }
.frame-choice { display: inline-flex; align-items: center; gap: 8px; min-height: 44px; margin: 0 16px 6px 0; font-weight: 400; cursor: pointer; }
.frame-choice input { width: auto; }
.frame-swatch { display: inline-block; width: 30px; height: 30px; background: var(--paper-dim); position: relative; flex-shrink: 0; }
.frame-swatch::after { content: ""; position: absolute; inset: 8px; background: var(--cadmium); }
.frame-swatch-none { border: 1px dashed var(--line); }
.frame-swatch-mat { background: #FBFAF6; border: 1px solid #D9D3C4; }
.frame-swatch-wood { background: #FBFAF6; border: 4px solid #7A4B22; }
.frame-swatch-wood::after { inset: 4px; }
.frame-swatch-fridge { background: #fff; transform: rotate(-4deg); box-shadow: 0 2px 4px rgba(0, 0, 0, 0.25); }
.frame-swatch-fridge::before { content: ""; position: absolute; top: -5px; left: 50%; width: 10px; height: 10px; margin-left: -5px; border-radius: 50%; background: #D32F2F; z-index: 1; }

@media print {
    .frame-mat, .frame-wood, .frame-fridge { box-shadow: none; }
    .frame-fridge { transform: none; }
    .artbook-page .art-frame img { max-height: 70vh; }
}

/* ---------- Family gallery links (children.php) ---------- */
.kid-share { margin: -6px 0 22px; padding: 14px 18px; border: 1px solid var(--line); border-top: 0; border-radius: 0 0 var(--radius) var(--radius); background: var(--surface); }
.kid-share h4 { margin: 0 0 6px; font-size: 0.95rem; }
.kid-share details > summary { list-style: none; cursor: pointer; display: inline-flex; }
.kid-share details > summary::-webkit-details-marker { display: none; }
.kid-share-form { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; margin-top: 10px; }
.kid-share-form label { display: inline-flex; align-items: center; gap: 6px; font-weight: 400; margin: 0; min-height: 44px; }
.kid-share-check input { width: auto; }
.kid-share .btn { height: 46px; padding-top: 0 !important; padding-bottom: 0 !important; align-items: center; box-sizing: border-box; }

/* ---------- Slideshow (slideshow.php, /g/...?show=1) ----------
   Always dark, whatever the site theme: it's for a TV or picture frame. */
.slideshow-body { margin: 0; background: #000; overflow: hidden; }
.slideshow { position: fixed; inset: 0; background: #000; color: #F3EEE4; font-family: var(--font-body); user-select: none; }
.slide-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; opacity: 0; transition: opacity 0.9s ease; }
.slide-img.is-visible { opacity: 1; }
.slide-top, .slide-caption, .slide-controls { position: absolute; left: 0; right: 0; transition: opacity 0.5s ease; z-index: 2; }
.slide-top { top: 0; display: flex; justify-content: space-between; align-items: center; padding: 14px 18px; background: linear-gradient(rgba(0,0,0,0.6), transparent); }
.slide-heading { font-family: var(--font-display); font-size: 1.15rem; }
.slide-exit { color: #F3EEE4; padding: 10px 14px; border: 1px solid rgba(243,238,228,0.4); border-radius: var(--radius); text-decoration: none; }
.slide-exit:hover { background: rgba(255,255,255,0.12); text-decoration: none; color: #fff; }
.slide-caption { bottom: 76px; text-align: center; padding: 0 20px; text-shadow: 0 1px 4px rgba(0,0,0,0.9); pointer-events: none; }
.slide-caption p { margin: 2px 0; color: #F3EEE4; }
.slide-caption p:empty { display: none; }
.slide-caption:has(.slide-title:not(:empty)) { background: rgba(0, 0, 0, 0.5); border-radius: var(--radius); padding: 8px 16px; left: 50%; right: auto; transform: translateX(-50%); width: max-content; max-width: calc(100% - 32px); }
.slide-title { font-family: var(--font-display); font-size: 1.35rem; }
.slide-made { font-size: 0.9rem; opacity: 0.85; }
.slide-quote { font-style: italic; max-width: 760px; margin: 6px auto 0 !important; }
.slide-controls { bottom: 0; display: flex; justify-content: center; align-items: center; flex-wrap: wrap; gap: 8px; padding: 12px; background: linear-gradient(transparent, rgba(0,0,0,0.7)); }
.slide-controls button, .slide-controls select { min-height: 44px; min-width: 44px; padding: 8px 12px; background: rgba(0,0,0,0.45); color: #F3EEE4; border: 1px solid rgba(243,238,228,0.4); border-radius: var(--radius); font: inherit; cursor: pointer; }
.slide-controls button:hover { background: rgba(255,255,255,0.15); }
.slide-controls button[aria-pressed="true"] { background: #F2A93B; border-color: #F2A93B; color: #211C15; }
.slide-controls select { width: auto; }
.slide-speed { display: inline-flex; align-items: center; gap: 6px; color: #F3EEE4; font-weight: 400; margin: 0; }
.slide-message { color: #F3EEE4; position: absolute; top: 50%; left: 0; right: 0; transform: translateY(-50%); text-align: center; font-size: 1.2rem; padding: 0 20px; z-index: 3; }
.slideshow.is-idle .slide-top, .slideshow.is-idle .slide-controls { opacity: 0; pointer-events: none; }
.slideshow.is-idle .slide-caption { opacity: 0.85; }
.slideshow.is-idle { cursor: none; }
@media (max-width: 600px) {
    .slide-caption { bottom: 120px; }
    .slide-title { font-size: 1.1rem; }
}
@media (prefers-reduced-motion: reduce) {
    .slide-img, .slide-top, .slide-caption, .slide-controls { transition: none; }
}

/* Visually hidden, still read by screen readers. */
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }

/* ---------- Bulk upload (bulk-upload.php) ---------- */
.bulk-settings { border: 0; padding: 0; margin: 0 0 6px; display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 0 18px; }
.bulk-settings[disabled] { opacity: 0.6; }
.bulk-drop { display: flex; flex-direction: column; align-items: center; gap: 6px; text-align: center; padding: 28px 16px; border: 2px dashed var(--line); border-radius: var(--radius); cursor: pointer; background: var(--paper-dim); font-weight: 400; }
.bulk-drop strong { color: var(--phthalo); }
.bulk-drop.is-over { border-color: var(--phthalo); background: var(--surface); }
.bulk-drop input[type="file"] { position: absolute; width: 1px; height: 1px; opacity: 0; }
.bulk-drop:focus-within { outline: 2px solid var(--phthalo); outline-offset: 2px; }
.bulk-list { list-style: none; padding: 0; margin: 16px 0 0; }
.bulk-item { display: flex; gap: 12px; align-items: center; padding: 10px 0; border-top: 1px solid var(--line); }
.bulk-thumb { width: 64px; height: 64px; object-fit: cover; border-radius: var(--radius); background: var(--paper-dim); flex-shrink: 0; }
.bulk-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.bulk-name { font-size: 0.8rem; color: var(--ink-soft); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bulk-body input[type="text"] { padding: 8px 10px; }
.bulk-bar { height: 5px; background: var(--paper-dim); border-radius: 999px; overflow: hidden; }
.bulk-bar-fill { height: 100%; width: 0; background: var(--phthalo); transition: width 0.2s ease; }
.bulk-item-status { font-size: 0.85rem; color: var(--ink-soft); }
.bulk-item.is-done .bulk-bar-fill { background: var(--sap); }
.bulk-item.is-failed .bulk-item-status, .bulk-item.is-invalid .bulk-item-status { color: var(--alizarin); }
.bulk-item.is-invalid { opacity: 0.75; }
.bulk-remove { min-width: 44px; min-height: 44px; padding: 0; justify-content: center; font-size: 1.3rem; }
.bulk-actions { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; justify-content: flex-end; margin-top: 16px; }
.bulk-actions p { margin: 0 auto 0 0; }
.bulk-done { margin-top: 14px; text-align: right; }
#bulk [hidden] { display: none !important; }
#bulk .btn:disabled { opacity: 0.45; cursor: default; transform: none; }

/* ---------- Hearts and notes from family links ---------- */
.family-box { margin-top: 32px; padding-top: 22px; border-top: 1px solid var(--line); }
.family-heart { display: flex; align-items: center; gap: 12px; margin-bottom: 22px; }
.family-heart .btn { min-height: 44px; }
.family-note h2 { font-size: 1.15rem; margin: 0 0 10px; }
.family-hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.family-panel { margin-top: 20px; max-width: 480px; }
.family-panel h3 { margin: 0 0 10px; font-size: 1rem; }
.family-hearts { margin: 0 0 10px; color: var(--alizarin); font-weight: 600; }
.family-note-item { padding: 10px 0; border-top: 1px solid var(--line); }
.family-note-item.is-new, .family-note-row.is-new { background: var(--paper-dim); }
.family-note-item form { margin-top: 6px; }
.family-note-meta { margin: 0 0 4px; font-size: 0.9rem; }
.family-note-body { margin: 0; white-space: normal; overflow-wrap: anywhere; }
.family-note-row { display: flex; gap: 14px; align-items: flex-start; padding: 14px 8px; border-top: 1px solid var(--line); }
.family-note-thumb img { width: 64px; height: 64px; object-fit: cover; border-radius: var(--radius); display: block; }
.family-note-main { flex: 1; min-width: 0; }
@media (max-width: 480px) { .family-note-row { flex-wrap: wrap; } }

/* ---------- On this day (index.php) ---------- */
.memories { margin-top: 30px; margin-bottom: 10px; }
.memories h2 { margin-bottom: 2px; }
.memories-row { display: flex; gap: 14px; overflow-x: auto; padding: 10px 0 6px; }
.memory { flex: 0 0 160px; display: flex; flex-direction: column; gap: 4px; color: inherit; text-decoration: none; }
.memory img { width: 160px; height: 160px; object-fit: cover; border-radius: var(--radius); border: 1px solid var(--line); }
.memory-when { font-size: 0.8rem; font-weight: 600; color: var(--alizarin); }
.memory-title { font-size: 0.9rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ---------- Year poster (poster.php) ---------- */
.poster { background: #fff; color: #211C15; padding: 28px; border: 1px solid var(--line); border-radius: var(--radius); }
.poster-head { text-align: center; margin-bottom: 18px; }
.poster-head h1 { font-size: clamp(1.8rem, 5vw, 3rem); margin: 0; color: #211C15; }
.poster-head p { margin: 4px 0 0; color: #57503F; }
.poster-grid { display: grid; gap: 6px; }
.poster-grid img { width: 100%; aspect-ratio: 1; object-fit: cover; display: block; border-radius: 3px; }

/* ---------- Then and now (compare.php) ---------- */
.compare { text-align: center; }
.compare h1 { margin-bottom: 18px; }
.compare-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; align-items: start; }
.compare figure { margin: 0; }
.compare img { width: 100%; height: auto; max-height: 70vh; object-fit: contain; border-radius: var(--radius); border: 1px solid var(--line); }
.compare-label { font-family: var(--font-display); font-size: 1.4rem; margin: 0 0 8px; }
.compare figcaption { margin-top: 8px; }
@media (max-width: 600px) { .compare-grid { grid-template-columns: 1fr; } }

/* ---------- Kid followers (child.php) ---------- */
.child-followers { margin: 0 0 24px; }
.child-followers summary { cursor: pointer; font-weight: 600; min-height: 44px; display: flex; align-items: center; }
.child-followers ul { list-style: none; padding: 0; margin: 10px 0 0; }
.child-followers li { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; padding: 6px 0; border-top: 1px solid var(--line); }

@media print {
    .poster { border: 0; padding: 0; }
    .poster-grid { gap: 4px; }
    .compare-grid { grid-template-columns: 1fr 1fr; }
    .compare img { max-height: 80vh; border: 0; }
}

/* On-page confirmation (assets/js/site.js) */
.confirm-step { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 8px; padding: 6px 10px; border: 1px solid var(--alizarin); border-radius: var(--radius); background: var(--surface); }
.confirm-msg { font-size: 0.9rem; color: var(--ink); max-width: 36em; }
.confirm-step .btn { min-height: 40px; }

/* ---------- Straighten (straighten.php) ---------- */
.straighten-stage { position: relative; display: inline-block; max-width: 100%; touch-action: none; user-select: none; -webkit-user-select: none; line-height: 0; }
.straighten-stage img { display: block; max-width: 100%; max-height: 72vh; width: auto; height: auto; border-radius: var(--radius); }
.straighten-overlay { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
.straighten-shade { fill: rgba(0, 0, 0, 0.45); }
.straighten-outline { fill: none; stroke: #F2A93B; stroke-width: 3; vector-effect: non-scaling-stroke; }
.straighten.is-invalid .straighten-outline { stroke: #D32F2F; stroke-dasharray: 8 6; }
.straighten-handle {
    position: absolute; width: 44px; height: 44px; margin: -22px 0 0 -22px; padding: 0; border: 0; border-radius: 50%;
    background: transparent; cursor: grab; touch-action: none;
}
.straighten-handle::after {
    content: ""; position: absolute; inset: 11px; border-radius: 50%;
    background: #fff; border: 3px solid #F2A93B; box-shadow: 0 1px 4px rgba(0, 0, 0, 0.5);
}
.straighten-handle:focus-visible::after, .straighten-handle.is-dragging::after { border-color: #1C5D6B; background: #FCEFD9; }
.straighten-handle.is-dragging { cursor: grabbing; }
.straighten-actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 16px; }
.straighten-actions .btn:disabled { opacity: 0.45; cursor: default; }
.straighten-hint { margin: 16px 0 0; padding: 10px 14px; background: var(--notice-bg); color: var(--notice-text); border-radius: var(--radius); font-size: 0.95rem; }
.img-adjust-buttons .btn.is-on { background: var(--cadmium); border-color: var(--cadmium-deep); color: #211C15; }
.straighten-hint.is-done { display: inline-block; padding: 6px 12px; font-size: 0.9rem; }
.icon-straighten { vertical-align: -2px; margin-right: 4px; flex-shrink: 0; }
.straighten-paper { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; flex-basis: 100%; }
.straighten-paper label { font-weight: 600; }
.straighten-paper select { min-height: 44px; max-width: 100%; }
.straighten-paper-note { margin: 0; flex-basis: 100%; }

/* "⋯" menus (messages, comments): a small icon with a 44px tap area. The
   ::before overlay enlarges the hit area without taking up layout space. */
.more-menu { position: relative; display: inline-block; }
.more-menu > summary, .more-item-details > summary { list-style: none; }
.more-menu > summary::-webkit-details-marker, .more-item-details > summary::-webkit-details-marker { display: none; }
.more-btn { position: relative; display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 24px; border-radius: 6px; color: var(--ink-soft); cursor: pointer; }
.more-btn::before { content: ''; position: absolute; top: -10px; bottom: -10px; left: -8px; right: -8px; }
.more-btn:hover, .more-btn:focus-visible, .more-menu[open] > .more-btn { color: var(--ink); background: var(--paper-dim); }
.more-btn:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
.more-btn-subtle { opacity: 0.5; transition: opacity 0.15s; }
.more-btn-subtle:hover, .more-btn-subtle:focus-visible, .more-menu[open] > .more-btn-subtle { opacity: 1; }
@media (hover: none) { .more-btn-subtle { opacity: 0.7; } }
.more-menu-panel { position: absolute; z-index: 40; top: calc(100% + 6px); left: 0; width: max-content; min-width: 210px; max-width: min(320px, calc(100vw - 32px)); padding: 6px; background: var(--popover-bg); border: 1px solid var(--popover-border); border-radius: var(--radius); box-shadow: var(--popover-shadow); }
.more-item { display: flex; align-items: center; width: 100%; min-height: 44px; padding: 8px 12px; background: none; border: 0; border-radius: 6px; font: inherit; font-size: 0.95rem; color: var(--ink); text-align: left; cursor: pointer; }
.more-item:hover, .more-item:focus-visible, .more-item-details[open] > .more-item { background: var(--popover-hover); }
.more-form { padding: 8px 6px 6px; }
.more-form .field { margin-bottom: 8px; }
.more-form textarea { width: 100%; }
.report-notice { margin: 0 0 10px; padding: 8px 10px; background: var(--notice-bg); color: var(--notice-text); border-radius: 6px; font-size: 0.88rem; }
.thread-header { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.thread-header .more-menu-panel { left: auto; right: 0; }
.thread-header h1 { min-width: 0; overflow-wrap: anywhere; }
.msg-more { margin-top: 4px; }
.comment-actions { display: flex; align-items: center; gap: 14px; margin-top: 4px; min-height: 28px; }
/* Quiet text button with a 44px-tall tap area. */
.text-action { position: relative; padding: 2px 4px; background: none; border: 0; font: inherit; font-size: 0.85rem; font-weight: 600; color: var(--ink-soft); cursor: pointer; }
.text-action::before { content: ''; position: absolute; top: -10px; bottom: -10px; left: -6px; right: -6px; }
.text-action:hover, .text-action:focus-visible { color: var(--ink); text-decoration: underline; }

/* Admin: reported-conversation copy. */
.notice-box { padding: 10px 14px; background: var(--notice-bg); color: var(--notice-text); border-radius: var(--radius); font-size: 0.92rem; }
.snapshot-thread { display: flex; flex-direction: column; gap: 10px; }
.snapshot-msg { max-width: 80%; padding: 8px 12px; border-radius: 12px; background: var(--paper-dim); }
.snapshot-msg.is-reporter { align-self: flex-end; border: 1px solid var(--line); background: var(--paper); }
.snapshot-msg p { margin: 0; color: var(--ink); overflow-wrap: anywhere; }
.snapshot-msg .snapshot-meta { font-size: 0.75rem; color: var(--ink-soft); margin-bottom: 2px; }

/* Search: page, tabs, sort, people, type-ahead (search.php, assets/js/search-suggest.js). */
.search-page-form { display: flex; gap: 8px; max-width: 640px; }
.search-page-form input[type="search"] { flex: 1; min-width: 0; }
.search-section-title { font-size: 1.1rem; margin: 26px 0 12px; }
.search-tabs { display: flex; flex-wrap: wrap; gap: 8px; margin: 6px 0 16px; }
.search-tabs .btn { min-height: 44px; }
.search-tab-count { opacity: 0.75; font-weight: 400; margin-left: 4px; }
.search-sort { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 14px; margin: 0 0 14px; font-size: 0.92rem; }
.search-sort a { display: inline-flex; align-items: center; min-height: 44px; color: var(--ink-soft); }
.search-sort a.is-current { color: var(--ink); font-weight: 700; text-decoration: underline; text-underline-offset: 4px; }
.search-dym { font-size: 1.05rem; margin: 6px 0 18px; }
.search-pages { display: flex; align-items: center; justify-content: center; gap: 14px; margin-top: 24px; }
.search-people { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 10px; }
.search-person { display: flex; align-items: center; gap: 12px; min-height: 44px; padding: 10px 12px; border: 1px solid var(--line); border-radius: var(--radius); color: var(--ink); }
.search-person:hover, .search-person:focus-visible { background: var(--paper-dim); }
.tag-count { opacity: 0.7; font-size: 0.85em; }
.kid-search-optin { margin: 4px 0 6px; font-size: 0.9rem; }
.kid-search-optin label { display: inline-flex; align-items: center; gap: 8px; min-height: 44px; cursor: pointer; }
.suggest-host { position: relative; }
.suggest-list { position: absolute; z-index: 60; top: calc(100% + 4px); left: 0; right: 0; min-width: 240px; max-height: 60vh; overflow-y: auto; margin: 0; padding: 6px; list-style: none; background: var(--popover-bg); border: 1px solid var(--popover-border); border-radius: var(--radius); box-shadow: var(--popover-shadow); }
.suggest-item { display: flex; flex-direction: column; justify-content: center; min-height: 44px; padding: 6px 10px; border-radius: 6px; cursor: pointer; }
.suggest-item[aria-selected="true"], .suggest-item:hover { background: var(--popover-hover); }
.suggest-label { color: var(--ink); font-weight: 600; overflow-wrap: anywhere; }
.suggest-detail { color: var(--ink-soft); font-size: 0.8rem; }

/* Picture descriptions (alt text): edit-artwork.php fields, artwork.php owner nudge. */
.alt-fields { border: 1px solid var(--line); border-radius: var(--radius); padding: 12px 14px 4px; margin: 0 0 18px; }
.alt-fields legend { font-weight: 700; padding: 0 6px; }
.alt-field { display: flex; gap: 12px; align-items: flex-start; margin-bottom: 12px; }
.alt-field-thumb { width: 64px; height: 64px; object-fit: cover; border-radius: 6px; flex-shrink: 0; }
.alt-field-input { flex: 1; min-width: 0; }
.alt-field-input label { display: block; font-size: 0.85rem; font-weight: 600; margin-bottom: 4px; }
.alt-field-input textarea { width: 100%; }
@media (max-width: 480px) { .alt-field-thumb { width: 48px; height: 48px; } }
.alt-nudge { margin: 14px 0 0; padding: 10px 14px; background: var(--notice-bg); color: var(--notice-text); border-radius: var(--radius); font-size: 0.92rem; }
.alt-nudge a { font-weight: 700; color: inherit; text-decoration: underline; }
.alt-nudge .help-text { display: block; color: inherit; opacity: 0.85; margin-top: 2px; }

/* Full-screen viewer (assets/js/viewer.js). The picture buttons look like the
   pictures did; the viewer is a fixed dark layer with 48px controls. */
.viewer-open { display: block; width: 100%; padding: 0; margin: 0; border: 0; background: none; cursor: zoom-in; border-radius: var(--radius); font: inherit; color: inherit; }
.viewer-open:focus-visible { outline: 3px solid var(--cadmium); outline-offset: 3px; }
html.viewer-lock, html.viewer-lock body { overflow: hidden; }
.viewer { position: fixed; inset: 0; z-index: 1000; display: flex; flex-direction: column; background: #0D0B09; color: #F3EEE6; }
.viewer-stage { position: relative; flex: 1; min-height: 0; display: flex; align-items: center; justify-content: center; overflow: hidden; touch-action: none; }
.viewer-img { display: block; max-width: 100%; max-height: 100%; object-fit: contain; transform-origin: center center; user-select: none; -webkit-user-select: none; -webkit-user-drag: none; }
.viewer.is-zoomed .viewer-stage { cursor: grab; }
.viewer-btn { position: absolute; z-index: 2; display: flex; align-items: center; justify-content: center; min-width: 48px; min-height: 48px; padding: 0; border: 0; border-radius: 999px; background: rgba(0, 0, 0, 0.55); color: #FFFFFF; font-size: 1.6rem; line-height: 1; cursor: pointer; }
.viewer-btn:hover { background: rgba(0, 0, 0, 0.75); }
.viewer-btn:focus-visible { outline: 3px solid #F5B754; outline-offset: 2px; }
.viewer-close { top: max(10px, env(safe-area-inset-top)); right: max(10px, env(safe-area-inset-right)); }
.viewer-prev { left: max(10px, env(safe-area-inset-left)); top: 50%; transform: translateY(-50%); font-size: 2.2rem; }
.viewer-next { right: max(10px, env(safe-area-inset-right)); top: 50%; transform: translateY(-50%); font-size: 2.2rem; }
.viewer-caption { padding: 10px 16px calc(12px + env(safe-area-inset-bottom)); background: rgba(0, 0, 0, 0.6); max-height: 30vh; overflow: auto; }
.viewer-caption p { margin: 0; }
.viewer .viewer-title { color: #F3EEE6; font-weight: 700; }
.viewer .viewer-desc { color: #D9D1C4; font-size: 0.92rem; margin-top: 4px; }
.viewer .viewer-link { display: inline-flex; align-items: center; min-height: 44px; color: #F5B754; }
@media (prefers-reduced-motion: reduce) { .viewer-img { transition: none !important; } }

/* Add to home screen (install.php): no tip inside the installed app itself. */
@media (display-mode: standalone) { .install-tip, .install-steps { display: none !important; } }
.install-standalone { display: none; }
@media (display-mode: standalone) { .install-standalone { display: block; } }
.install-steps h2 { font-size: 1.15rem; margin: 22px 0 8px; }
.install-steps ol { padding-left: 22px; }
.install-steps li { margin: 6px 0; }

/* Multi-picture pieces (render_piece_pictures(), assets/js/piece-gallery.js).
   Without JavaScript the slides simply stack; .is-enhanced is the carousel. */
.viewer-gallery, .piece-gallery { min-width: 0; max-width: 100%; }
.piece-slide + .piece-slide { margin-top: 14px; }
.piece-slide + .piece-slide > .art-frame { margin-top: 8px; }
.piece-gallery.is-enhanced .piece-slide + .piece-slide { margin-top: 0; }
/* With JavaScript, pictures 2+ stay out of the layout until piece-gallery.js
   takes over, so the browser's lazy-load look-ahead doesn't fetch them
   (html.js comes from js-flag.js in <head>; .gallery-fallback undoes this if
   the gallery script never ran). Without JavaScript they stack as before. */
.js:not(.gallery-fallback) .piece-gallery:not(.is-enhanced) .piece-slide + .piece-slide { display: none; }
.piece-stage { position: relative; touch-action: pan-y; }
.piece-nav { position: absolute; z-index: 2; top: 50%; transform: translateY(-50%); display: flex; align-items: center; justify-content: center; width: 44px; height: 44px; padding: 0; border: 0; border-radius: 999px; background: rgba(0, 0, 0, 0.62); color: #FFFFFF; font-size: 1.7rem; line-height: 1; cursor: pointer; }
.piece-prev { left: 8px; }
.piece-next { right: 8px; }
.piece-nav:hover:not(:disabled) { background: rgba(0, 0, 0, 0.8); }
.piece-nav:disabled { opacity: 0.35; cursor: default; }
.piece-nav:focus-visible { outline: 3px solid #F5B754; outline-offset: 2px; }
.piece-counter { position: absolute; z-index: 2; top: 8px; left: 8px; padding: 3px 10px; border-radius: 999px; background: rgba(0, 0, 0, 0.68); color: #FFFFFF; font-size: 0.8rem; font-weight: 600; pointer-events: none; }
.piece-thumbs { display: flex; gap: 8px; margin-top: 10px; padding: 4px 2px 6px; max-width: 100%; overflow-x: auto; overscroll-behavior-x: contain; scrollbar-width: thin; }
.piece-thumb { flex: 0 0 auto; width: 64px; height: 64px; padding: 0; border: 2px solid transparent; border-radius: 8px; background: var(--paper-dim); cursor: pointer; overflow: hidden; }
.piece-thumb img { display: block; width: 100%; height: 100%; object-fit: cover; border: 0 !important; border-radius: 6px !important; }
.piece-thumb[aria-current="true"] { border-color: var(--ink); }
.piece-thumb:focus-visible { outline: 3px solid var(--cadmium); outline-offset: 2px; }
.piece-fullsize { margin: 6px 0 0; }
@media (max-width: 480px) { .piece-thumb { width: 56px; height: 56px; } }

/* "N pictures" badge on grid cards: readable on any picture. */
.count-badge { position: absolute; z-index: 1; top: 8px; right: 8px; display: inline-flex; align-items: center; gap: 4px; padding: 3px 9px 3px 7px; border-radius: 999px; background: rgba(0, 0, 0, 0.72); color: #FFFFFF; font-size: 13px; font-weight: 600; line-height: 1.25; pointer-events: none; }
.count-badge svg { flex-shrink: 0; }

/* Admin moderation access: blurred preview + request form, banner, 403 page. */
.mod-preview { display: flex; align-items: flex-start; gap: 10px; flex-wrap: wrap; }
.mod-tile { position: relative; display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; overflow: hidden; border-radius: 4px; background: var(--paper-dim); }
.mod-tile img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; border: 0 !important; border-radius: 0 !important; }
.mod-lock { position: relative; z-index: 1; color: #FFFFFF; filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.7)); }
.mod-request > summary { list-style: none; min-height: 44px; display: inline-flex; align-items: center; }
.mod-request > summary::-webkit-details-marker { display: none; }
.mod-form { margin-top: 10px; max-width: 320px; }
.mod-form textarea, .mod-form select { width: 100%; }
.mod-banner { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px; margin: 18px 0 0; padding: 10px 14px; border-radius: var(--radius); background: var(--notice-bg); color: var(--notice-text); border: 1px solid var(--popover-border); }
.mod-banner p { margin: 0; color: inherit; }
.mod-403 { max-width: 420px; margin: 18px auto 0; text-align: left; }
.mod-log { display: flex; flex-direction: column; gap: 10px; }
/* Moderation hide: the banner on a hidden piece (owner and admin versions),
   and the Hide / Unhide / Keep hidden controls in admin lists. */
.hidden-banner { margin: 18px 0 0; padding: 12px 14px; border-radius: var(--radius); background: var(--notice-bg); color: var(--notice-text); border: 1px solid var(--popover-border); }
.hidden-banner p { margin: 0 0 6px; color: inherit; }
.hidden-banner .help-text { color: inherit; opacity: 0.9; }
.hidden-banner > :last-child { margin-bottom: 0; }
.hidden-banner-actions, .admin-art-actions { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 8px; }
.hidden-banner-actions { margin-top: 8px; }
.admin-hide-panel { margin-top: 20px; padding-top: 14px; border-top: 1px solid var(--line); }
.art-card-unavailable { min-height: 120px; display: flex; align-items: flex-end; background: var(--paper-dim); }
.art-card-unavailable .art-title { color: var(--ink-soft); font-style: italic; }

/* ---------- Stats (stats.php, the artwork page's owner panel) ---------- */
.stats-totals { list-style: none; padding: 0; margin: 0 0 12px; display: flex; flex-wrap: wrap; gap: 8px 18px; }
.stats-totals li { color: var(--ink-soft); }
.stats-totals strong { color: var(--ink); font-size: 1.15rem; }
.stats-totals-big { display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: 10px; }
.stats-totals-big li { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: 12px 14px; }
.stats-totals-big strong { display: block; font-size: 1.6rem; line-height: 1.2; }
.stats-section { margin-top: 20px; }
.stats-section h2 { font-size: 1.25rem; margin: 0 0 12px; }
.stats-subhead { font-size: 1rem; margin: 18px 0 8px; }
.stats-tabs { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 14px; }
.stats-chart { margin: 0; }
.stats-chart figcaption { margin-bottom: 8px; }
.stats-chart figcaption .help-text { display: block; margin-top: 2px; }
.stats-plot { position: relative; padding-top: 18px; }
.stats-max { position: absolute; top: 0; left: 0; font-size: 0.75rem; color: var(--ink-soft); }
.stats-svg { display: block; width: 100%; height: 140px; }
.stats-svg rect { fill: var(--alizarin); }
.stats-svg .stats-axis { stroke: var(--line); stroke-width: 2; }
.stats-xlabels { display: flex; justify-content: space-between; gap: 8px; font-size: 0.75rem; color: var(--ink-soft); margin-top: 4px; }
.stats-table-wrap { margin-top: 8px; }
.stats-table-wrap > summary { cursor: pointer; font-size: 0.85rem; color: var(--ink-soft); min-height: 44px; display: inline-flex; align-items: center; }
.stats-table-wrap { overflow-x: auto; }
.stats-table { width: 100%; border-collapse: collapse; font-size: 0.85rem; margin: 6px 0 12px; }
.stats-table caption { text-align: left; font-weight: 600; padding: 6px 0; }
.stats-table th, .stats-table td { text-align: left; padding: 6px 8px; border-bottom: 1px solid var(--line); vertical-align: top; }
.stats-table td { font-variant-numeric: tabular-nums; }
.stats-sources, .stats-top { list-style: none; padding: 0; margin: 0; }
.stats-sources li, .stats-top li { display: flex; justify-content: space-between; align-items: center; gap: 10px; padding: 6px 0; border-bottom: 1px solid var(--line); }
.stats-top a { display: flex; align-items: center; gap: 10px; min-width: 0; color: inherit; }
.stats-top a span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.stats-top img { width: 40px; height: 40px; object-fit: cover; border-radius: 4px; flex-shrink: 0; }
.stats-tags { list-style: none; padding: 0; margin: 0; display: flex; flex-wrap: wrap; gap: 8px 12px; }
.stats-columns { display: grid; grid-template-columns: 1fr; gap: 0 20px; }
@media (min-width: 760px) { .stats-columns { grid-template-columns: 1fr 1fr; } }
.stats-panel { margin-top: 20px; }
.stats-panel > summary { cursor: pointer; font-weight: 600; min-height: 44px; display: flex; align-items: center; flex-wrap: wrap; gap: 6px; }
.stats-panel[open] > summary { margin-bottom: 10px; }
