/* ============================================================================
   Photos by Neuphlo — design system
   Plain CSS, custom properties, no build step.

   Derived from docs/neuphlo-design-language.md (neuphlo.com @ 6900c40).
   Adopts the Neuphlo palette, the layered elevation scale, the 0.5px hairline
   + ring-shadow surface treatment, the 14px radius scale, the mono eyebrow and
   the motion system, in full.

   Three themes:
     :root                      light   (marketing, admin, sign-in)
     .dark / [data-theme=dark]  dark    (marketing, admin, sign-in)
     .theme-stage               stage   (guest gallery — always on, darker than
                                         dark so photographs carry the page)

   Contents
     01  fonts
     02  tokens
     03  reset and base
     04  focus
     05  layout: container, section, dividers
     06  surfaces: panels
     07  type roles
     08  buttons
     09  fields
     10  pills, dots, meta
     11  navigation and footer
     12  photo primitives: grid, tile, day rule
     13  action bar (dock)
     14  upload sheet and progress
     15  lightbox
     16  dialogs and sheets
     17  share and QR
     18  states: empty, loading, error, notice
     19  motion
     20  reduced motion
     21  scrollbars
     22  utilities
   ========================================================================== */


/* == 01  fonts ==============================================================
   neuphlo.com self-hosts these via Fontsource (npm). This app has no bundler,
   so they come from Google Fonts. Before production, vendor the woff2 files
   locally and delete this import — a third-party font CDN is a render-blocking
   round trip on the exact bad-wifi connection the gallery is designed for.
   Geist Mono is the highest-signal face of the three; host that one first. */

@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/fonts/inter-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: "Inter";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/fonts/inter-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-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "Geist";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/fonts/geist-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: "Geist";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/fonts/geist-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-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "Geist Mono";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/fonts/geist-mono-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: "Geist Mono";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/fonts/geist-mono-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-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}


/* == 02  tokens ============================================================= */

:root {
  /* -- dark palette source. Never reference these directly; the two mapping
        blocks below alias them onto the live token names. Written once so the
        dark theme cannot drift between the OS-preference path and the
        explicit-class path. -- */
  --dk-panel-1: #252524;
  --dk-panel-2: #2A2A29;
  --dk-panel-3: #31302F;
  --dk-panel-line: rgba(255, 255, 255, 0.07);
  --dk-panel-ring: 0 0 0 1px rgba(0, 0, 0, 0.25);
  --dk-section-tint: rgba(255, 255, 255, 0.022);

  --dk-brand-text: #2BD4C3;
  --dk-brand-graphic: #2BD4C3;

  --dk-notice-soft: #2A1C10;
  --dk-notice-soft-border: #5A3A12;
  --dk-notice-text: #FF9A3C;

  --dk-ok: #22C55E;
  --dk-ok-text: #4ADE80;

  --dk-background: #1F1F1E;
  --dk-foreground: #E1E1E1;
  --dk-card: #262626;
  --dk-popover: #2D2D2D;
  --dk-primary: #E1E1E1;
  --dk-primary-foreground: #1F1F1E;
  --dk-secondary: #262626;
  --dk-muted: #262626;
  --dk-accent: #2E2E2D;
  --dk-muted-foreground: #989898;
  --dk-text-tertiary: #8A8A8A;
  --dk-border: #333333;
  --dk-input-line: #808080;
  --dk-ring: #767676;
  --dk-ring-strong: #A1A1A1;
  --dk-destructive: #FF6467;
  --dk-destructive-foreground: #1F1F1E;
  --dk-destructive-text: #FF6467;

  --dk-photo-bg: #3A3A38;
  --dk-scrim: rgba(0, 0, 0, 0.78);

  --dk-ambient-tint: rgba(255, 255, 255, 0.05);
  --dk-ambient-blend: lighten;
  --dk-streak-tint: rgba(255, 255, 255, 0.75);

  --dk-sb-track: #171717;
  --dk-sb-thumb: #737373;
  --dk-sb-thumb-hover: #A1A1A1;

  /* -- live tokens: light -- */

  /* elevation. Warm neutrals, not grey. Lighter as it comes forward. */
  --panel-1: #F4F4F3;
  --panel-2: #FBFBFA;
  --panel-3: #FFFFFF;
  --panel-line: rgba(0, 0, 0, 0.08);
  --panel-ring: 0 0 0 1px rgba(0, 0, 0, 0.10);
  --section-tint: rgba(0, 0, 0, 0.035);

  /* brand. --brand fills, --brand-text types, --brand-graphic draws meaningful
     non-text marks (progress fills, live dots) that need 3:1 on their own. */
  --brand: #12B5A6;
  --brand-foreground: #08201E;
  --brand-text: #0E7D72;
  --brand-active: #0E9384;
  --brand-graphic: #0E7D72;

  /* notice. Structural port of Neuphlo's --agent-live: same one-hue,
     fill + text + soft-fill shape, repurposed for gallery expiry. */
  --notice: #FF7A00;
  --notice-foreground: #231400;
  --notice-soft: #FFF1E3;
  --notice-soft-border: #F5C99B;
  --notice-text: #9C4200;

  /* ok. Live connection, upload complete. */
  --ok: #16A34A;
  --ok-text: #15803D;

  /* neutrals */
  --background: #FFFFFF;
  --foreground: #0A0A0A;
  --card: #FFFFFF;
  --popover: #FFFFFF;
  --primary: #171717;
  --primary-foreground: #FAFAFA;
  --secondary: #F5F5F5;
  --muted: #F5F5F5;
  --accent: #EEEEEE;
  --muted-foreground: #6B6B6B;
  --text-tertiary: #525252;
  --border: #E5E5E5;
  --input-line: #8A8A8A;
  --ring: #A1A1A1;
  --ring-strong: #525252;
  --destructive: #E7000B;
  --destructive-foreground: #FFFFFF;
  --destructive-text: #E7000B;

  /* photo */
  --photo-bg: #EDEDEB;
  --scrim: rgba(10, 10, 10, 0.72);

  /* atmosphere */
  --ambient-tint: rgba(18, 181, 166, 0.07);
  --ambient-blend: normal;
  --streak-tint: rgba(18, 181, 166, 0.5);

  /* scrollbars */
  --sb-track: #F5F5F5;
  --sb-thumb: #A1A1A1;
  --sb-thumb-hover: #737373;

  /* geometry */
  --radius: 16px;
  --radius-sm: 12px;
  --radius-md: 14px;
  --radius-lg: 16px;
  --radius-xl: 20px;
  --radius-panel-recessed: 12px;
  --radius-panel-elevated: 10px;
  --radius-panel-row: 8px;

  /* type */
  --font-sans: "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI",
    Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif;
  --font-display: "Geist", "Inter", ui-sans-serif, system-ui, -apple-system,
    "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-mono: "Geist Mono", ui-monospace, "SF Mono", Menlo, Monaco, Consolas,
    "Liberation Mono", "Courier New", monospace;

  /* motion */
  --fx-ease: cubic-bezier(0.22, 0.61, 0.36, 1);

  /* chrome geometry, gallery */
  --dock-h: 68px;
  --safe-b: env(safe-area-inset-bottom, 0px);
  --safe-t: env(safe-area-inset-top, 0px);
  --safe-l: env(safe-area-inset-left, 0px);
  --safe-r: env(safe-area-inset-right, 0px);
  --tile-gap: 3px;

  color-scheme: light;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]):not([data-theme="stage"]) {
    --panel-1: var(--dk-panel-1);
    --panel-2: var(--dk-panel-2);
    --panel-3: var(--dk-panel-3);
    --panel-line: var(--dk-panel-line);
    --panel-ring: var(--dk-panel-ring);
    --section-tint: var(--dk-section-tint);
    --brand-text: var(--dk-brand-text);
    --brand-graphic: var(--dk-brand-graphic);
    --notice-soft: var(--dk-notice-soft);
    --notice-soft-border: var(--dk-notice-soft-border);
    --notice-text: var(--dk-notice-text);
    --ok: var(--dk-ok);
    --ok-text: var(--dk-ok-text);
    --background: var(--dk-background);
    --foreground: var(--dk-foreground);
    --card: var(--dk-card);
    --popover: var(--dk-popover);
    --primary: var(--dk-primary);
    --primary-foreground: var(--dk-primary-foreground);
    --secondary: var(--dk-secondary);
    --muted: var(--dk-muted);
    --accent: var(--dk-accent);
    --muted-foreground: var(--dk-muted-foreground);
    --text-tertiary: var(--dk-text-tertiary);
    --border: var(--dk-border);
    --input-line: var(--dk-input-line);
    --ring: var(--dk-ring);
    --ring-strong: var(--dk-ring-strong);
    --destructive: var(--dk-destructive);
    --destructive-foreground: var(--dk-destructive-foreground);
    --destructive-text: var(--dk-destructive-text);
    --photo-bg: var(--dk-photo-bg);
    --scrim: var(--dk-scrim);
    --ambient-tint: var(--dk-ambient-tint);
    --ambient-blend: var(--dk-ambient-blend);
    --streak-tint: var(--dk-streak-tint);
    --sb-track: var(--dk-sb-track);
    --sb-thumb: var(--dk-sb-thumb);
    --sb-thumb-hover: var(--dk-sb-thumb-hover);
    color-scheme: dark;
  }
}

