/* =====================================================================
   nv-base — the design tokens and the surfaces every Noriva page shares
   =====================================================================

   Loaded FIRST, before nv-card.css or nv-menu.css. Those two are the card
   and the list page; this is what they agree on.

   Why a separate file: the card and the menu are the same object seen twice
   — a visitor flips the card and lands on the menu — so they have to share
   one palette, one radius, one motion curve and one sheet. A copied token
   block is a token block that drifts, and two pages disagreeing about what
   "accent" means is exactly the kind of thing nobody notices until a
   customer does.

   ---------------------------------------------------------------------
   CUSTOMISING
   ---------------------------------------------------------------------
   Every colour, radius, shadow and duration is a custom property on :root.
   A customisation stylesheet overrides tokens, not rules — and an override
   on `.nv-card` still wins for the card itself:

       .nv-card { --nv-back-bg: #10151c; --nv-accent: #d4a017; }

   See docs/card-themes/ for the full guide.

   ---------------------------------------------------------------------
   THEME
   ---------------------------------------------------------------------
   Three signals, because the project uses more than one:
     * `[data-theme="dark"|"light"]` on <html>   — what utils.js sets
     * `html.dark`                                — used elsewhere in admin
     * `prefers-color-scheme`                     — when neither is set
   Light values live on the base :root block so a page is never colourless
   if something fails to load; the dark blocks only re-declare tokens.
   ===================================================================== */

/* ── tokens ─────────────────────────────────────────────────────────── */

/* Declared on :root, not on .nv-card. The stage and the memory-wall sheet
   are OUTSIDE the card and cannot read a property declared on a descendant —
   scoping the palette to .nv-card left the sheet reading its hard-coded
   fallbacks and rendering white under the dark theme.

   Overriding any of these on `.nv-card` still works and still wins for the
   card itself; that is the documented customisation hook. Override them on
   :root to move the surrounding surfaces with it. */
:root {
  /* motion
     --nv-flip-dur is the WHOLE turn: rotation and the lift that goes with
     it finish together. nv-card.js reads this value, so the class that
     drives the lift can never outlive the transition it belongs to.

     --nv-ease is deliberately not a hard ease-out. The old
     cubic-bezier(.22,1,.36,1) put 94% of the rotation into the first 40% of
     the time and then crawled the last few degrees, which reads as the card
     freezing just before it lands. This curve keeps moving. */
  --nv-flip-dur: 480ms;
  --nv-ease: cubic-bezier(.33, .12, .18, 1);
  --nv-ease-soft: cubic-bezier(.4, 0, .2, 1);

  /* front face */
  --nv-front-fg: #ffffff;
  --nv-front-fg-soft: rgba(255, 255, 255, .78);
  --nv-front-fill: rgba(255, 255, 255, .16);    /* glass buttons       */
  --nv-front-fill-hi: rgba(255, 255, 255, .30);
  --nv-front-line: rgba(255, 255, 255, .22);
  /* The halo that keeps white text readable on a pale photograph. Themes
     that put dark text on the front should invert this to a light value. */
  --nv-front-outline: rgba(0, 0, 0, .55);
  --nv-front-base: #1d2430;                     /* behind the gallery  */
  --nv-scrim-top: rgba(0, 0, 0, .42);
  --nv-scrim-mid: rgba(0, 0, 0, .10);
  --nv-scrim-bottom: rgba(0, 0, 0, .82);

  /* back face */
  --nv-back-bg: #f7f8fa;
  --nv-back-bg-2: #ffffff;                      /* header / footer     */
  --nv-back-fg: #101827;
  --nv-back-muted: #667085;
  --nv-surface: #ffffff;
  --nv-surface-hi: #f1f3f7;
  --nv-line: #e5e8ee;

  /* accents */
  --nv-accent: #2563eb;
  --nv-accent-fg: #ffffff;
  --nv-accent-soft: rgba(37, 99, 235, .10);
  --nv-gold: #d97706;
  --nv-gold-soft: rgba(217, 119, 6, .12);
  --nv-open: #16a34a;
  --nv-closed: #dc2626;

  /* depth */
  --nv-shadow: 0 18px 50px -18px rgba(12, 18, 33, .45);
  --nv-shadow-lift: 0 40px 90px -28px rgba(12, 18, 33, .62);

  /* geometry */
  --nv-ratio: 5 / 8;              /* desktop card proportions          */
  --nv-max-w: 26rem;              /* 416px                             */
  --nv-max-h: 46rem;
  --nv-radius: 26px;
  --nv-pad: 1.25rem;

  /* page behind the card */
  --nv-stage-bg: #eef1f6;
  --nv-stage-glow: rgba(37, 99, 235, .16);
}