:root[data-theme="dark"],
.dark {
  --panel-1: var(--dk-panel-1);
  --panel-2: var(--dk-panel-2);
  --panel-3: var(--dk-panel-3);
  --panel-line: var(--dk-panel-line);
  --panel-ring: var(--dk-panel-ring);
  --section-tint: var(--dk-section-tint);
  --brand-text: var(--dk-brand-text);
  --brand-graphic: var(--dk-brand-graphic);
  --notice-soft: var(--dk-notice-soft);
  --notice-soft-border: var(--dk-notice-soft-border);
  --notice-text: var(--dk-notice-text);
  --ok: var(--dk-ok);
  --ok-text: var(--dk-ok-text);
  --background: var(--dk-background);
  --foreground: var(--dk-foreground);
  --card: var(--dk-card);
  --popover: var(--dk-popover);
  --primary: var(--dk-primary);
  --primary-foreground: var(--dk-primary-foreground);
  --secondary: var(--dk-secondary);
  --muted: var(--dk-muted);
  --accent: var(--dk-accent);
  --muted-foreground: var(--dk-muted-foreground);
  --text-tertiary: var(--dk-text-tertiary);
  --border: var(--dk-border);
  --input-line: var(--dk-input-line);
  --ring: var(--dk-ring);
  --ring-strong: var(--dk-ring-strong);
  --destructive: var(--dk-destructive);
  --destructive-foreground: var(--dk-destructive-foreground);
  --destructive-text: var(--dk-destructive-text);
  --photo-bg: var(--dk-photo-bg);
  --scrim: var(--dk-scrim);
  --ambient-tint: var(--dk-ambient-tint);
  --ambient-blend: var(--dk-ambient-blend);
  --streak-tint: var(--dk-streak-tint);
  --sb-track: var(--dk-sb-track);
  --sb-thumb: var(--dk-sb-thumb);
  --sb-thumb-hover: var(--dk-sb-thumb-hover);
  color-scheme: dark;
}

/* -- stage: the guest gallery ground.
   One step recessive of dark mode. Photographs are the brightest thing on the
   page and every piece of chrome sits under them. Same warm neutral cast and
   the same forward-is-lighter rule as the other two themes, so it reads as the
   same product. Not preference-driven: the gallery is always this. -- */
:root[data-theme="stage"],
.theme-stage {
  --panel-1: #1A1A19;
  --panel-2: #1F1F1E;
  --panel-3: #262625;
  --panel-line: rgba(255, 255, 255, 0.08);
  --panel-ring: 0 0 0 1px rgba(0, 0, 0, 0.40);
  --section-tint: rgba(255, 255, 255, 0.02);

  --brand: #12B5A6;
  --brand-foreground: #08201E;
  --brand-text: #2BD4C3;
  --brand-active: #0E9384;
  --brand-graphic: #2BD4C3;

  --notice: #FF7A00;
  --notice-foreground: #231400;
  --notice-soft: #231703;
  --notice-soft-border: #5A3A12;
  --notice-text: #FF9A3C;

  --ok: #22C55E;
  --ok-text: #4ADE80;

  --background: #121211;
  --foreground: #EDEDEB;
  --card: #1A1A19;
  --popover: #262625;
  --primary: #EDEDEB;
  --primary-foreground: #121211;
  --secondary: #1F1F1E;
  --muted: #1F1F1E;
  --accent: #262625;
  --muted-foreground: #9A9A98;
  --text-tertiary: #7A7A78;
  --border: #333331;
  --input-line: #7A7A78;
  --ring: #6E6E6C;
  --ring-strong: #B4B4B1;
  --destructive: #FF6467;
  --destructive-foreground: #121211;
  --destructive-text: #FF8A8C;

  --photo-bg: #232322;
  --scrim: rgba(6, 6, 5, 0.97);

  --ambient-tint: rgba(18, 181, 166, 0.05);
  --ambient-blend: lighten;
  --streak-tint: rgba(255, 255, 255, 0.40);

  --sb-track: #121211;
  --sb-thumb: #4A4A48;
  --sb-thumb-hover: #6E6E6C;

  color-scheme: dark;
}


/* == 03  reset and base ===================================================== */

*,
*::before,
*::after {
  box-sizing: border-box;
  border-color: var(--border);
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--background);
  color: var(--foreground);
  font-family: var(--font-sans);
  font-size: 16px;
  line-height: 1.625;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overscroll-behavior-y: none;
}

[hidden] { display: none !important; }

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

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

button, input, select, textarea { font: inherit; color: inherit; }

hr { border: 0; margin: 0; }

::selection {
  background: color-mix(in oklab, var(--brand) 30%, transparent);
  color: var(--foreground);
}

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  left: 12px; top: -100px;
  z-index: 200;
  padding: 10px 16px;
  border-radius: var(--radius-md);
  background: var(--brand);
  color: var(--brand-foreground);
  font-size: 14px;
  font-weight: 500;
  transition: top 150ms var(--fx-ease);
}
.skip-link:focus-visible { top: calc(12px + var(--safe-t)); }


/* == 04  focus ==============================================================
   Neuphlo's ring is a soft 3px glow at 50% of --ring. That glow alone does not
   reach 3:1 against every surface in every theme, so a solid 2px --ring-strong
   outline carries the requirement and the glow stays as the house look.
   Verified: --ring-strong reaches 7.10:1 (light), 5.10:1 (dark), 7.29:1 (stage)
   against the least favourable panel in its theme. */

:focus-visible {
  outline: 2px solid var(--ring-strong);
  outline-offset: 2px;
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--ring) 50%, transparent);
}
.btn--brand:focus-visible,
.btn--dock:focus-visible {
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--brand) 40%, transparent);
}


/* == 05  layout ============================================================= */

.container {
  max-width: 1200px;
  margin-inline: auto;
  padding-inline: 24px;
}
.container--narrow { max-width: 880px; }

.section { padding-block: 64px; }
@media (min-width: 1024px) { .section { padding-block: 80px; } }

.section--hero { padding-block: 128px 80px; position: relative; overflow: hidden; }
@media (min-width: 640px)  { .section--hero { padding-block: 144px 80px; } }
@media (min-width: 1024px) { .section--hero { padding-block: 160px 96px; } }

.section-tint {
  position: relative;
  background-image: linear-gradient(to bottom,
    rgba(0, 0, 0, 0) 0%, var(--section-tint) 14%,
    var(--section-tint) 86%, rgba(0, 0, 0, 0) 100%);
}

.hairline {
  position: relative;
  overflow: hidden;
  height: 1px;
  border: 0;
  background: linear-gradient(to right,
    rgba(0, 0, 0, 0) 0%, var(--border) 18%, var(--border) 82%, rgba(0, 0, 0, 0) 100%);
}
.hairline::after {
  content: "";
  position: absolute;
  inset-block: 0;
  left: 0;
  width: 190px;
  border-radius: 999px;
  background: linear-gradient(90deg,
    rgba(0, 0, 0, 0) 0%, var(--streak-tint) 50%, rgba(0, 0, 0, 0) 100%);
  opacity: 0;
  animation: line-charge var(--charge-duration, 17s) linear infinite;
  animation-delay: var(--charge-delay, 0s);
}
.hairline:nth-of-type(3n + 2) { --charge-delay: 7s;  --charge-duration: 23s; }
.hairline:nth-of-type(3n)     { --charge-delay: 13s; --charge-duration: 29s; }

@keyframes line-charge {
  0%        { opacity: 0; transform: translate3d(-190px, 0, 0); }
  3%, 22%   { opacity: 1; }
  26%, 100% { opacity: 0; transform: translate3d(calc(100vw + 220px), 0, 0); }
}

/* 12-column editorial grid, collapses to one column below 1024px */
.grid12 { display: grid; grid-template-columns: 1fr; gap: 48px; }
@media (min-width: 1024px) {
  .grid12 { grid-template-columns: repeat(12, minmax(0, 1fr)); gap: 40px; }
  .col-4  { grid-column: span 4; }
  .col-5  { grid-column: span 5; }
  .col-6  { grid-column: span 6; }
  .col-7  { grid-column: span 7; }
  .col-8  { grid-column: span 8; }
  .col-12 { grid-column: span 12; }
  /* the deliberate empty gutter at column 7 */
  .col-start-8 { grid-column: 8 / span 5; }
  .lg-center { align-self: center; }
}