html[data-theme="dark"],
html.dark {
  --nv-back-bg: #0e1218;
  --nv-back-bg-2: #141a22;
  --nv-back-fg: #eef2f8;
  --nv-back-muted: #93a1b5;
  --nv-surface: #171e27;
  --nv-surface-hi: #1e2733;
  --nv-line: #263041;

  --nv-accent: #60a5fa;
  --nv-accent-fg: #05101f;
  --nv-accent-soft: rgba(96, 165, 250, .14);
  --nv-gold: #fbbf24;
  --nv-gold-soft: rgba(251, 191, 36, .14);
  --nv-open: #34d399;
  --nv-closed: #f87171;

  --nv-front-base: #0a0e14;
  --nv-scrim-bottom: rgba(0, 0, 0, .88);

  --nv-shadow: 0 18px 50px -18px rgba(0, 0, 0, .8);
  --nv-shadow-lift: 0 40px 90px -28px rgba(0, 0, 0, .92);

  --nv-stage-bg: #070a0f;
  --nv-stage-glow: rgba(96, 165, 250, .12);
}

@media (prefers-color-scheme: dark) {
  html:not([data-theme="light"]):not(.light) {
    --nv-back-bg: #0e1218;
    --nv-back-bg-2: #141a22;
    --nv-back-fg: #eef2f8;
    --nv-back-muted: #93a1b5;
    --nv-surface: #171e27;
    --nv-surface-hi: #1e2733;
    --nv-line: #263041;

    --nv-accent: #60a5fa;
    --nv-accent-fg: #05101f;
    --nv-accent-soft: rgba(96, 165, 250, .14);
    --nv-gold: #fbbf24;
    --nv-gold-soft: rgba(251, 191, 36, .14);
    --nv-open: #34d399;
    --nv-closed: #f87171;

    --nv-front-base: #0a0e14;
    --nv-scrim-bottom: rgba(0, 0, 0, .88);

    --nv-shadow: 0 18px 50px -18px rgba(0, 0, 0, .8);
    --nv-shadow-lift: 0 40px 90px -28px rgba(0, 0, 0, .92);

    --nv-stage-bg: #070a0f;
    --nv-stage-glow: rgba(96, 165, 250, .12);
  }
}

/* ── page ───────────────────────────────────────────────────────────── */

.nv-body {
  margin: 0;
  min-height: 100dvh;
  background: var(--nv-stage-bg, #eef1f6);
  color-scheme: light dark;
  /* The card is the whole viewport; the page itself never scrolls. The
     remaining modals are position:fixed with their own scroll containers, so
     this does not trap them. */
  overflow: hidden;
  overscroll-behavior: none;
  -webkit-tap-highlight-color: transparent;
}


/* =====================================================================
   nv-sheet — a surface that opens ON the card's own footprint
   =====================================================================
   Used by the memory wall. Same width, same height, same radius and the
   same stage padding as the card, so it reads as the card opening rather
   than as an unrelated overlay dropped over the page. On desktop it holds
   the card's proportions instead of stretching across the window.
   ===================================================================== */

.nv-sheet {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: max(env(safe-area-inset-top), 10px) 10px max(env(safe-area-inset-bottom), 10px);
  box-sizing: border-box;
}
/* Its own hide rule, so opening and closing never depends on Tailwind's
   `hidden` utility surviving a rebuild. */
.nv-sheet.hidden, .nv-sheet[hidden] { display: none; }

.nv-sheet__scrim {
  position: absolute;
  inset: 0;
  background: rgba(2, 6, 16, .62);
  backdrop-filter: blur(5px);
  -webkit-backdrop-filter: blur(5px);
}

.nv-sheet__panel {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: var(--nv-max-w);
  height: 100%;
  max-height: var(--nv-max-h);
  min-height: 0;
  box-sizing: border-box;
  border-radius: var(--nv-radius);
  overflow: hidden;
  background: var(--nv-back-bg, #fff);
  color: var(--nv-back-fg, #101827);
  box-shadow: var(--nv-shadow-lift, 0 40px 90px -28px rgba(0, 0, 0, .6));
  animation: nv-sheet-in .32s var(--nv-ease, cubic-bezier(.22, 1, .36, 1));
}

@media (min-width: 480px) and (min-height: 620px) {
  .nv-sheet__panel { height: auto; aspect-ratio: var(--nv-ratio); }
}

@keyframes nv-sheet-in {
  from { opacity: 0; transform: translateY(14px) scale(.97); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .nv-sheet__panel { animation: none; }
}

.nv-sheet__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .7rem;
  flex: none;
  padding: .85rem var(--nv-pad);
  background: var(--nv-back-bg-2, #fff);
  border-bottom: 1px solid var(--nv-line, #e5e8ee);
}
.nv-sheet__title { margin: 0; font-size: 1rem; font-weight: 800; }

.nv-sheet__body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
  scrollbar-color: var(--nv-line, #e5e8ee) transparent;
}
.nv-sheet__body::-webkit-scrollbar { width: 6px; }
.nv-sheet__body::-webkit-scrollbar-thumb {
  background: var(--nv-line, #e5e8ee);
  border-radius: 999px;
}

.nv-sheet__foot {
  flex: none;
  padding: .75rem var(--nv-pad);
  padding-bottom: max(.75rem, env(safe-area-inset-bottom));
  background: var(--nv-back-bg-2, #fff);
  border-top: 1px solid var(--nv-line, #e5e8ee);
}