.cards { display: grid; gap: 20px; }
@media (min-width: 640px)  { .cards--2 { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 768px)  { .cards--3 { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 1024px) { .cards--4 { grid-template-columns: repeat(4, 1fr); } }

.stack { display: flex; flex-direction: column; }
.row   { display: flex; align-items: center; }
.row--gap { gap: 12px; }
.spacer { flex: 1 1 auto; }


/* == 06  surfaces =========================================================== */

.panel-recessed {
  background: var(--panel-1);
  border: 0.5px solid var(--panel-line);
  border-radius: var(--radius-panel-recessed) var(--radius-panel-recessed) 0 0;
  opacity: 0.62;
  -webkit-mask-image:
    linear-gradient(to right,  #000 0%, #000 52%, rgba(0, 0, 0, 0) 100%),
    linear-gradient(to bottom, #000 0%, #000 58%, rgba(0, 0, 0, 0) 100%);
  -webkit-mask-composite: source-in;
  mask-image:
    linear-gradient(to right,  #000 0%, #000 52%, rgba(0, 0, 0, 0) 100%),
    linear-gradient(to bottom, #000 0%, #000 58%, rgba(0, 0, 0, 0) 100%);
  mask-composite: intersect;
}

.panel-recessed-wide {
  opacity: 0.78;
  -webkit-mask-image:
    linear-gradient(to right,  #000 0%, #000 88%, rgba(0, 0, 0, 0) 100%),
    linear-gradient(to bottom, #000 0%, #000 72%, rgba(0, 0, 0, 0) 100%);
  -webkit-mask-composite: source-in;
  mask-image:
    linear-gradient(to right,  #000 0%, #000 88%, rgba(0, 0, 0, 0) 100%),
    linear-gradient(to bottom, #000 0%, #000 72%, rgba(0, 0, 0, 0) 100%);
  mask-composite: intersect;
}

.panel-elevated {
  background: var(--panel-3);
  border: 0.5px solid var(--panel-line);
  border-radius: var(--radius-panel-elevated);
  box-shadow: var(--panel-ring);
}

.panel-row {
  background: var(--panel-2);
  border: 0.5px solid var(--panel-line);
  border-radius: var(--radius-panel-row);
}

.panel-shot {
  background: var(--panel-1);
  border: 0.5px solid var(--panel-line);
  border-radius: var(--radius-panel-recessed);
  box-shadow: var(--panel-ring);
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 88%, rgba(0, 0, 0, 0) 100%);
  mask-image: linear-gradient(to bottom, #000 0%, #000 88%, rgba(0, 0, 0, 0) 100%);
}

.card-interactive { transition: border-color 150ms var(--fx-ease); }
.card-interactive:hover {
  border-color: color-mix(in oklab, var(--brand) 40%, transparent);
}

/* layered panel stage — hero and section visuals */
.panel-stage { position: relative; height: 368px; }
.panel-stage > .panel-recessed {
  position: absolute;
  inset-inline: 0;
  top: 0;
  height: 300px;
  overflow: hidden;
  padding: 16px 20px 0;
}
.panel-stage > .panel-elevated {
  position: absolute;
  bottom: 24px;
  left: 8px;
  width: min(320px, 88%);
  padding: 14px 16px;
}
.panel-stage--diagonal > .panel-recessed {
  inset-inline: auto 0;
  top: 100px;
  left: 40px;
  padding: 20px 20px 0;
}
.panel-stage--diagonal > .panel-elevated { top: 272px; bottom: auto; left: 0; width: 300px; }


/* == 07  type roles ========================================================= */

.eyebrow {
  display: block;
  font-family: var(--font-mono);
  font-size: 12px;
  line-height: 16px;
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  color: var(--muted-foreground);
  margin: 0;
}
.eyebrow--sm { font-size: 10px; letter-spacing: 0.18em; }

.section-index {
  display: block;
  font-family: var(--font-mono);
  font-size: 12px;
  line-height: 16px;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  color: var(--muted-foreground);
  margin: 0;
}
.section-index b { font-weight: 400; color: var(--brand-text); }
.section-index i { font-style: normal; color: var(--border); margin: 0 8px; }

.caption {
  font-family: var(--font-mono);
  font-size: 12px;
  line-height: 16px;
  text-transform: uppercase;
  letter-spacing: 0.18em;
  color: var(--muted-foreground);
  margin: 0;
}

.meta {
  font-family: var(--font-mono);
  font-size: 12px;
  line-height: 1.5;
  color: var(--muted-foreground);
  margin: 0;
}
.meta--sm { font-size: 11px; letter-spacing: 0.02em; }

h1, .h1 {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 36px;
  line-height: 1.05;
  letter-spacing: -0.025em;
  color: var(--foreground);
  margin: 24px 0 0;
}
@media (min-width: 640px)  { h1, .h1 { font-size: 48px; } }
@media (min-width: 1024px) { h1, .h1 { font-size: 60px; } }

h2, .h2 {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 30px;
  line-height: 1.1;
  letter-spacing: -0.025em;
  color: var(--foreground);
  margin: 20px 0 0;
}
@media (min-width: 640px) { h2, .h2 { font-size: 36px; } }

h3, .h3 {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 24px;
  line-height: 1.15;
  letter-spacing: -0.025em;
  color: var(--foreground);
  margin: 20px 0 0;
}
@media (min-width: 640px) { h3, .h3 { font-size: 30px; } }

/* inside cards and app chrome headings drop to the body face */
.h-card {
  font-family: var(--font-sans);
  font-size: 16px;
  font-weight: 600;
  line-height: 1.4;
  letter-spacing: 0;
  color: var(--foreground);
  margin: 0;
}
.h-app {
  font-family: var(--font-display);
  font-size: 24px;
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: -0.025em;
  color: var(--foreground);
  margin: 0;
}

p, .body {
  font-size: 16px;
  font-weight: 400;
  line-height: 1.625;
  color: var(--muted-foreground);
  margin: 24px 0 0;
}
.body--lead { font-size: 16px; }
@media (min-width: 640px) { .body--lead { font-size: 18px; } }
.body--sm { font-size: 14px; }
.body--tight { margin-top: 8px; }
.body--flat { margin-top: 0; }
.body--fore { color: var(--foreground); }
.measure { max-width: 36rem; }

.bullets { list-style: none; margin: 20px 0 0; padding: 0; display: grid; gap: 10px; }
.bullets li {
  display: flex;
  gap: 10px;
  align-items: baseline;
  font-size: 14px;
  line-height: 1.5;
  color: var(--muted-foreground);
}
.bullets li::before {
  content: "";
  flex: none;
  width: 5px; height: 5px;
  margin-top: 8px;
  border-radius: 9999px;
  background: var(--brand-graphic);
}

.link-brand {
  color: var(--brand-text);
  font-weight: 500;
  transition: color 150ms var(--fx-ease);
}
.link-brand:hover { color: var(--brand-active); }

.link-quiet { color: var(--muted-foreground); transition: color 150ms var(--fx-ease); }
.link-quiet:hover { color: var(--foreground); }


/* == 08  buttons ============================================================
   Base height is 36px per the source, but every touch target gets a 44px
   minimum via the ::after hit-area on coarse pointers. */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  position: relative;
  gap: 8px;
  height: 36px;
  padding: 8px 16px;
  border: 0;
  border-radius: var(--radius-md);
  background: transparent;
  font-family: inherit;
  font-size: 14px;
  font-weight: 500;
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  flex-shrink: 0;
  transition: background-color 150ms var(--fx-ease), color 150ms var(--fx-ease),
              border-color 150ms var(--fx-ease), opacity 150ms var(--fx-ease);
}
.btn:disabled, .btn[aria-disabled="true"] { pointer-events: none; opacity: 0.5; }
.btn svg { width: 16px; height: 16px; flex: none; }

/* Coarse pointers get a 44px hit area without changing the visual box. */
@media (pointer: coarse) {
  .btn::after {
    content: "";
    position: absolute;
    left: 50%;
    top: 50%;
    width: max(100%, 44px);
    height: max(100%, 44px);
    transform: translate(-50%, -50%);
  }
}

.btn--lg { height: 44px; padding: 0 24px; font-size: 15px; }
.btn--sm { height: 32px; padding: 0 12px; gap: 6px; }
.btn--icon { width: 36px; height: 36px; padding: 0; }
.btn--icon-lg { width: 44px; height: 44px; padding: 0; }
.btn--block { width: 100%; }

.btn--brand { background: var(--brand); color: var(--brand-foreground); }
.btn--brand:hover { background: color-mix(in oklab, var(--brand) 90%, transparent); }
.btn--brand:active { background: var(--brand-active); }

.btn--default { background: var(--primary); color: var(--primary-foreground); }
.btn--default:hover { background: color-mix(in oklab, var(--primary) 90%, transparent); }

.btn--outline {
  background: transparent;
  color: var(--foreground);
  border: 1px solid var(--input-line);
}
.btn--outline:hover { background: var(--accent); }

.btn--ghost { background: transparent; color: var(--foreground); }
.btn--ghost:hover { background: var(--accent); }

.btn--quiet { background: transparent; color: var(--muted-foreground); }
.btn--quiet:hover { background: var(--accent); color: var(--foreground); }

.btn--danger { background: transparent; color: var(--destructive-text); }
.btn--danger:hover { background: color-mix(in oklab, var(--destructive) 12%, transparent); }

.btn--danger-solid { background: var(--destructive); color: var(--destructive-foreground); }
.btn--danger-solid:hover { background: color-mix(in oklab, var(--destructive) 90%, transparent); }

/* secondary CTA arrow — never on the primary */
.btn .arrow { margin-left: -2px; }

.btn-row { display: flex; flex-direction: column; gap: 12px; margin-top: 32px; }
@media (min-width: 640px) { .btn-row { flex-direction: row; align-items: center; gap: 16px; } }

/* spinner for pending buttons */
.btn[data-pending] { pointer-events: none; }
.btn[data-pending] .btn-label { opacity: 0.6; }
.spinner {
  width: 16px; height: 16px;
  border-radius: 9999px;
  border: 2px solid color-mix(in oklab, currentColor 25%, transparent);
  border-top-color: currentColor;
  animation: spin 700ms linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }


/* == 09  fields ============================================================= */

.field-group { display: grid; gap: 6px; }

.field-label {
  display: block;
  font-size: 14px;
  font-weight: 500;
  color: var(--foreground);
}
.field-label .optional { font-weight: 400; color: var(--muted-foreground); }

.field {
  width: 100%;
  min-height: 44px;
  border: 0;
  border-bottom: 1px solid var(--input-line);
  border-radius: 0;
  background: transparent;
  padding: 10px 0;
  font-family: inherit;
  font-size: 16px; /* 16px prevents the iOS focus zoom */
  color: var(--foreground);
  transition: border-color 150ms var(--fx-ease);
}
.field::placeholder { color: color-mix(in oklab, var(--muted-foreground) 75%, transparent); }
.field:focus {
  border-bottom-color: var(--foreground);
  outline: 2px solid var(--ring-strong);
  outline-offset: 3px;
  box-shadow: none;
}
.field[aria-invalid="true"] { border-bottom-color: var(--destructive); }

.field-hint { font-size: 13px; line-height: 1.5; color: var(--muted-foreground); margin: 0; }
.field-error {
  display: flex;
  gap: 6px;
  align-items: flex-start;
  font-size: 13px;
  line-height: 1.5;
  color: var(--destructive-text);
  margin: 0;
}

/* read-only link box, used by the share panel */
.copy-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 6px 6px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--panel-2);
}
.copy-row input {
  flex: 1 1 auto;
  min-width: 0;
  border: 0;
  background: transparent;
  padding: 0;
  font-family: var(--font-mono);
  font-size: 14px;
  color: var(--foreground);
  text-overflow: ellipsis;
}
.copy-row input:focus { outline: none; }


/* == 10  pills, dots, meta ================================================== */

.pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  width: fit-content;
  padding: 3px 10px;
  border: 1px solid var(--border);
  border-radius: 9999px;
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 16px;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--muted-foreground);
  white-space: nowrap;
}
.pill--brand {
  border-color: color-mix(in oklab, var(--brand) 45%, transparent);
  color: var(--brand-text);
}
.pill--notice {
  border-color: var(--notice-soft-border);
  background: var(--notice-soft);
  color: var(--notice-text);
}
.pill--ok { border-color: color-mix(in oklab, var(--ok) 45%, transparent); color: var(--ok-text); }
.pill--plain { border-color: transparent; background: var(--accent); }

.dot {
  width: 6px; height: 6px;
  flex: none;
  border-radius: 9999px;
  background: var(--muted-foreground);
}
.dot--brand  { background: var(--brand-graphic); }
.dot--ok     { background: var(--ok); }
.dot--notice { background: var(--notice); }

.dot-live { position: relative; }
.dot-live::after {
  content: "";
  position: absolute;
  inset: -3px;
  border-radius: 9999px;
  border: 1px solid currentColor;
  color: var(--ok);
  opacity: 0;
  animation: ping 2.4s var(--fx-ease) infinite;
}
@keyframes ping {
  0%   { transform: scale(0.7); opacity: 0.9; }
  70%  { transform: scale(1.6); opacity: 0; }
  100% { transform: scale(1.6); opacity: 0; }
}

.micro-label {
  font-family: var(--font-mono);
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.18em;
  color: var(--brand-text);
}


/* == 11  navigation and footer ============================================== */

.nav {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 50;
  height: calc(56px + var(--safe-t));
  padding-top: var(--safe-t);
  border-bottom: 1px solid var(--border);
  background: color-mix(in oklab, var(--background) 80%, transparent);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .nav { background: var(--background); }
}
.nav-inner {
  display: flex;
  align-items: center;
  gap: 16px;
  height: 56px;
  max-width: 1200px;
  margin-inline: auto;
  padding-inline: 24px;
}
.nav-links { display: none; gap: 4px; align-items: center; }
@media (min-width: 1024px) { .nav-links { display: flex; } }
.nav-link {
  padding: 8px 12px;
  border-radius: var(--radius-md);
  font-size: 14px;
  font-weight: 500;
  color: var(--muted-foreground);
  transition: color 200ms var(--fx-ease), background-color 200ms var(--fx-ease);
}
.nav-link:hover { color: var(--brand-text); }
.nav-link[aria-current="page"] { color: var(--foreground); background: var(--accent); }

.wordmark { display: inline-flex; align-items: center; gap: 8px; transition: opacity 150ms; }
.wordmark:hover { opacity: 0.8; }
.wordmark .mark {
  width: 28px; height: 28px;
  flex: none;
  border-radius: 22.4%;
  background: var(--brand);
  display: grid; place-items: center;
  color: var(--brand-foreground);
}
.wordmark .mark svg { width: 16px; height: 16px; }
.wordmark .name {
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 600;
  letter-spacing: -0.025em;
  color: var(--foreground);
}
.wordmark .by {
  display: none;
  font-family: var(--font-mono);
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.18em;
  color: var(--muted-foreground);
  padding-left: 2px;
}
@media (min-width: 480px) { .wordmark .by { display: inline; } }

.footer {
  border-top: 1px solid var(--border);
  padding-block: 48px;
}
@media (min-width: 1024px) { .footer { padding-block: 64px; } }
.footer-grid { display: grid; gap: 32px; grid-template-columns: 1fr; }
@media (min-width: 768px) { .footer-grid { grid-template-columns: 2fr 1fr 1fr 1fr; gap: 40px; } }
.footer h4 {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: 0.18em;
  color: var(--muted-foreground);
  margin: 0 0 14px;
}
.footer ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px; }
.footer a { font-size: 14px; color: var(--muted-foreground); transition: color 150ms var(--fx-ease); }
.footer a:hover { color: var(--foreground); }
.footer-base {
  display: flex;
  flex-wrap: wrap;
  gap: 12px 24px;
  margin-top: 40px;
  padding-top: 24px;
  border-top: 1px solid var(--border);
}


/* == 12  photo primitives ===================================================
   A contact-sheet grid of equal squares, not a masonry column flow. Masonry
   via column-count fills top-to-bottom per column, which would scramble the
   EXIF timeline that is the point of the product. Equal squares keep strict
   left-to-right chronological reading order at every breakpoint. */

.sheet {
  display: grid;
  grid-template-columns: repeat(var(--cols, 3), 1fr);
  gap: var(--tile-gap);
}
@media (min-width: 480px)  { .sheet { --cols: 4; } }
@media (min-width: 768px)  { .sheet { --cols: 5; --tile-gap: 6px; } }
@media (min-width: 1100px) { .sheet { --cols: 6; } }
@media (min-width: 1600px) { .sheet { --cols: 7; } }

.tile {
  position: relative;
  display: block;
  aspect-ratio: 1;
  overflow: hidden;
  border: 0;
  padding: 0;
  border-radius: 10px;
  background: var(--photo-bg);
  cursor: pointer;
  transition: opacity 150ms var(--fx-ease);
}
.tile:hover { opacity: 0.86; }
.tile.skeleton { border-radius: 10px; }
.tile > img,
.tile > .tile-fill { width: 100%; height: 100%; object-fit: cover; }
.tile:focus-visible { outline-offset: -2px; z-index: 1; }

.tile-badge {
  position: absolute;
  right: 6px; bottom: 6px;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 6px;
  border-radius: 9999px;
  background: rgba(0, 0, 0, 0.62);
  color: #FFFFFF;
  font-family: var(--font-mono);
  font-size: 10px;
  line-height: 14px;
  letter-spacing: 0.06em;
}
.tile-badge svg { width: 10px; height: 10px; }

.tile--new::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  border: 2px solid var(--brand);
  border-radius: 10px;
  animation: tile-settle 1400ms var(--fx-ease) forwards;
}
@keyframes tile-settle { to { opacity: 0; } }

/* day rule — the timeline made visible */
.day-rule {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 28px 0 10px;
}
.day-rule:first-child { margin-top: 0; }
.day-rule h2 {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 400;
  line-height: 16px;
  text-transform: uppercase;
  letter-spacing: 0.18em;
  color: var(--muted-foreground);
  margin: 0;
  white-space: nowrap;
}
.day-rule .rule {
  flex: 1 1 auto;
  height: 1px;
  background: linear-gradient(to right, var(--border) 0%, rgba(0, 0, 0, 0) 100%);
}
.day-rule .span {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.06em;
  color: var(--muted-foreground);
  white-space: nowrap;
}

/* gallery page frame */
.gallery-body {
  padding-bottom: calc(var(--dock-h) + var(--safe-b) + 24px);
  display: flex;
  flex-direction: column;
  min-height: 100svh;
}
.gallery-main { flex: 1 1 auto; display: flex; flex-direction: column; }
#state-photos { flex: 1 1 auto; display: flex; flex-direction: column; }
#photo-groups { flex: 0 0 auto; }
.gallery-foot {
  margin-top: auto;
  display: grid;
  justify-items: center;
  gap: 6px;
  padding: 40px 16px 8px;
  text-align: center;
}
.gallery-main { padding-inline: max(12px, var(--safe-l)) max(12px, var(--safe-r)); }
@media (min-width: 768px) { .gallery-main { padding-inline: 24px; } }

.gallery-head {
  position: sticky;
  top: 0;
  z-index: 40;
  padding: calc(var(--safe-t) + 12px) max(12px, var(--safe-l)) 12px max(12px, var(--safe-r));
  background: color-mix(in oklab, var(--background) 86%, transparent);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-bottom: 1px solid color-mix(in oklab, var(--border) 70%, transparent);
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .gallery-head { background: var(--background); }
}
.gallery-head-inner {
  display: flex;
  align-items: center;
  gap: 12px;
  max-width: 1500px;
  margin-inline: auto;
}
.gallery-title {
  font-family: var(--font-display);
  font-size: 20px;
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: -0.025em;
  color: var(--foreground);
  margin: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
@media (min-width: 768px) { .gallery-title { font-size: 24px; } }
.gallery-sub {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 2px 0 0;
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 16px;
  letter-spacing: 0.06em;
  color: var(--muted-foreground);
}
.gallery-sub b { font-weight: 400; color: var(--foreground); }


/* == 13  action bar (dock) ==================================================
   The single primary action on the highest-traffic screen. Fixed, safe-area
   padded, 44px+ target, brand fill. Nothing else lives here. */

.dock {
  position: fixed;
  inset: auto 0 0 0;
  z-index: 60;
  padding: 10px max(12px, var(--safe-l)) calc(10px + var(--safe-b)) max(12px, var(--safe-r));
  background: color-mix(in oklab, var(--background) 88%, transparent);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border-top: 1px solid color-mix(in oklab, var(--border) 80%, transparent);
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .dock { background: var(--background); }
}
.dock-inner {
  display: flex;
  align-items: center;
  gap: 10px;
  max-width: 640px;
  margin-inline: auto;
}

.btn--dock {
  position: relative;
  flex: 1 1 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  min-height: 48px;
  padding: 0 20px;
  border: 0;
  border-radius: var(--radius-md);
  background: var(--brand);
  color: var(--brand-foreground);
  font-family: inherit;
  font-size: 16px;
  font-weight: 500;
  cursor: pointer;
  transition: background-color 150ms var(--fx-ease);
}
.btn--dock:hover { background: color-mix(in oklab, var(--brand) 92%, transparent); }
.btn--dock:active { background: var(--brand-active); }
.btn--dock svg { width: 20px; height: 20px; flex: none; }
.btn--dock input[type="file"] {
  position: absolute;
  inset: 0;
  opacity: 0;
  cursor: pointer;
}

.dock-side {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px; height: 48px;
  flex: none;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--panel-3);
  color: var(--foreground);
  cursor: pointer;
  transition: background-color 150ms var(--fx-ease);
}
.dock-side:hover { background: var(--accent); }
.dock-side svg { width: 20px; height: 20px; }


/* == 14  upload sheet and progress ==========================================
   Docked directly above the action bar so progress and the button that
   started it stay in one place. Collapsible; never blocks the grid. */

.uploads {
  position: fixed;
  inset: auto 0 calc(var(--dock-h) + var(--safe-b)) 0;
  z-index: 55;
  padding: 0 max(12px, var(--safe-l)) 8px max(12px, var(--safe-r));
  pointer-events: none;
}
.uploads-card {
  pointer-events: auto;
  max-width: 640px;
  margin-inline: auto;
  padding: 12px 14px 8px;
  background: var(--panel-3);
  border: 0.5px solid var(--panel-line);
  border-radius: var(--radius-md);
  box-shadow: var(--panel-ring), 0 12px 32px -20px rgba(0, 0, 0, 0.7);
}
.uploads-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding-bottom: 8px;
}
.uploads-head .title {
  font-family: var(--font-mono);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--muted-foreground);
}
.uploads-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 2px;
  max-height: 200px;
  overflow-y: auto;
}
.upload {
  display: grid;
  grid-template-columns: 28px minmax(0, 1fr) auto auto;
  align-items: center;
  gap: 10px;
  padding: 6px 0;
}
.upload-thumb {
  width: 28px; height: 28px;
  border-radius: 4px;
  background: var(--photo-bg);
  overflow: hidden;
}
.upload-name {
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 14px;
  color: var(--foreground);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.upload-state {
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 14px;
  color: var(--muted-foreground);
  font-variant-numeric: tabular-nums;
}
.upload[data-state="done"] .upload-state { color: var(--ok-text); }
.upload[data-state="error"] .upload-state { color: var(--destructive-text); }
.upload-bar {
  grid-column: 2 / -1;
  height: 3px;
  border-radius: 9999px;
  background: color-mix(in oklab, var(--foreground) 14%, transparent);
  overflow: hidden;
}
.upload-bar > span {
  display: block;
  height: 100%;
  border-radius: 9999px;
  background: var(--brand-graphic);
  transition: width 240ms var(--fx-ease);
}
.upload[data-state="error"] .upload-bar > span { background: var(--destructive); }
.upload-retry {
  font-size: 12px;
  font-weight: 500;
  color: var(--brand-text);
  background: none;
  border: 0;
  padding: 4px 6px;
  cursor: pointer;
}

/* global thin progress line for whole-batch state */
.progress-line {
  height: 2px;
  border-radius: 9999px;
  background: color-mix(in oklab, var(--foreground) 14%, transparent);
  overflow: hidden;
}
.progress-line > span {
  display: block;
  height: 100%;
  background: var(--brand-graphic);
  transition: width 240ms var(--fx-ease);
}
.progress-line--indeterminate > span {
  width: 40%;
  animation: slide 1200ms var(--fx-ease) infinite;
}
@keyframes slide {
  0%   { transform: translateX(-110%); }
  100% { transform: translateX(260%); }
}


/* == 15  lightbox =========================================================== */

.lightbox {
  position: fixed;
  inset: 0;
  z-index: 90;
  display: grid;
  grid-template-rows: auto 1fr auto;
  background: var(--scrim);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  overscroll-behavior: contain;
}
.lb-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: calc(var(--safe-t) + 8px) max(8px, var(--safe-l)) 8px max(8px, var(--safe-r));
}
.lb-bar--bottom {
  padding: 8px max(8px, var(--safe-l)) calc(var(--safe-b) + 12px) max(8px, var(--safe-r));
}
.lb-count {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.08em;
  color: #EDEDEB;
  font-variant-numeric: tabular-nums;
}
.lb-when {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.06em;
  color: #A8A8A5;
}
.lb-stage {
  position: relative;
  display: grid;
  place-items: center;
  overflow: hidden;
  min-height: 0;
  touch-action: pan-y pinch-zoom;
}
.lb-stage > img,
.lb-stage > .tile-fill {
  max-width: 100%;
  max-height: 100%;
  width: auto; height: auto;
  object-fit: contain;
}
.lb-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-width: 44px;
  height: 44px;
  padding: 0 14px;
  border: 0;
  border-radius: var(--radius-md);
  background: rgba(255, 255, 255, 0.10);
  color: #EDEDEB;
  font-family: inherit;
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
  transition: background-color 150ms var(--fx-ease);
}
.lb-btn:hover { background: rgba(255, 255, 255, 0.18); }
.lb-btn--danger { color: #FF8A8C; }
.lb-btn svg { width: 18px; height: 18px; }
.lb-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  display: none;
  width: 44px; height: 44px;
  align-items: center;
  justify-content: center;
  border: 0;
  border-radius: 9999px;
  background: rgba(255, 255, 255, 0.10);
  color: #EDEDEB;
  cursor: pointer;
}
.lb-nav:hover { background: rgba(255, 255, 255, 0.18); }
.lb-prev { left: 16px; }
.lb-next { right: 16px; }
@media (hover: hover) and (min-width: 768px) { .lb-nav { display: inline-flex; } }
.lb-hint {
  position: absolute;
  inset: auto 0 12px;
  text-align: center;
  font-family: var(--font-mono);
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.18em;
  color: rgba(237, 237, 235, 0.55);
}
@media (hover: hover) and (min-width: 768px) { .lb-hint { display: none; } }


/* == 16  dialogs and sheets ================================================= */

.overlay {
  position: fixed;
  inset: 0;
  z-index: 80;
  display: grid;
  place-items: end center;
  padding: 0;
  background: color-mix(in oklab, #000 58%, transparent);
}
@media (min-width: 640px) { .overlay { place-items: center; padding: 24px; } }

.dialog {
  width: 100%;
  max-width: 520px;
  max-height: 92dvh;
  overflow-y: auto;
  padding: 24px 24px calc(24px + var(--safe-b));
  background: var(--panel-3);
  border: 0.5px solid var(--panel-line);
  border-radius: var(--radius-xl) var(--radius-xl) 0 0;
  box-shadow: var(--panel-ring), 0 20px 48px -28px rgba(0, 0, 0, 0.5);
}
@media (min-width: 640px) { .dialog { border-radius: var(--radius-xl); padding-bottom: 24px; } }
.dialog-grip {
  width: 36px; height: 4px;
  margin: -8px auto 16px;
  border-radius: 9999px;
  background: var(--border);
}
@media (min-width: 640px) { .dialog-grip { display: none; } }
.dialog-head { display: flex; align-items: flex-start; gap: 12px; }
.dialog-title {
  font-family: var(--font-display);
  font-size: 22px;
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: -0.025em;
  color: var(--foreground);
  margin: 0;
}
.dialog-actions {
  display: flex;
  flex-direction: column-reverse;
  gap: 10px;
  margin-top: 24px;
}
@media (min-width: 640px) {
  .dialog-actions { flex-direction: row; justify-content: flex-end; }
}


/* == 17  share and QR =======================================================
   The QR always renders dark-on-white regardless of theme. Inverted QR codes
   fail on a meaningful share of camera apps, and this code gets pointed at a
   phone across a noisy room. The white card is a deliberate bright object. */

.qr-card {
  display: grid;
  place-items: center;
  gap: 12px;
  padding: 20px;
  background: #FFFFFF;
  border-radius: var(--radius);
  box-shadow: var(--panel-ring);
}
.qr-card svg { width: 100%; max-width: 232px; height: auto; }
.qr-card .qr-label {
  font-family: var(--font-mono);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: #525252;
  text-align: center;
}

.share-grid { display: grid; gap: 20px; }
@media (min-width: 640px) { .share-grid { grid-template-columns: 232px 1fr; align-items: start; } }

.short-link {
  font-family: var(--font-mono);
  font-size: 18px;
  letter-spacing: -0.01em;
  color: var(--foreground);
  word-break: break-all;
}
.short-link .host { color: var(--muted-foreground); }

.access-note {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  padding: 12px 14px;
  border: 0.5px solid var(--panel-line);
  border-radius: var(--radius-panel-row);
  background: var(--panel-1);
}
.access-note svg { width: 16px; height: 16px; flex: none; margin-top: 3px; color: var(--muted-foreground); }
.access-note p { margin: 0; font-size: 13px; line-height: 1.55; color: var(--muted-foreground); }
.access-note strong { color: var(--foreground); font-weight: 500; }


/* == 18  states ============================================================= */

/* empty */
.empty {
  display: grid;
  justify-items: center;
  gap: 8px;
  padding: 56px 24px;
  text-align: center;
}
.empty--left { justify-items: start; text-align: left; }
.empty-title {
  font-family: var(--font-display);
  font-size: 20px;
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: -0.025em;
  color: var(--foreground);
  margin: 12px 0 0;
}
.empty-body {
  font-size: 14px;
  line-height: 1.625;
  color: var(--muted-foreground);
  margin: 6px 0 0;
  max-width: 34ch;
}
.empty-mark {
  width: 56px; height: 56px;
  display: grid;
  place-items: center;
  border-radius: 9999px;
  border: 1px solid var(--border);
  color: var(--muted-foreground);
}
.empty-mark svg { width: 22px; height: 22px; }

/* loading skeleton */
.skeleton {
  background: var(--photo-bg);
  border-radius: 2px;
  position: relative;
  overflow: hidden;
}
.skeleton::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg,
    rgba(255, 255, 255, 0) 0%,
    color-mix(in oklab, var(--foreground) 6%, transparent) 50%,
    rgba(255, 255, 255, 0) 100%);
  animation: shimmer 1400ms linear infinite;
}
@keyframes shimmer {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(100%); }
}

/* inline notices */
.notice {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: flex-start;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius-panel-row);
  background: var(--panel-2);
  font-size: 13px;
  line-height: 1.55;
  color: var(--muted-foreground);
}
.notice svg { width: 16px; height: 16px; flex: none; margin-top: 2px; }
.notice strong { color: var(--foreground); font-weight: 500; }
.notice p { flex: 1 1 220px; }
.notice .notice-actions { margin-left: auto; display: flex; gap: 8px; flex: none; }
@media (max-width: 519px) {
  .notice .notice-actions { margin-left: 26px; }
}

.notice--warn {
  border-color: var(--notice-soft-border);
  background: var(--notice-soft);
  color: var(--notice-text);
}
.notice--warn strong { color: var(--notice-text); }
.notice--warn svg { color: var(--notice-text); }

.notice--error {
  border-color: color-mix(in oklab, var(--destructive) 45%, transparent);
  background: color-mix(in oklab, var(--destructive) 8%, transparent);
  color: var(--destructive-text);
}
.notice--error strong { color: var(--destructive-text); }

.notice--offline {
  position: fixed;
  inset: auto max(12px, var(--safe-l)) calc(var(--dock-h) + var(--safe-b) + 8px) max(12px, var(--safe-r));
  z-index: 58;
  max-width: 640px;
  margin-inline: auto;
  box-shadow: var(--panel-ring);
}

/* toast */
.toast {
  position: fixed;
  inset: auto 0 calc(var(--dock-h) + var(--safe-b) + 12px) 0;
  z-index: 70;
  display: grid;
  justify-items: center;
  pointer-events: none;
}
.toast > * {
  pointer-events: auto;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px;
  border-radius: 9999px;
  background: var(--panel-3);
  border: 0.5px solid var(--panel-line);
  box-shadow: var(--panel-ring);
  font-size: 13px;
  font-weight: 500;
  color: var(--foreground);
}

/* expiry, in list rows */
.expiry {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.06em;
  color: var(--muted-foreground);
}
.expiry[data-level="soon"] { color: var(--notice-text); }


/* == 19  motion ============================================================= */

.fade-up {
  --fx-duration: 620ms;
  --fx-delay: 0ms;
  --fx-travel: 20px;
  opacity: 0;
  transform: translateY(var(--fx-travel));
  transition: opacity var(--fx-duration) var(--fx-ease) var(--fx-delay),
              transform var(--fx-duration) var(--fx-ease) var(--fx-delay);
  will-change: opacity, transform;
}
.fade-up.is-visible { opacity: 1; transform: translateY(0); will-change: auto; }

.fade-up--settle {
  --fx-duration: 820ms;
  --fx-travel: 34px;
  transform: translateY(var(--fx-travel)) scale(0.988);
}
.fade-up--settle.is-visible { transform: translateY(0) scale(1); }

.fade-up--reveal {
  --fx-duration: 900ms;
  --fx-travel: 26px;
  clip-path: inset(14% 0 0 0);
  transition: opacity var(--fx-duration) var(--fx-ease) var(--fx-delay),
              transform var(--fx-duration) var(--fx-ease) var(--fx-delay),
              clip-path var(--fx-duration) var(--fx-ease) var(--fx-delay);
}
.fade-up--reveal.is-visible { clip-path: inset(0 0 0 0); }

.fade-stagger { opacity: 1; transform: none; transition: none; }
.fade-stagger > * {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 600ms var(--fx-ease) var(--fx-delay),
              transform 600ms var(--fx-ease) var(--fx-delay);
}
.fade-stagger.is-visible > * { opacity: 1; transform: translateY(0); }
.fade-stagger > *:nth-child(1) { --fx-delay: 0ms; }
.fade-stagger > *:nth-child(2) { --fx-delay: 70ms; }
.fade-stagger > *:nth-child(3) { --fx-delay: 140ms; }
.fade-stagger > *:nth-child(4) { --fx-delay: 210ms; }
.fade-stagger > *:nth-child(5) { --fx-delay: 280ms; }
.fade-stagger > *:nth-child(6) { --fx-delay: 350ms; }
.fade-stagger > *:nth-child(n + 7) { --fx-delay: 420ms; }

.ambient-pool {
  position: absolute;
  inset: -35%;
  pointer-events: none;
  border-radius: 9999px;
  background: radial-gradient(closest-side, var(--ambient-tint) 0%, rgba(0, 0, 0, 0) 100%);
  mix-blend-mode: var(--ambient-blend);
  animation: ambient-drift var(--ambient-duration, 16s) ease-in-out infinite alternate;
  animation-delay: var(--ambient-delay, 0ms);
}
@keyframes ambient-drift {
  from { transform: translate3d(-12%, -7%, 0) scale(1); }
  to   { transform: translate3d(14%, 9%, 0) scale(1.28); }
}


/* == 20  reduced motion =====================================================
   Kills everything. Not optional. */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  .fade-up, .fade-up--settle, .fade-up--reveal {
    opacity: 1; transform: none; clip-path: none; transition: none;
  }
  .fade-stagger > * { opacity: 1; transform: none; transition: none; }
  .ambient-pool { animation: none; }
  .hairline::after { display: none; }
  .skeleton::after { display: none; }
  .dot-live::after { display: none; }
  .tile--new::before { animation: none; opacity: 0; }
  .progress-line--indeterminate > span { animation: none; width: 100%; opacity: 0.5; }
  .spinner { animation: none; border-top-color: transparent; }
}


/* == 21  scrollbars ========================================================= */

* { scrollbar-width: thin; scrollbar-color: var(--sb-thumb) var(--sb-track); }
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-track { background: var(--sb-track); border-radius: 5px; }
*::-webkit-scrollbar-thumb {
  background: var(--sb-thumb);
  border-radius: 5px;
  border: 2px solid var(--sb-track);
}
*::-webkit-scrollbar-thumb:hover { background: var(--sb-thumb-hover); }


/* == 22  utilities ========================================================== */

.mt-8  { margin-top: 8px; }
.mt-12 { margin-top: 12px; }
.mt-16 { margin-top: 16px; }
.mt-20 { margin-top: 20px; }
.mt-24 { margin-top: 24px; }
.mt-32 { margin-top: 32px; }
.mt-40 { margin-top: 40px; }
.mt-48 { margin-top: 48px; }
.mt-0  { margin-top: 0; }
.muted { color: var(--muted-foreground); }
.fore  { color: var(--foreground); }
.nums  { font-variant-numeric: tabular-nums; }
.wrap  { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px; }


/* == 23  app shell =========================================================
   Lifted from the page-level <style> blocks in docs/design/admin.html and
   docs/design/signin.html, now that the routes exist. */

.app-main { padding-top: calc(56px + var(--safe-t)); }
.page-head { display: flex; align-items: flex-end; gap: 16px; flex-wrap: wrap; padding-block: 40px 24px; }

.g-list { display: grid; gap: 10px; list-style: none; margin: 0; padding: 0; }
.g-row { display: grid; grid-template-columns: 64px 1fr; gap: 14px; align-items: center; padding: 14px; }
.g-cover {
  width: 64px; height: 64px;
  border-radius: var(--radius-panel-row);
  overflow: hidden;
  background: var(--photo-bg);
  flex: none;
}
.g-cover img { width: 100%; height: 100%; object-fit: cover; }
.g-body { min-width: 0; }
.g-actions {
  grid-column: 1 / -1;
  display: flex; gap: 8px; align-items: center;
  padding-top: 12px; margin-top: 12px;
  border-top: 1px solid color-mix(in oklab, var(--border) 60%, transparent);
}
.g-row .expiry { grid-column: 2; justify-self: start; margin-top: -4px; }
@media (min-width: 768px) {
  .g-row { grid-template-columns: 64px minmax(0, 1fr) auto auto; gap: 16px; }
  .g-actions { grid-column: auto; padding-top: 0; margin-top: 0; border-top: 0; }
  .g-row .expiry { grid-column: auto; justify-self: auto; margin-top: 0; }
}
.g-name { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.g-name a { color: var(--foreground); }
.g-name a:hover { color: var(--brand-text); }

.avatar {
  width: 28px; height: 28px;
  border-radius: 9999px;
  background: var(--accent);
  display: grid; place-items: center;
  font-size: 11px; font-weight: 500;
  color: var(--foreground);
}

/* row overflow menu */
.menu-anchor { position: relative; display: inline-flex; }
.menu {
  position: absolute;
  right: 0; top: calc(100% + 6px);
  z-index: 40;
  min-width: 168px;
  display: grid; gap: 2px;
  padding: 6px;
  border-radius: var(--radius-sm);
  background: var(--popover);
  border: 0.5px solid var(--panel-line);
  box-shadow: var(--panel-ring), 0 12px 32px -20px rgba(0, 0, 0, 0.7);
}
.menu button {
  display: flex; align-items: center; gap: 8px;
  width: 100%;
  padding: 8px 10px;
  border: 0; border-radius: 8px;
  background: none;
  color: var(--foreground);
  font-size: 14px;
  text-align: left;
  cursor: pointer;
}
.menu button:hover { background: var(--accent); }
.menu button svg { width: 15px; height: 15px; flex: none; }
.menu button.is-danger { color: var(--destructive-text); }
.menu button.is-danger:hover { background: color-mix(in oklab, var(--destructive) 12%, transparent); }

/* sign-in */
.auth-main { padding-top: calc(56px + var(--safe-t)); position: relative; overflow: hidden; }
.auth-main.section { padding-block: calc(56px + var(--safe-t) + 48px) 64px; }
@media (min-width: 1024px) { .auth-main.section { padding-block: calc(56px + var(--safe-t) + 64px) 80px; } }
.auth-card { padding: 24px; }
@media (min-width: 640px) { .auth-card { padding: 32px; } }

.or-rule { display: flex; align-items: center; gap: 12px; margin-top: 20px; }
.or-rule i { flex: 1 1 auto; height: 1px; background: color-mix(in oklab, var(--foreground) 16%, transparent); }
.or-rule span {
  font-family: var(--font-mono); font-size: 10px; text-transform: uppercase;
  letter-spacing: 0.18em; color: var(--muted-foreground);
}

.state-mark {
  width: 48px; height: 48px;
  display: grid; place-items: center;
  border-radius: 9999px;
  background: var(--accent);
  color: var(--foreground);
}
.state-mark svg { width: 22px; height: 22px; }
.state-mark--brand { background: color-mix(in oklab, var(--brand) 16%, transparent); color: var(--brand-text); }

/* video tile with no still to show */
.tile-blank {
  width: 100%; height: 100%;
  display: grid; place-items: center;
  background: var(--photo-bg);
  color: var(--muted-foreground);
}
.tile-blank svg { width: 22px; height: 22px; }

/* the dock file input is transparent, so the label carries the focus ring */
.btn--dock:has(input:focus-visible) {
  outline: 2px solid var(--ring-strong);
  outline-offset: 2px;
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--brand) 40%, transparent);
}

.menu-note {
  margin: 0;
  padding: 6px 10px 8px;
  font-size: 12px;
  line-height: 1.4;
  color: var(--muted-foreground);
  word-break: break-all;
  border-bottom: 1px solid color-mix(in oklab, var(--border) 60%, transparent);
}

.upload:not([data-state="uploading"]) .upload-bar { display: none; }

/* when uploads are running the offline notice stacks inside the card
   instead of anchoring to the dock, so the two never overlap */
.uploads-card > .notice--offline {
  position: static;
  inset: auto;
  max-width: none;
  margin: 0 0 10px;
  box-shadow: none;
}
